Android MVP模式实现

MVP模式介绍

MVP模式是MVC模式的一个演化版本,全称Model View Presenter 。MVP模式的运用越来越多,它有效的降低了View的复杂度,避免了大量的业务逻辑在View中进行处理。MVP模式解除了Model和View的耦合,使得程序有更好的扩展性,可读性以及可测试性,Model和View是通过Presenter来进行通信,通过各自的接口来实现,依赖于抽象而不是具体,所以更加的灵活,修改起来更加的方便。

MVP模式并没有标准的模式,可以有多种的实现方式,主要是通过Presenter将View和Model解耦合。

Model

负责对于数据的存取,Presenter层通过Model来获得数据

View

View一般都是Activity或者Fragment,View里面会有一个Presenter变量,来实现对于View逻辑的处理

Presenter

用于沟通View和Model使其独立开来,从Model获得数据通过Presenter交由View


MVP的实现

项目结构


首先看看写得基类Presenter

public abstract class Presenter<T> {
    protected Context context;
    public Reference<T> mView;

    public void attach(T mView) {
        this.mView = new WeakReference<>(mView);
    }

    public void detach() {
        if (mView != null) {
            mView.clear();
            mView = null;
        }
    }

    public Presenter(Context context) {
        this.context = context;
    }
}
这是一个泛型类,泛型类型是View所要实现的接口的类型,其中有attach和detach方法,因为在Presenter中会持有View的引用,View一般是Activity,所以在销毁Activity时需要解除与Presenter的关联,避免内存泄漏;attach是为了与Activity建立联系。

下面看看BaseMvpActivity,这是一个基类Activity

public abstract class BaseMvpActivity<V, T extends Presenter<V>> extends
        Activity {
    protected Context context;

    private LinearLayout parentLinearLayout;
    private TextView mTextViewTitle;
    public T presenter;


    @SuppressWarnings("unchecked")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initContentView(R.layout.activity_base);
        context = this;
        // 初始化Presenter
        presenter = createPresenter();
        // 初始化View,View与Presenter建立关联
        presenter.attach((V) this);

        mTextViewTitle = (TextView) findViewById(R.id.tv_title);


    }

    /**
     * 设置标题栏的文字
     *
     * @param title
     */
    protected void setTitleText(String title) {
        mTextViewTitle.setText(title);
    }

    /**
     * 初始化contentview
     */
    private void initContentView(int layoutResID) {
        ViewGroup viewGroup = (ViewGroup) findViewById(android.R.id.content);
        viewGroup.removeAllViews();
        parentLinearLayout = new LinearLayout(this);
        parentLinearLayout.setOrientation(LinearLayout.VERTICAL);
        viewGroup.addView(parentLinearLayout);
        LayoutInflater.from(this)
                .inflate(layoutResID, parentLinearLayout, true);
    }

    @Override
    public void setContentView(int layoutResID) {
        LayoutInflater.from(this)
                .inflate(layoutResID, parentLinearLayout, true);
    }

    @Override
    public void setContentView(View view) {
        parentLinearLayout.addView(view);
    }

    @Override
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        parentLinearLayout.addView(view, params);
    }


    @Override
    protected void onDestroy() {
        presenter.detach();
        super.onDestroy();
    }

    // 实例化presenter
    public abstract T createPresenter();

}

BaseMVPActivity含有两个泛型类型,第一个是View(Activity)的接口类型,第二个是Presenter的类型。在onCreate中,创建了Presenter,并通过attach方法使得Presenter与Activity建立了联系,在onDestroy中解除了联系,避免内存泄漏。其他一些代码是一些共同逻辑的实现,以便在子Activity中复用。


Model

public class LoginModel {

    public interface CallBack {
        void onSuccess(String string);

        void onFailure(String string);
    }

    public void login(final String username, final String password, final CallBack callBack) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (username.equals("lzy") && password.equals("123")) {
                    callBack.onSuccess("登录成功");
                } else {
                    callBack.onFailure("登录失败");
                }

            }
        }).start();
    }
}
登录自然会有一个请求网络数据登录的方法,CallBcak接口是为了向Presenter暴露出获得的数据,使得Presenter获取Model的数据


LoginView

public interface LoginView extends BaseView {

    void changeText(String text);

    String getUserName();

    String getPassword();
}
LoginView接口就是Activity的逻辑接口,建立Presenter和View的联系,用于在Presenter中回调,Activity(即View)中的逻辑交由Presenter处理,通过LoginView接口回调给Activity展示。

看看MainActivity

public class MainActivity extends BaseMvpActivity<LoginView, LoginPresenter> implements LoginView {

    private TextView mTextView;
    private EditText mEditTextUsername;
    private EditText mEditTextPassword;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        setTitleText("主界面");
        Button button = (Button) findViewById(R.id.bt);
        mTextView = (TextView) findViewById(R.id.tv);
        mEditTextUsername = (EditText) findViewById(R.id.et_username);
        mEditTextPassword = (EditText) findViewById(R.id.et_password);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                presenter.login(v);
            }
        });
    }

    @Override
    public LoginPresenter createPresenter() {
        return new LoginPresenter(context);
    }

    @Override
    public void changeText(String text) {
        mTextView.setText(text);
    }

    @Override
    public String getUserName() {
        return mEditTextUsername.getText().toString().trim();
    }

    @Override
    public String getPassword() {
        return mEditTextPassword.getText().toString().trim();
    }

    @Override
    public void showLoading() {

    }

    @Override
    public void hideLoading() {

    }

    @Override
    public void showToast(String text) {
        Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
    }

}
现在主界面看起来就十分的简洁了,Activity就只是负责view的显示,逻辑或数据都不再在Activity里面处理。

LoginPresenter

public class LoginPresenter extends Presenter<LoginView> {

    private LoginModel loginModel;
    private Handler handler;

    public LoginPresenter(Context context) {
        super(context);
        loginModel = new LoginModel();
        handler = new Handler();
    }

    public void login(View view) {
        if (mView.get().getPassword().isEmpty() || mView.get().getUserName().isEmpty()) {
            mView.get().showToast("用户名或密码不能为空");
            return;
        }
        mView.get().changeText("正在登录");
        loginModel.login(mView.get().getUserName(), mView.get().getPassword(), new LoginModel.CallBack() {
            @Override
            public void onSuccess(final String string) {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        mView.get().changeText(string);
                    }
                });
            }

            @Override
            public void onFailure(final String string) {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        mView.get().changeText(string);
                    }
                });
            }
        });
    }

}


源码下载


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值