MVP在Android中2种实现(2)

对此题目有兴趣的同学都是知道至少了解这个东西,在此我不准备讲太多的理论,因为互联网上对MVP的介绍铺天盖地了.例如这位同学的文章就很精彩 Android MVP 详解(上),本人只是介绍两种MVP在Android的实现方法。

第一种:MVP在Android中2种实现(1)
第二种: MVP在Android中2种实现(2)

本文是对 MVP在Android中2种实现(1)中讲述的MVP实现方式的一种改进和增强。第一种方法最大的弊端就是有可能造成内存泄漏,本文利用虚引用结合Activity的生命周期来解决这个问题。

第一种方法会造成内存泄漏是由于Presenter持有了View的强引用,导致当系统试图回收销毁的View实例时候受阻导致内存泄漏,那么只要我们让Presenter持有View弱引用即可解决此问题,下面看代码:

Prestener

我们定义一个Presenter的基类,让其他presenter继承此类。

package com.ss007.androidmvpsample.enhancedMvp;

import java.lang.ref.Reference;
import java.lang.ref.WeakReference;

/**
 * Copyright (C) 2017 ben
 *
 *
 * @author ben
 * @version 1.0
 * @createDate 2017/7/5 10:34
 * @description
 */

public class BasePresenter<V>
{
    protected Reference<V> mViewRef;

    public void attachView(V view)
    {
        mViewRef = new WeakReference<V>(view);
    }

    public V getView()
    {
        if (mViewRef == null)
        {
            return null;
        }
        return mViewRef.get();
    }

    public boolean isViewAttached()
    {
        return mViewRef != null && mViewRef.get() != null;
    }

    public void detachView()
    {
        if (mViewRef != null)
        {
            mViewRef.clear();
            mViewRef = null;
        }
    }
}

这是一个泛型类,参数为V为要引用的View.

  • attachView()方法的作用是创建View的虚引用,此方法放在View初始化过程中,例如onCreate()方法中

  • detachView()方法的作用是销毁View的虚引用,此方法放在View销毁化过程中,例如onDestroy()方法中

  • getView()放用来获取View

View

我们定义一个View的基类,让其他View继承此类。

package com.ss007.androidmvpsample.enhancedMvp;

import android.os.Bundle;

import com.ss007.androidmvpsample.BaseActivity;

/**
 * Copyright (C) 2017
 *
 *
 * @author ben
 * @version 1.0
 * @createDate 2017/7/5 10:32
 * @description
 */

public abstract class MVPBaseActivity<V,T extends BasePresenter<V>> extends BaseActivity
{
    protected T mPresenter;

    @Override
    protected void onCreate(Bundle arg)
    {
        super.onCreate(arg);
        mPresenter=createPresenter();
        mPresenter.attachView((V) this);
    }

    @Override
    protected void onDestroy()
    {
        super.onDestroy();
        mPresenter.detachView();
    }

    protected abstract T createPresenter();
}

这也是一个泛型基类,第一个泛型参数V:代表当前处理的View,第二个泛型参数T:代表当前使用的Presenter,要求此presenter必须继承至
BasePresenter.要求每个Activity必须继承至此类。

onCreate()onDestroy()中的处理逻辑已经在讲解 Prestener 时候已经说过。

createPresenter() 用来创建presenter实例,便于在View中通过其调用presenter的方法,此方法是abstract的,这就要求MVPBaseActivity子类必须实现此方法。

讲清楚了这两个类,下面的代码就简单了,基本就是与第一种一样了。

具体实例

第一步:根据业务需要定义两个接口,一个给Presenter实现,一个给View实现。

第二步:如果决定使用轻Model重Presenter的模式,那么Model基本就是一些JavaBean类,让View持有Presenter的引用(最好是以接口声明),那么在View中就可以调用Presenter里面的方法了,例如点击登录按钮,调用presenter里面的login()方法。

第三步:Presenter里面的方法执行后会有结果回来,那么View是要对这些结果做出响应的,例如登录后是成功了还是失败了呢?这就需要从Presenter里面调用View里面的方法将结果传过去。所以需要Presenter持有一个View的引用(最好是以接口声明)。

presenter实现的接口Login2Presenter

package com.ss007.androidmvpsample.enhancedMvp;

/**
 * Copyright (C) 2017
 *
 *
 * @author ben
 * @version 1.0
 * @createDate 2017/7/5 10:40
 * @description
 */

public interface Login2Presenter
{
    void login(String userName,String passWord);
}

View实现的接口Login2ActView

package com.ss007.androidmvpsample.enhancedMvp;

/**
 * Copyright (C) 2017
 *
 *
 * @author ben
 * @version 1.0
 * @createDate 2017/7/5 10:40
 * @description
 */

public interface Login2ActView
{
    void loginSuccess(String responseStr);
    void loginFailed(String code,String errBody);
}

View

package com.ss007.androidmvpsample.enhancedMvp;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.ss007.androidmvpsample.R;

public class Login2Act extends MVPBaseActivity<Login2Act,Login2PresenterImp> implements Login2ActView
{
    private final static String TAG = Login2Act.class.getSimpleName();

    private EditText userName, passWord;
    private Button btnLogin;
    private Activity mAct;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login2);
        mAct = this;
        userName = (EditText) findViewById(R.id.et_user_name);
        passWord = (EditText) findViewById(R.id.et_password);
        btnLogin = (Button) findViewById(R.id.btn_login);
        btnLogin.setOnClickListener(clickListener);
    }

    @Override
    protected Login2PresenterImp createPresenter()
    {
        return new Login2PresenterImp();
    }

    @Override
    public void loginSuccess(String responseStr)
    {
        btnLogin.setText("Login");
        Log.d(TAG, String.format("result: %s", responseStr));
        Toast.makeText(mAct, "login success", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void loginFailed(String code, String errBody)
    {
        Log.d(TAG, String.format("error code:%s | error body: %s", code, errBody));
        Toast.makeText(mAct, "login failed", Toast.LENGTH_SHORT).show();
    }
    private View.OnClickListener clickListener = new View.OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
            switch (v.getId())
            {
                case R.id.btn_login:
                    if (mPresenter != null)
                    {
                        btnLogin.setText("Loginning ...");
                        mPresenter.login(userName.getText().toString(), passWord.getText().toString());
                    }

                    break;
                default:
                    break;
            }
        }
    };
}

Presenter

package com.ss007.androidmvpsample.enhancedMvp;

import android.os.Handler;

/**
 * Copyright (C) 2017  ben
 *
 *
 * @author ben
 * @version 1.0
 * @createDate 2017/7/5 10:40
 * @description
 */

public class Login2PresenterImp extends BasePresenter<Login2Act> implements Login2Presenter
{
    @Override
    public void login(String userName, String passWord)
    {
        final Login2ActView login2ActView= getView();
        //模拟登录(Mock login)
        new Handler().postDelayed(new Runnable()
        {
            @Override
            public void run()
            {
                boolean isSuccess=true;//depend on result from your server
                if (login2ActView==null)
                    return;
                if (isSuccess)
                {
                    login2ActView.loginSuccess("the result get from your server");
                }
                else
                {
                    login2ActView.loginFailed("error code","error body");
                }
            }
        }, 2000);
    }
}

小结

Activity可以这么做,那么Fragment也可以使用类似的方法处理.

最后祝大家编码快乐,生活快乐。

源代码下载地址

猜你喜欢

转载自blog.csdn.net/shusheng0007/article/details/77938378
今日推荐