LookLook剖析,架构概述——MVP、Retrofit+RxJava

前言: 学习LookLook这个开源项目的初衷是学习MVP架构,因为自己已经块学了一年的Android,可是对架构一直没有什么概念,而且平时自己编项目时总是没有框架。写到哪里,就封装到哪里,照着一些接口自己总是瞎写写,收获甚微,代码乱,所以出现最多的情况就是写不下去了,代码不仅没法扩展,也没法修改。

项目地址:https://github.com/xinghongfei/LookLook

LookLook的最大特点就是他的MVP架构,所以让我们先从MVP架构看起: MVP:Model、View、Presenter 简单来说就是将应用分为三层,降低耦合性:数据(Bean)、视图(Activity、Fragment)、适配器,并且View和Model分别与Presenter交互,View和Model不交互 哈哈,怎么听着这么像AdapterView呢(悄悄告诉你,RecyclerView的适配器里也有观察者模式的踪影哦)!

我们可以先构想一下数据刷新的整个过程: 用户触发加载刷新等操作 --> View通知Presenter更新数据 --> Presenter通知Model获取数据 --> 加载完毕 --> Model 通知Presenter数据发生改变 --> Presenter通知View更新界面

View和Presenter的交互: View持有Presenter的引用,当用户触发加载操作的时候,调用Presenter的getData()方法通知数据更新。 当数据更新完成后,presenter会在内部拿着View的引用来进行UI操作(updateMeiziData()...)。

Model和Presenter的交互方式很特殊,采用了RxJava+Retrofit的方式: 上代码:

public interface ZhihuApi {

    @GET("/api/4/news/latest")
    Observable<ZhihuDaily> getLastDaily();

    @GET("/api/4/news/before/{date}")
    Observable<ZhihuDaily> getTheDaily(@Path("date") String date);

    @GET("/api/4/news/{id}")
    Observable<ZhihuStory> getZhihuStory(@Path("id") String id);
}

ApiManager:这里我只贴部分代码

public class ApiManage {
	public ZhihuApi getZhihuApiService() {
        if (zhihuApi == null) {
            synchronized (zhihuMonitor) {
                if (zhihuApi == null) {
                    zhihuApi = new Retrofit.Builder()
                            .baseUrl("http://news-at.zhihu.com")
                            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                            // 注意这里添加RxJavaCallAdapterFactory
                            .client(client)
                            .addConverterFactory(GsonConverterFactory.create())
                            .build().create(ZhihuApi.class);
                }
            }
        }
        return zhihuApi;
    }
}

这样通过这个方法就可以获得RxJava的被观察者了,然后只要在Presenter中向这个被观察者中添加几个随从(观察着),就可以随时获悉数据的变化情况

public class ZhihuPresenterImpl extends BasePresenterImpl implements IZhihuPresenter {

	// presenter持有view的引用
    private IZhihuFragment mZhihuFragment;
    private CacheUtil mCacheUtil;
    private Gson gson = new Gson();

    public ZhihuPresenterImpl(Context context,IZhihuFragment zhihuFragment) {

        mZhihuFragment = zhihuFragment;
        mCacheUtil = CacheUtil.get(context);
    }

    @Override
    public void getLastZhihuNews() {
        mZhihuFragment.showProgressDialog();
        Subscription subscription = ApiManage.getInstance().getZhihuApiService().getLastDaily()
                .map(new Func1<ZhihuDaily, ZhihuDaily>() { //添加了观察者,当这些观察者发现数据状态有变时,就会使用View的接口来更新UI
                    @Override
                    public ZhihuDaily call(ZhihuDaily zhihuDaily) {
                        String date = zhihuDaily.getDate();
                        for (ZhihuDailyItem zhihuDailyItem : zhihuDaily.getStories()) {
                            zhihuDailyItem.setDate(date);
                        }
                        return zhihuDaily;
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<ZhihuDaily>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {
                        mZhihuFragment.hidProgressDialog();
                        mZhihuFragment.showError(e.getMessage());
                    }

                    @Override
                    public void onNext(ZhihuDaily zhihuDaily) {
                        mZhihuFragment.hidProgressDialog();
                        mCacheUtil.put(Config.ZHIHU, gson.toJson(zhihuDaily));
                        mZhihuFragment.updateList(zhihuDaily);
                    }
                });
        addSubscription(subscription);
    }
    
    @Override
    public void getTheDaily(String date) {
        Subscription subscription = ApiManage.getInstance().getZhihuApiService().getTheDaily(date)
                .map(new Func1<ZhihuDaily, ZhihuDaily>() {
                    @Override
                    public ZhihuDaily call(ZhihuDaily zhihuDaily) {
                        String date = zhihuDaily.getDate();
                        for (ZhihuDailyItem zhihuDailyItem : zhihuDaily.getStories()) {
                            zhihuDailyItem.setDate(date);
                        }
                        return zhihuDaily;
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<ZhihuDaily>() {
                    @Override
                    public void onCompleted() {
                    }

                    @Override
                    public void onError(Throwable e) {
                        e.printStackTrace();
                        mZhihuFragment.hidProgressDialog();
                        mZhihuFragment.showError(e.getMessage());
                    }

                    @Override
                    public void onNext(ZhihuDaily zhihuDaily) {
                        mZhihuFragment.hidProgressDialog();
                        mZhihuFragment.updateList(zhihuDaily);
                    }
                });
        addSubscription(subscription);
    }

    @Override
    public void getLastFromCache() {
        if (mCacheUtil.getAsJSONObject(Config.ZHIHU) != null) {
            ZhihuDaily zhihuDaily = gson.fromJson(mCacheUtil.getAsJSONObject(Config.ZHIHU).toString(), ZhihuDaily.class);
            mZhihuFragment.updateList(zhihuDaily);
        }
    }
}

是不是很简单呢?MVP也基本就是这个样子,很有利于后期的维护和代码的修改,至少思路还是很清晰的!!

最后更新于