# 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的适配器里也有观察者模式的踪影哦）！

让我们来看一下LookLook： ![^\_^](https://github.com/yangsx95/notes/blob/master/front-end/android/LookLook剖析,架构概述——MVP、Retrofit+RxJava.assets/20161031203331645.png) ps:初学UML，图画的不标准，还请见谅！！！

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

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

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

```java
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:这里我只贴部分代码

```java
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中向这个被观察者中添加几个随从（观察着），就可以随时获悉数据的变化情况

```java
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也基本就是这个样子，很有利于后期的维护和代码的修改，至少思路还是很清晰的！！


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://yangsx95.gitbook.io/notes/front-end/android/looklook-pou-xi-jia-gou-gai-shu-mvpretrofit+rxjava.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
