MVPExample--Android MVP开发见解

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模式的presenter
private 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;
}

@Override
public 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;
}


@Override
public <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
}

@Override
public <T> void onRequest(String url, Map param, TypeToken<T> tTypeToken, String flag) {
    mGithubView.showLoading();
    GithubDataManager.getInstance().getGithubData(url, param, flag, tTypeToken, this);
}

@Override
public <T> void onRequestSuccess(T data, String flag) {
    mGithubView.showSuccessHandle(data, flag);
}

@Override
public 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
 */
@Override
public <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);
        }
    });
}

@Override
public <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
 */
@Override
public <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;

@Override
protected 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);
}

@Override
public 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;
    }
}

/**
 * 请求显示加载中
 */
@Override
public void showLoading() {
    mLoadingMvp.setVisibility(0);
}

/**
 * 请求失败的操作
 *
 * @param tag request flag
 */
@Override
public 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
 */
@Override
public 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
 */
@Override
public void showFailHandle(String msg, String flag) {
    。。。。。。
}

/**
 * 请求成功的操作
 *
 * @param tag request flag
 */
@Override
public void showSuccessHandle(Object data, String flag) {
    。。。。。。
}

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

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


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值