缓存网络数据--Rx和数据库

 2023-09-05 阅读 54 评论 0

摘要:欢迎Follow我的GitHub, 关注我的CSDN. 本文的合集已经编著成书,高级Android开发强化实战,欢迎各位读友的建议和指导。在京东即可购买:https://item.jd.com/12385680.html RxJava是响应式编程, 在异步处理网络数据时, 使用广泛. 我们也可以使用一些Rx的特

欢迎Follow我的GitHub, 关注我的CSDN.

缓存模式

本文的合集已经编著成书,高级Android开发强化实战,欢迎各位读友的建议和指导。在京东即可购买:https://item.jd.com/12385680.html

Book

RxJava是响应式编程, 在异步处理网络数据时, 使用广泛.
我们也可以使用一些Rx的特性, 优雅地缓存网络数据.

缓存模式: 读取数据库, 显示, 请求数据, 存储到数据库, 再更新页面.

使用Dagger2+Retrofit+Rx的标准组合, 我来讲解一下如何使用.

GitHub下载地址

动画


1. 框架

常规项目, 包含跳转缓存和非缓存页面, 为了模拟慢速环境, 延迟3秒加载数据.

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}// 跳转无缓存public void gotoNoCache(View view) {startActivity(new Intent(this, NocacheActivity.class));}// 跳转有缓存public void gotoCache(View view) {startActivity(new Intent(this, CacheActivity.class));}
}

2. 无缓存

依赖注入三个关键部分, Application/Component/Module.

public class RcApplication extends Application {private ApiComponent mApiComponent;@Override public void onCreate() {super.onCreate();mApiComponent = DaggerApiComponent.builder().apiModule(new ApiModule(this)).build();}public ApiComponent getApiComponent() {return mApiComponent;}
}
@Singleton
@Component(modules = ApiModule.class)
public interface ApiComponent {void inject(NocacheActivity activity);void inject(CacheActivity activity);
}
@Module
public class ApiModule {private Application mApplication;public ApiModule(Application application) {mApplication = application;}@Provides@Singletonpublic Application provideApplication() {return mApplication;}@Provides@Singleton GitHubClient provideGitHubClient() {return new GitHubClient();}@Provides ObservableRepoDb provideObservableRepoDb() {return new ObservableRepoDb(mApplication);}
}

模块提供应用信息, GitHub的网络请求, 数据库.
@Singleton表示单例模式, 全部注入拥有一个实例.

页面, 使用RecyclerView显示列表信息, 在加载时显示ProgressBar.

/*** 无缓存Activity* <p>* Created by wangchenlong on 16/1/18.*/
public class NocacheActivity extends Activity {@Bind(R.id.nocache_rv_list) RecyclerView mRvList;@Bind(R.id.nocache_pb_progress) ProgressBar mPbProgress;@Inject Application mApplication;@Inject GitHubClient mGitHubClient;private ListAdapter mListAdapter;@Override protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_nocache);ButterKnife.bind(this);((RcApplication) getApplication()).getApiComponent().inject(this);LinearLayoutManager layoutManager = new LinearLayoutManager(mApplication);mRvList.setLayoutManager(layoutManager);mListAdapter = new ListAdapter();mRvList.setAdapter(mListAdapter);}@Override protected void onResume() {super.onResume();// 延迟3秒, 模拟效果mGitHubClient.getRepos("SpikeKing").delay(3, TimeUnit.SECONDS).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(this::onSuccess, this::onError);mPbProgress.setVisibility(View.VISIBLE);}private void onSuccess(ArrayList<Repo> repos) {mListAdapter.setRepos(repos);mPbProgress.setVisibility(View.INVISIBLE);}private void onError(Throwable throwable) {mPbProgress.setVisibility(View.INVISIBLE);}
}

通过观察可以发现, 长时间显示白屏会降低用户体验. 我来看看缓存模式.


3. 缓存

缓存模式: 读取数据库, 显示, 请求数据, 存储到数据库, 再更新页面.
推荐使用脚本生成数据库处理类, 使用方式参考, 自动生成DbHelper的脚本.

主页逻辑.

public class CacheActivity extends Activity {@Bind(R.id.cache_rv_list) RecyclerView mRvList; // 列表@Bind(R.id.cache_srl_swipe) SwipeRefreshLayout mSrlSwipe; // 刷新@Inject Application mApplication;@Inject ObservableRepoDb mRepoDb;@Inject GitHubClient mGitHubClient;private ListAdapter mListAdapter; // RecyclerView适配器@Override protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_cache);ButterKnife.bind(this);// 注入类((RcApplication) getApplication()).getApiComponent().inject(this);LinearLayoutManager layoutManager = new LinearLayoutManager(mApplication);mRvList.setLayoutManager(layoutManager);mListAdapter = new ListAdapter();mRvList.setAdapter(mListAdapter);mSrlSwipe.setOnRefreshListener(this::fetchUpdates);}@Override protected void onResume() {super.onResume();mRepoDb.getObservable().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(this::setData);fetchUpdates();Toast.makeText(mApplication, "正在更新", Toast.LENGTH_SHORT).show();}// 设置数据, 更新完成会调用private void setData(ArrayList<Repo> repos) {mListAdapter.setRepos(repos);Toast.makeText(mApplication, "更新完成", Toast.LENGTH_SHORT).show();}private void fetchUpdates() {// 延迟3秒, 模拟效果mGitHubClient.getRepos("SpikeKing").delay(3, TimeUnit.SECONDS).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(mRepoDb::insertRepoList, this::fetchError, this::fetchComplete);}private void fetchError(Throwable throwable) {mSrlSwipe.setRefreshing(false);}private void fetchComplete() {mSrlSwipe.setRefreshing(false);}
}

数据库的观察者

/*** Redo的观察者* <p>* Created by wangchenlong on 16/1/18.*/
public class ObservableRepoDb {private PublishSubject<ArrayList<Repo>> mPublishSubject; // 发表主题private RepoDbHelper mDbHelper; // 数据库public ObservableRepoDb(Context context) {mDbHelper = new RepoDbHelper(context);mPublishSubject = PublishSubject.create();}// 返回观察者public Observable<ArrayList<Repo>> getObservable() {Observable<ArrayList<Repo>> firstObservable = Observable.fromCallable(this::getRepoList);return firstObservable.concatWith(mPublishSubject); // 连接发表主题}// 从数据库获得数据private ArrayList<Repo> getRepoList() {mDbHelper.openForRead();ArrayList<Repo> repos = new ArrayList<>();Cursor c = mDbHelper.getAllRepo();if (!c.moveToFirst()) {return repos; // 返回空}do {// 添加数据repos.add(new Repo(c.getString(RepoDbHelper.REPO_ID_COLUMN_POSITION),c.getString(RepoDbHelper.REPO_NAME_COLUMN_POSITION),c.getString(RepoDbHelper.REPO_DESCRIPTION_COLUMN_POSITION),new Repo.Owner(c.getString(RepoDbHelper.REPO_OWNER_COLUMN_POSITION), "", "", "")));} while (c.moveToNext());c.close();mDbHelper.close();return repos;}// 插入Repo列表public void insertRepoList(ArrayList<Repo> repos) {mDbHelper.open();mDbHelper.removeAllRepo();for (Repo repo : repos) {mDbHelper.addRepo(repo.getId(),repo.getName(),repo.getDescription(),repo.getOwner().getLogin());}mDbHelper.close();mPublishSubject.onNext(repos); // 会调用更新数据}
}

这一部分是关键, 实现网络请求同步插入数据库和更新页面.
关联PublishSubject, 在插入数据完成后, 调用绑定观察者, 更新页面.
.concatWith(mPublishSubject)mPublishSubject.onNext(repos).


Rx在处理网络请求方面, 确实非常优雅, 值得喜欢完美的人使用.

OK, that’s all! Enjoy it.

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://808629.com/125.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 86后生记录生活 Inc. 保留所有权利。

底部版权信息