MVP模式初探
来源:互联网 发布:淘宝助理导出数据包 编辑:程序博客网 时间:2024/06/17 00:51
之前一直听说MVP的好处多多,也看过相关资料,但是没有仔细研究过,今天看了看面试题,发现竟然让用MVP模式实现登录功能,于是抓紧研究了下。
关于MVP的介绍以及与MVC的区别网上有相当多的资料可以参考,这里推荐鸿翔大神的博客
我这里引用下MVP和MVC的区别,方便查看:
其实最明显的区别就是,MVC中是允许Model和View进行交互的,而MVP中很明显,Model与View之间的交互由Presenter完成。还有一点就是Presenter与View之间的交互是通过接口的。
光看不练假把式,理解后那就写一个demo吧。
先上效果图:
包结构如下:
说一说我的思路:
1、点击LOGIN按钮,会实现登录的功能,所以需要声明一个ILoginPresenter的接口,内置login方法,当然具体的实现需要一个LoginPresenterImpl类。
2、登录失败或成功后,需要给出提示,因此还需要定义一个ILoginView接口,内置loginFail和loginSuccess方法,而它的具体实现类便是这个Activity,同样需要一个ILoginView的具体实现类。
再说一遍整体的流程:点击login按钮,activity调用presenter实现登录功能,在presenter里执行登录逻辑,执行完毕登录逻辑后,调用presenter里的loginview(即登录activity)的相关方法,完成UI的显示。
相关代码如下,进行了简单的封装,处理了内存泄漏的问题:
public interface ILoginView {//登录view void loginSuccess(); void loginFail();}
public interface ILoginPresenter { void login(User user);}
//所有Presenter的基类,简单的封装。public class BasePresenter<T> { private static final String TAG = "BasePresenter"; private WeakReference<T> mViewHolder;//利用弱引用解决内存泄漏的问题。 public void attachView(T view) {//需要在Activity的onCreate或onResume方法里调用 mViewHolder = new WeakReference<>(view); } public T getView() {//必须attachView调用后才能调用此方法 if (mViewHolder != null) { Log.w(TAG, "maybe do not call attachView()."); return mViewHolder.get(); } return null; } public void detachView() {//需要在Activity的onDestroy或onPause调用 mViewHolder.clear(); mViewHolder = null; }}
//所有Activity都要继承此类,简单的封装了下。public abstract class BaseActivity<T, V extends BasePresenter<T>> extends AppCompatActivity { protected List<V> mPresenters = new ArrayList<>();//因为一个Activity可能会有多个Presenter,因此这使用了一个链表用来存储。 @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPresenters();//onCreate方法里添加Presenter,此方法需要在子类中实现。 if (mPresenters != null) { for (V v : mPresenters) { v.attachView((T) this); } } } @Override protected void onDestroy() {//资源清理,防止内存泄漏。 super.onDestroy(); if (mPresenters != null) { for (V v : mPresenters) { v.detachView(); } mPresenters.clear(); mPresenters = null; } } /*** * NOTE: 不要忘了在这个方法里初始化 handler 和 presenter。 * 子类中实现此方法。 */ public abstract void addPresenters();}
//登录代理的具体实现类。public class LoginPresenterImp extends BasePresenter<MainActivity> implements ILoginPresenter { private volatile int mNum = 0; private ILoginView mLoginView; private Handler mHandler; public LoginPresenterImp(Handler handler) { mHandler = handler; } @Override public void login(User user) { mLoginView = getView(); if (mLoginView != null) { new Thread(new Runnable() { @Override public void run() {//模拟子线程访问网络。 if (mNum % 2 == 0) { mHandler.post(new Runnable() {//主线程中更新UI。 @Override public void run() { mLoginView.loginSuccess(); } }); } else { mHandler.post(new Runnable() {//主线程中更新UI。 @Override public void run() { mLoginView.loginFail(); } }); } mNum++; } }).start(); } }}
//实现BaseActivity,实现ILoginView接口public class MainActivity extends BaseActivity<MainActivity, LoginPresenterImp> implements ILoginView { private EditText mEtUsername; private EditText mEtPassword; private Button mBtnLogin; private LoginPresenterImp mLoginPresenter;//presenter的引用 private MyHandler mHandler;//handler为了将UI操作切换到UI线程中来。 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } @Override public void addPresenters() {//处理presenter和handler mHandler = new MyHandler(this); mLoginPresenter = new LoginPresenterImp(mHandler); mPresenters.add(mLoginPresenter); } private void initView() { mEtUsername = (EditText) findViewById(R.id.main_et_username); mEtPassword = (EditText) findViewById(R.id.main_et_password); mBtnLogin = (Button) findViewById(R.id.main_btn_login); mBtnLogin.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String username = mEtUsername.getText().toString().trim(); String password = mEtPassword.getText().toString().trim(); if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) { Toast.makeText(MainActivity.this, "must not empty", Toast.LENGTH_SHORT).show(); return; } User user = new User(); user.setUsername(username); user.setPassword(password); mLoginPresenter.login(user);//调用presenter的login方法,将登录逻辑从activity中解耦出去。 } }); } @Override public void loginSuccess() {//登录成功后会调用 Toast.makeText(this, "login success", Toast.LENGTH_SHORT).show(); } @Override public void loginFail() {//登录失败后会调用 Toast.makeText(this, "login fail", Toast.LENGTH_SHORT).show(); } private class MyHandler extends Handler { private WeakReference<MainActivity> mReference; public MyHandler(MainActivity activity) { mReference = new WeakReference<>(activity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (mReference.get() != null) { switch (msg.what) { default: break; } } } }}
github源码
欢迎批评指正!
阅读全文
1 0
- MVP 模式初探
- mvp模式初探
- Android MVP 模式初探
- MVP模式初探
- MVP模式初探
- android中的MVP模式初探
- iOS中的MVP模式初探
- .Net平台-MVP模式初探(一)
- Android开发,MVP开发模式初探。
- android之MVP开发模式初探
- MVC、MVP、MVVM 初探(二)--- MVP模式
- mvp初探
- mvp初探
- [Android学习]Android中MVP模式初探1
- Android MVP RxJava 初探
- kotlin初探mvp架构
- MVP模式
- MVP模式
- 创建session学习-request.getSession()
- substring的参数问题
- 本次考试总结(2017.8.15上午考试)(noip2016真题)
- Java 5.0 java 包和面向对象语言的特点
- bzoj3132上帝造题的七分钟 二维树状数组
- MVP模式初探
- JAVA设计模式之抽象工厂模式
- HBase之JavaAPI
- HDUOJ 1874 畅通工程续 四种算法Dijkstra Bellman Floyd SPFA
- JDBC连接数据库步骤(以MYSQL为例)
- 中位数及带权中位数
- 我的压箱底,500G视频网盘分享
- C++ ifstream 从文件中 字符串和数字混合输入
- HTTP 报文详解