MVP模式初探

之前一直听说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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值