Retrofit缓存网络数据RxCache--RxJava和数据库

标签: 缓存数据库
7535人阅读 评论(1) 收藏 举报

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

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

SpikeKing 大神github地址:https://github.com/SpikeKing
代码:https://github.com/SpikeKing/wcl-rx-cache-demo

这里写图片描述

使用Dagger2+Retrofit+Rx的标准组合, 我来讲解一下如何使用.
这里写图片描述

  1. 框架

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

public class MainActivity extends AppCompatActivity {

    @Override
    protected 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));
    }
}
  1. 无缓存

依赖注入三个关键部分, 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
    @Singleton
    public 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);
    }
}

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

缓存

缓存模式: 读取数据库, 显示, 请求数据, 存储到数据库, 再更新页面.
推荐使用脚本生成数据库处理类, 使用方式参考, 自动生成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在处理网络请求方面, 确实非常优雅, 值得喜欢完美的人使用.

最后感谢作者分享
原文链接:http://blog.csdn.net/caroline_wendy/article/details/50540272

代码:https://github.com/SpikeKing/wcl-rx-cache-demo


关于缓存有一个rxcache也可以试试。

RxCache - Android和Java的Reactive缓存库

RxCache项目地址:https://github.com/VictorAlbertos/RxCache

0
1

猜你在找
【直播】机器学习&数据挖掘7周实训--韦玮
【套餐】系统集成项目管理工程师顺利通关--徐朋
【直播】3小时掌握Docker最佳实战-徐西宁
【套餐】机器学习系列套餐(算法+实战)--唐宇迪
【直播】计算机视觉原理及实战--屈教授
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之矩阵--黄博士
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之凸优化--马博士
【套餐】Javascript 设计模式实战--曾亮
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:9547289次
    • 积分:70720
    • 等级:
    • 排名:第23名
    • 原创:505篇
    • 转载:916篇
    • 译文:4篇
    • 评论:2681条
    打赏
    如果您认为本博客不错,读后觉得有收获,不妨打赏赞助我一下,让我有动力继续写出高质量的博客。



    赠人玫瑰,手有余香。分享技术,传递快乐。

    有心课堂,传递的不仅仅是技术!

    QQ交流群:183899857

    有心课堂会员,请加入VIP QQ交流群:213725333

    github
    我的视频
    博客专栏
    最新评论