MVPExample--Android MVP开发见解

来源:互联网 发布:js时间戳与php时间戳 编辑:程序博客网 时间:2024/06/10 15:01

MVPExample

前言

     前段时间在看有关android MVP架构方面的资料,在掘金上看到一个不错文章Android MVP 架构必要知识:第一部分
,然后就按照自己理解,写了一个例子(看起来文章很长不怎么想看,其实主要是贴的代码多了都是一个类一个类的(不贴全咯,就觉得少了点什么强迫症!!),,一部分是为了讲述demo有什么功能的展示代码看一下就行,包含了不少不言而喻的细节,真正实现的代码并不多,或者说这个demo的代码并不多,最后会奉上demo地址),各位看官要是觉得有什么不对的或者不合理的地方还请指出来(●’◡’●)。
    毕竟还是第一次写博客有点紧张和(/▽\=)啊。好了废话结束进入正题开始码字母 Come with me.

今天我要讲的内容主要以围绕下面的第二张图来说,(这里讨论mvp和mvc具体的差别和使用场景)一般我们在网上看到的有关于mvp相关的介绍,MVP 将一个应用分成了三个基础部分,通过Presenter层
控制view层与model层进行交互,这里我们引进了一个DataManager也就是Model的管理者,
presenter通过DataManager集中控制model层访问数据。例如网络访问,本地数据库访问,例如:

  1. Model:负责处理应用的数据部分。
  2. View:负责将带有数据的视图显示在屏幕上。
  3. Presenter:连接 Model 和 View 的桥梁,它也负责操控 View。
  4. 对各个不同Model层操作的集中安置和管理,让以后的维护者不必到处找某一个数据操作在什么地方

这是项目的结构图

    从上图可以看出项目结构主要分为 model层接口和实现,DataManager接口和实现,presenter和view的接口集合(GithubContract),和presenter层实现,以及view层activity。图二中虚线所表示的指接口,所以虚线相对应的实线部分就是实现类。
    Demo的主要功能是从github上获取项目信息并显示


定义Model,View,Presenter 接口 以及 众多Model数据操作管理者DataManager接口

GithubContract.java这个类定义了presenter层和view层的功能接口。

Presenter 接口作为连接Model和View的中间桥梁,需要将二者连接起来,因此他需要完成以下工作:

  • 开始获取数据
  • 获取数据之后的成功或者失败的处理

View 接口定义所有需要实现的视图逻辑,在我们的下载任务中,视图逻辑包括

  • 显示加载
  • 数据获取成功或者失败的回调,展示相应的ui
public interface GithubContract {/** * Description:MVP模式的view层 */interface GithubView<T> {    /**     * 显示加载中     */    void showLoading();    /**     * 请求失败的操作     *     * @param tag request flag     */    void showFailHandle(String tag, String flag);    /**     * 请求成功的操作     *     * @param tag request flag     */    void showSuccessHandle(T tag, String flag);}/** * Description:MVP模式的Presenter层 */interface GithubPresenter {    /**     * 开始请求     */    <T> void onRequest(String url, Map param, Class<T> tClass, String flag);    /**     * 开始请求     */    <T> void onRequest(String url, Map param, TypeToken<T> tTypeToken, String flag);    /**     * 请求成功的回调     *     * @param data 数据     */    <T> void onRequestSuccess(T data, String flag);    /**     * 请求失败的回调     *     * @param msg 信息     */    void onRequestFail(String msg, String flag);}}

GithubModel.java这是model数据层的定义
Model 接口定义所有需要实现的业务逻辑,在我们的demo,业务逻辑只有实现了一个,就是下从github上获取项目信息

public interface GithubModel<T> {/** * 回调 */interface GithubMCallback<T> {    void callbackSuceed(T t);    void callbackFail(String mag);}/** * 获取数据 * * @param url * @param param * @param tGithubMCallback */void getGithubData(String url, Map param, GithubMCallback<T> tGithubMCallback);}  

DataManager.java这是model层数据集合操作的定义,这里可以定义各种对数据的操作进行集中管理例如网络请求,访问本地数据库等
在这里其实Presenter不直接控制Model层数据操作,而是Presenter通过DataManager间接操作model数据层,只要目的是集中管理Model数据操作,
在DataManager里面定义了从github上获取数据的操作(本demo中实现的功能)以及访问数据库(没有实现).

public interface DataManager {/** * 从github上获取数据 * * @param url * @param parem * @param flag * @param tClass * @param tGithubPresenter */<T> void getGithubData(String url, Map parem, String flag, Class<T> tClass, GithubPresenterImpl tGithubPresenter);/** * 从github上获取数据 * * @param url * @param parem * @param flag * @param tTypeToken * @param tGithubPresenter * @param <T> */<T> void getGithubData(String url, Map parem, String flag, TypeToken<T> tTypeToken, GithubPresenterImpl tGithubPresenter);/** * 获取本地数据库中的数据的model * * @param <T> */<T> void getDataFromDB(Class<T> tClass);}  

使用过程 接口Model,View,Presenter,DataManager具体实现

Model 具体实现

public class GithubModelImpl<T> implements GithubModel<T> {//    private GithubContract.GithubPresenter mGithubPresenter;//提供者 mvp模式的presenterprivate GithubMCallback<T> mGithubCallback;private URL mURL;private Class<T> mTClass;private TypeToken<T> mTypeToken;public GithubModelImpl(Class<T> pClass) {    this.mTClass = pClass;}public GithubModelImpl(TypeToken<T> tTypeToken) {    this.mTypeToken = tTypeToken;}@Overridepublic void getGithubData(String url, Map param, GithubMCallback<T> tGithubMCallback) {    try {        this.mGithubCallback = tGithubMCallback;        mURL = new URL(url);        new GithubTask().execute(mURL);    } catch (MalformedURLException e) {        e.printStackTrace();    }}private class GithubTask extends AsyncTask<URL, Void, T> {    @Override    protected T doInBackground(URL... params) {        try {            URL url = params[0];            //打开链接            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();            //设置请求方式 get post            urlConnection.setRequestMethod("GET");            //设置请求超时            urlConnection.setConnectTimeout(5000);            //设置读数据超时            urlConnection.setReadTimeout(5000);            //获取响应码            int code = urlConnection.getResponseCode();            if (code == 200) {//请求成功                //提取 并 解析数据                //1、提取数据                BufferedReader reader = new BufferedReader(                        new InputStreamReader(urlConnection.getInputStream()));                char[] buf = new char[2048];                StringBuilder builder = new StringBuilder();                int size = 0;                while (-1 != (size = reader.read(buf))) {                    builder.append(buf, 0, size);                }                reader.close();//关闭流                //2、解析数据                T parsedGSON = null;                if (null != mTClass)                    parsedGSON = (T) new Gson().fromJson(builder.toString(), mTClass);                else if (null != mTypeToken)                    parsedGSON = (T) new Gson().fromJson(builder.toString(), mTypeToken.getType());                return parsedGSON;            } else {                Log.d("GithubModelImpl", "code:" + code + "==>请求失败信息:" + urlConnection.getResponseMessage());                return null;            }        } catch (IOException e) {            e.printStackTrace();            return null;        }    }    @Override    protected void onPostExecute(T t) {        if (t == null) {            mGithubCallback.callbackFail("Fail");//                mGithubPresenter.onRequestFail("Fail", mRequestFlag);        } else {            mGithubCallback.callbackSuceed(t);//                mGithubPresenter.onRequestSuccess(t, mRequestFlag);        }    }}}

在MVP模式中,Model的工作就是完成具体的业务操作,网络请求,持久化数据增删改查等任务。同时Model中又不会包含任何View。
这里Model的具体实现很简单,利用异步任务和HttpURLConnection从github上获取开源项目的信息,在onPostExecute方法返回结果,并由model接口中定义的回调接口GithubMCallback回调处理给Presenter使用。
那么Presenter接口又是怎样实现的呢?赶紧来看看

Presenter的实现

public class GithubPresenterImpl implements GithubContract.GithubPresenter {private GithubContract.GithubView mGithubView;//mvp模式的视图控制public GithubPresenterImpl(GithubContract.GithubView githubView) {    this.mGithubView = githubView;}@Overridepublic <T> void onRequest(String url, Map param, Class<T> tClass,String flag) {    mGithubView.showLoading();    GithubDataManager.getInstance().getGithubData(url, param, flag, tClass, this);//        this.mGithubModel.getGithubData(url, param, flag);//之前的另一种方法 在presenter层直接去控制model}@Overridepublic <T> void onRequest(String url, Map param, TypeToken<T> tTypeToken, String flag) {    mGithubView.showLoading();    GithubDataManager.getInstance().getGithubData(url, param, flag, tTypeToken, this);}@Overridepublic <T> void onRequestSuccess(T data, String flag) {    mGithubView.showSuccessHandle(data, flag);}@Overridepublic void onRequestFail(String msg, String flag) {    mGithubView.showFailHandle(msg, flag);}}

可以看到,我们在GithubPresenterImpl的构造方法中,接收了传入了view,这样Presenter中就可以通过view的回调去通知activity更新UI了;
而在onRequest(…)方法中可以回调显示请求加载框以及开始请求数据,请求数据通过GithubDataManager(单例)去选择操作Model层的某一块功能并把presenter传过去。
这样;在Presenter具体实现中,业务相关的操作由Model去完成(例如download),视图相关的操作由View去完成
(如setView等)。Presenter 作为桥梁的作用就这样体现出来了(其中model层有DataManager集中管理),巧妙的将View和Model的具体实现连接了起来。

DataManager具体实现

public class GithubDataManager implements DataManager {private static volatile GithubDataManager mInstance;/** * 安全的单例模式 * * @return */public static GithubDataManager getInstance() {    GithubDataManager instance = mInstance;    if (instance == null) {        synchronized (GithubDataManager.class) {            instance = mInstance;            if (null == instance) {                instance = new GithubDataManager();                mInstance = instance;            }        }    }    return instance;}/** * 通过网络 从github上获取数据 的model * * @param url * @param parem * @param flag * @param tClass * @param tGithubPresenter * @param <T> * @return */@Overridepublic <T> void getGithubData(String url, Map parem, final String flag, Class<T> tClass, final GithubPresenterImpl tGithubPresenter) {    new GithubModelImpl<T>(tClass).getGithubData(url, parem, new GithubModel.GithubMCallback<T>() {        @Override        public void callbackSuceed(T t) {            tGithubPresenter.onRequestSuccess(t, flag);        }        @Override        public void callbackFail(String mag) {            tGithubPresenter.onRequestFail(mag, flag);        }    });}@Overridepublic <T> void getGithubData(String url, Map parem, final String flag, TypeToken<T> tTypeToken, final GithubPresenterImpl tGithubPresenter) {    new GithubModelImpl<T>(tTypeToken).getGithubData(url, parem, new GithubModel.GithubMCallback<T>() {        @Override        public void callbackSuceed(T t) {            tGithubPresenter.onRequestSuccess(t, flag);        }        @Override        public void callbackFail(String mag) {            tGithubPresenter.onRequestFail(mag, flag);        }    });}/** * 获取本地数据库中的数据的model * * @param tClass */@Overridepublic <T> void getDataFromDB(Class<T> tClass) {}}

GithubDataManager单例实现,因为他只是起到了中间调用者的工作本身没有数据的变化,不需要多实例。
在GithubDataManager中实现了DataManager中的getGithubData(…)和getDataFromDB(…)两个方法分别是访问网络和访问本地数据库(这里只实现一个功能),起到的作用就是对Model层操作的集中安置和管理,让以后的维护者不必到处找某一个数据操作在什么地方。
在getGithubData(。。)方法中实例化GithubModelImpl并传入相应的参数,通过实例去调用这个model操作获取网络数据,再返回结果是通过传入的Presenter对象,将处理结果回调到GithubPresenterImpl,最后在上面GithubPresenterImpl实现中再通过view回调到Activity里面操作UI,最后就是View的实现。

View的实现

public class ModeActivity extends AppCompatActivity implements View.OnClickListener, GithubContract.GithubView {private static final String REQUEST_TAG_GITHUB = "github";private static final String REQUEST_TAG_GITHUB_2 = "github_2";private Button mButMvpGet;private ProgressBar mLoadingMvp;private TextView mTextMvpShow;private Button mButMvpGet2;private Toolbar mToolbar;private GithubContract.GithubPresenter mGithubPresenter;@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_mvp);    initView();    mGithubPresenter = new GithubPresenterImpl(this);}private void initView() {    mToolbar = (Toolbar) findViewById(R.id.toolbar);    mToolbar.setTitle(getResources().getString(R.string.app_name));    setSupportActionBar(mToolbar);    mButMvpGet = (Button) findViewById(R.id.but_mvp_get);    mButMvpGet.setOnClickListener(this);    mLoadingMvp = (ProgressBar) findViewById(R.id.loading_mvp);    mLoadingMvp.setOnClickListener(this);    mTextMvpShow = (TextView) findViewById(R.id.text_mvp_show);    mTextMvpShow.setOnClickListener(this);    mButMvpGet2 = (Button) findViewById(R.id.but_mvp_get_2);    mButMvpGet2.setOnClickListener(this);}@Overridepublic void onClick(View v) {    switch (v.getId()) {        case R.id.but_mvp_get:            mGithubPresenter                    .onRequest("https://api.github.com/repos/CymChad/BaseRecyclerViewAdapterHelper", null, GithubBean.class, REQUEST_TAG_GITHUB);//                mGithubPresenter//                        .onRequest("https://api.github.com/repos/CymChad/BaseRecyclerViewAdapterHelper", null, new TypeToken<GithubBean>(){},REQUEST_TAG_GITHUB);            break;        case R.id.but_mvp_get_2:            mGithubPresenter                    .onRequest("https://api.github.com/repos/google/guava", null, new TypeToken<GithubBean>() {                    }, REQUEST_TAG_GITHUB_2);            break;    }}/** * 请求显示加载中 */@Overridepublic void showLoading() {    mLoadingMvp.setVisibility(0);}/** * 请求失败的操作 * * @param tag request flag */@Overridepublic void showFailHandle(String msg, String flag) {    if (REQUEST_TAG_GITHUB.equals(flag)) {        mLoadingMvp.setVisibility(View.GONE);        mTextMvpShow.setText(msg);    } else if (REQUEST_TAG_GITHUB_2.equals(flag)) {        mLoadingMvp.setVisibility(View.GONE);        mTextMvpShow.setText(msg);    }}/** * 请求成功的操作 * * @param tag request flag */@Overridepublic void showSuccessHandle(Object data, String flag) {    if (REQUEST_TAG_GITHUB.equals(flag)) {        mLoadingMvp.setVisibility(View.GONE);        mTextMvpShow.setText("name:" + ((GithubBean) data).getName());    } else if (REQUEST_TAG_GITHUB_2.equals(flag)) {        mLoadingMvp.setVisibility(View.GONE);        mTextMvpShow.setText("full_name:" + ((GithubBean) data).getFull_name());    }}}

提供了两个按钮,分别获取不同开源项目的信息,异步进行。
在点下按钮执行开始下载任务的时候,View(Activity)中没有具体的实现,只是调用了Presenter中的onRequest方法,而Presenter中的onRequest又会去通过DataManager调用Model的getGithubDatad方法,Model又会在根据具体逻辑(在这里就是Http请求)的状态去调用Presenter中的方法,例如我们在AsyncTask的结果回调方法中,调用mGithubCallback.callbackSuceed(t);时,就会去调用Presenter的具体实现。

/** * 请求失败的操作 * * @param tag request flag */@Overridepublic void showFailHandle(String msg, String flag) {    。。。。。。}/** * 请求成功的操作 * * @param tag request flag */@Overridepublic void showSuccessHandle(Object data, String flag) {    。。。。。。}

而他的内部实现又是操作具体的View,也就是我们在Activity中初始化Presenter中传递的this,也就是当前Activity(View),这样最终回到了Activity中的.

Demo地址:点我、点我、点我


2 0
原创粉丝点击