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层访问数据。例如网络访问,本地数据库访问,例如:
- Model:负责处理应用的数据部分。
- View:负责将带有数据的视图显示在屏幕上。
- Presenter:连接 Model 和 View 的桥梁,它也负责操控 View。
- 对各个不同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地址:点我、点我、点我
- MVPExample--Android MVP开发见解
- Android开发MVP模式个人见解
- Android MVP开发模式
- Android MVP开发。
- android MVP 开发模式
- Android mvp开发模式
- Android 开发MVP模式
- Android mvp开发模式
- android mvp开发模式
- 谈谈mvp的实战见解
- Android开发MVP模式解析
- Android开发MVP模式实践
- android开发模式之MVP
- Android开发MVP模式解析
- Android开发MVP模式实践
- Android开发中的MVP架构
- Android中的 mvp 开发模式
- Android MVP 开发模式优缺点
- gradle编译启动项目时报错Could not find tools.jar
- iOS本地化学习小结
- 向Retrofit打响第一炮
- 《ACM程序设计》书中题目U(美丽数字)
- 二叉树的遍历算法实现、以及所有简单操作
- MVPExample--Android MVP开发见解
- 安装和使用Karma-Jasmine进行自动化测试
- 海航持续并购正向发展,集团破产消息是假的
- Spark RDD持久化策略
- java 学习总结
- Fundebug上线Node.js错误监控啦
- 初探匿名内部类
- HashMap实现原理分析
- 我理解的原型