# Store
#### 项目介绍
- 项目名称:Store
- 所属系列:openharmony的第三方组件适配移植
- 功能:Store是一个Java库,用于轻松、反应式的数据加载
- 项目移植状态:主功能完成
- 调用差异:无
- 开发版本:sdk6,DevEco Studio2.2 Beta1
- 基线版本: Release 3.1.1
#### 效果演示
<img src="Images/1.gif"></img>
DEMO示例需使用代理
#### 安装教程
1.在项目根目录下的build.gradle文件中,
```
allprojects {
repositories {
maven {
url 'https://s01.oss.sonatype.org/content/repositories/releases/'
}
}
}
```
2.在entry模块的build.gradle文件中,
```
dependencies {
implementation('com.gitee.chinasoft_ohos:store:1.0.0')
//文件系统持久性库,用于从网络到文件系统的流式传输
implementation('com.gitee.chinasoft_ohos:filesystem:1.0.0')
//Gson 解析器
implementation('com.gitee.chinasoft_ohos:middleware:1.0.0')
//Jackson 解析器
implementation('com.gitee.chinasoft_ohos:middleware_jackson:1.0.0')
//Moshi 解析器
implementation('com.gitee.chinasoft_ohos:middleware_moshi:1.0.0')
......
}
```
在sdk6,DevEco Studio2.2 Beta1下项目可直接运行 如无法运行,删除项目.gradle,.idea,build,gradle,build.gradle文件, 并依据自己的版本创建新项目,将新项目的对应文件复制到根目录下
#### 使用说明
#####创建 Stores
构建StoreBuilder时有3个切入口。您使用哪一个切入口取决于您是否有自己的关键数据类型和分析器。
```
public final class StoreBuilder {
public static <Parsed> RealStoreBuilder<Parsed, Parsed, BarCode> barcode()
public static <Key, Parsed> RealStoreBuilder<Parsed, Parsed, Key> key()
public static <Key, Raw, Parsed> RealStoreBuilder<Raw, Parsed, Key> parsedWithKey()
}
```
#####缓存并得到新数据
首先调用get和concat来取得结果。然后添加distinct操作符来筛选唯一的发布。如果缓存和网络返回了同样的结果或者第一个被调用的需要通过网络来执行,那它将只会返回一个结果。
```
store.get(barCode)
.concatWith(store.fetch(barCode))
.distinct()
.subscribe()
```
注意:如果您省略了distinct()那您将得到两个值。保持订阅以获得后续发布
```
store.stream()
.subscribe()
```
注意: 任何条形码都会使得订阅流发布。您可使用过滤操作符来选取结果子集。
#####清除缓存后刷新 有时您想在当缓存清空时获取新的数据。一个常用的适用场景是您想要在用户递交不同的POST请求时从网络得到数据。公共储存方法getRefreshing(key)使得您可以在任何时候调用store.clear(key)来重新连接网络执行。举例说明:
```
allNotesStore.getRefreshing(barCode)
.subscribe(observer);
notesApi.submitNewNote(barcode);
allNotesStore.clear(barcode); //when clear is called store will hit network again
```
#####刷新过期数据
使用Persister时,当纪录过期时您可能会想回填磁盘缓存。您可以通过往您的StoreBuilder添加方法并使用RecordProvider或者使用我们内建的
```
RecordPersister store = StoreBuilder.barcode()
.fetcher(fetcher)
.persister(persister)
.refreshOnStale()
.open();
Store<ArticleAsset, Integer> store = StoreBuilder.barcode()
.fetcher(articleBarcode -> api.getAsset(articleBarcode.getKey(),articleBarcode.getType()))
.persister(new RecordPersister(FileSystemFactory.create(context.getFilesDir()),5, TimeUnit.HOURS))
.open();
```
#####过期数据联网
使用Persister时,您可能想在返回过期纪录前联网。您可以通过往您的StoreBuilder添加方法并使用RecordProvider或者使用我们内建的
```
RecordPersister store = StoreBuilder.barcode()
.fetcher(fetcher)
.persister(persister)
.networkBeforeStale()
.open();
Store<ArticleAsset, Integer> store = StoreBuilder.barcode()
.fetcher(articleBarcode -> api.getAsset(articleBarcode.getKey(),articleBarcode.getType()))
.persister(new RecordPersister(FileSystemFactory.create(context.getFilesDir()),5, TimeUnit.HOURS))
.open();
```
#####可清除的磁盘缓存
如果您希望store.clear(key)也可以清空您的磁盘缓存,请让Persister应用Clearable
#####多重解析器
您可能会想使用中间件解析器解析json至pojo,然后使用另一个解析器来打开数据。
```
Parser<BufferedSource, RedditData> sourceParser = GsonParserFactory.createSourceParser(provideGson(), RedditData.class);
Parser<RedditData, Data> envelopeParser = redditData -> redditData.data();
ParsingStoreBuilder.<BufferedSource,RedditData>builder()
.fetcher(this::fetcher)
.persister(persister)
.parser(new MultiParser<>(Arrays.asList(sourceParser,envelopeParser)))
.open();
```
#####最上层 JSON 数列 In some cases you may need to parse a top level JSONArray, in which case you can provide a TypeToken.
```
Store<List<Article>> Store = ParsingStoreBuilder.<BufferedSource, List<Article>>builder()
.nonObservableFetcher(this::getResponse)
.parser(GsonParserFactory.createSourceParser(gson, new TypeToken<List<Article>>() {}))
.open();
```
#####自定义缓存政策 通过使用expireAfterAccess 政策,stores默认会为上限100项条目缓存至多24小时。您可以使用您的自定义来覆盖改写缓存的时间和类型。下例将会展现永久缓存1项条目来保存下一层级的内存占用。
```
ParsingStoreBuilder.<BufferedSource,RedditData>builder()
.fetcher(this::fetcher)
.parser(GsonParserFactory.createSourceParser(provideGson(),RedditData.class))
.memory(CacheBuilder.newBuilder()
.maximumSize(1)
.expireAfterWrite(Long.MAX_VALUE, TimeUnit.SECONDS)
.build())
.open();
```
#####下划Stores层级 当您想要构建有其他添加功能方法的store时,下划Stores层级可能是最好的方法。store如何构建将取决于您将要添加的内容。
```
public class SampleStore extends RealStore<String, BarCode> {
@Inject
public SampleStore(Fetcher<String, BarCode> fetcher, Persister<String, BarCode> persister) {
super(fetcher, persister);
}
}
```
#####用FileSystemPersister来缓存 当您想要允许磁盘缓存时,使用Source Persister通过向您的build.gradle添加'com.nytimes.ohos:filesystem:VERSION'可能是最简单的方式。 Source Persisiter可以使得BufferedSource持续。您可以方便的从Okhttp Response 或者 Retrofit ResponseBody得到一个BufferedSource。如果您对数据抓取使用了不同的网络客户端,您可以自行创建一个BufferedSource:
```
Okio.buffer(Okio.source(new ByteArrayInputStream(data.getBytes(UTF_8))))
```
if coming from an inputStream
```
Okio.buffer(Okio.source(inputStream))
```
当您有一个可以返回BufferedSource的fetcher后,您可以将它作为一个FileSystemPersister。
```
Persister<BufferedSource, BarCode> persister = FileSystemPersister.create(fileSystem, key ->"Book"+key.getType()+key.getKey())
```
在使用FileSystemFactory时您必须提供一个PathResolver,这是为了能在多个store中共享同一个FileSystem。
```
StoreBuilder.<BufferedSource>builder()
.fetcher(this::fetcher)
.persister(persister)
.open();
```
大多数情况下您会想将数据解析至pojo而非返回BufferedSource。中间解析器将帮您实现这一目的。
```
ParsingStoreBuilder.<BufferedSource,RedditData>builder()
.fetcher(this::fetcher)
.persister(persister)
.parser(MoshiParserFactory.createSourceParser(new Moshi.Builder().build(),RedditData.class))
.open();
.parser(JacksonParserFactory.createSourceParser(new ObjectMapper(),RedditData.class))
.parser(GsonParserFactory.createSourceParser(new Gson(),RedditData.class))
```
#### 测试信息
CodeCheck代码测试无异常
CloudTest代码测试无异常
病毒安全检测通过
当前版本demo功能与原组件基本无差异
#### 版本迭代
- 1.0.0