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源码
欢迎批评指正!

原创粉丝点击