Dagger2 、 MVP的简单封装

Dagger2 + MVP的简单封装

现在很多 Android 开发都在用 MVP 模式,并且现在 Dagger2 注入依赖也挺方便的,所以就简单的对两者做了个封装,这样使用起来会更加方便。我们这里不对 MVP 做具体的讲解,只是简单的封装一下,便于使用,具体的 MVP 使用请参考其他文章。

代码已上传到 Github,有兴趣的可以去下载运行。

准备工作

Dagger引入

compile 'com.google.dagger:dagger:2.10'
compile 'com.google.dagger:dagger-android-support:2.10' // if you use the support libraries
annotationProcessor 'com.google.dagger:dagger-compiler:2.10'

M层

Model 层主要的职责有:

  • 从网络,数据库,文件,传感器,第三方等数据源读写数据。

  • 对外部的数据类型进行解析转换为APP内部数据交由上层处理。

  • 对数据的临时存储,管理,协调上层数据请求。

我们首先来定义接口 IModel :

public interface IModel {
    void onDestroy();
}

创建接口 BaseModel 继承于 IModel:

public interface BaseModel extends IModel{
}

这里在 IModel 中定义了 onDestroy() 方法,我们知道,M 层主要是负责对数据进行操作的,我们难免会持有网络请求等其他的对象的引用,为了防止内存泄漏,我们需要在 Model 销毁的时候,通过 onDestroy()方法中释放持有的引用。

V层

在 MVP 开发中,View 层通常指的是 Activity 、Fragment、View、ViewGroup 等。

主要职责:

  • 提供 UI 交互

  • 在 Presenter 的控制下修改 UI。

  • 将业务事件交由 Presenter 处理

View 层持有 Presenter 的引用,所以我们创建一个 BaseMvpActivity 如下:

public abstract class BaseMvpActivity<P extends BasePresenter> extends AppCompatActivity {

    @Inject
    protected P mPresenter;

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (null != mPresenter) {
            mPresenter.onDestroy();
        }
        this.mPresenter = null;
    }
}

可以看到,我们创建了个泛型 P ,并且这个泛型必须是 BasePresenter 的子类,可以看到定义 Presenter 的时候,上面有个注解是 @Inject ,这个注解就是 Dagger2 中的注解,使用这个注解就表示 mPresenter 是通过 Dagger2 注入的。另外在 Activity 销毁的时候,我们对持有的 Presenter 释放,防止内存泄漏。

然后我们再来定义一个接口 BaseView:

public interface BaseView {
}

这个接口就代表 View 层,我们使用的时候,一般需要针对每个页面都有一个接口继承于 BaseView,然后需要在具体的 Activity 中实现新定义的这个接口(比如 public interface IMainView estends BaseView ,我们就要实现 IMainView 这个接口,而不是 BaseView 这个接口)。也就是说我们平时写的页面都要继承于 BaseMvpActivity 并且 实现 BaseView 接口的子类。比如:


public interface IMainView extends BaseView{

}

public class MainActivity extends BaseMvpActivity implements IMainView{

}

P层

Presenter 层主要是连接 View 层和 Model 层的桥梁,负责把 View 层需要数据从 Model 层拿到,返回给 View 层;

所以我们在 P(Presenter) 层要持有 View 和 Model 层的引用。如下所示:

public class BasePresenter<M extends BaseModel, V extends BaseView> implements IPresenter {


    protected M mModel;

    protected V mView;

    public BasePresenter(M model, V view) {
        mModel = model;
        mView = view;
    }

    public BasePresenter(V view) {
        mView = view;
    }

    @Override
    public void onDestroy() {
        if (mModel != null) {
            mModel.onDestroy();
        }
        this.mModel = null;
        this.mView = null;
    }
}

可以看到,我们分别持有 View 层的引用 mView,Model 层的引用 mModel,为了防止内存泄漏,我们定义了一个 Ipresenter 接口,

public interface IPresenter {
    void onDestroy();
}

在 onDestroy() 方法中释放 View 层和 Model 层的引用。

使用

现在我们基本的已经封装好了,那么下面就通过一个实例来试用下:

创建 Component

@Component(modules = Login1Module.class)
public interface Login1Component {
    void inject(Login1Activity login1Activity);
}

创建 Module

@Module
public class Login1Module {

    private Login1Contract.ILoginView mILoginView;

    public Login1Module(Login1Contract.ILoginView ILoginView) {
        mILoginView = ILoginView;
    }

    @Provides
    Login1Contract.ILoginView getView() {
        return mILoginView;
    }

    @Provides
    Login1Contract.ILoginModel getModel(Login1Model model) {
        return model;
    }
}

创建契约来规定 Model 和 View

分析 View 层和 Model 层需要的操作,定义接口如下:

/**
 * 定义 View 和 Model 层规则
 * Created by smartsean on 2018/1/10.
 */
public interface Login1Contract {
    interface ILoginModel extends BaseModel{
        void login(String username, String password, OnLoginListener loginListener);
    }

    interface ILoginView extends BaseView{

        String getUserName();

        String getPassword();

        void clearUserName();

        void clearPassword();

        void showLoading();

        void hideLoading();

        void toMainActivity(UserInfoModel userInfoModel);

        void showFailedError();
    }

    interface OnLoginListener{
        void loginSuccess(UserInfoModel userInfoModel);

        void loginFailed();
    }

}

创建 Model

Model 层主要是对数据操作的,我们这里开启线程模拟登录操作:

/**
 * @author SmartSean Created on 2018/1/25 16:49.
 */

public class Login1Model implements Login1Contract.ILoginModel {

    @Inject
    public Login1Model() {
    }

    @Override
    public void login(final String username, final String password, final Login1Contract.OnLoginListener loginListener) {
        new Thread() {
            @Override
            public void run() {
                super.run();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if ("sean".equals(username) && "2".equals(password)) {
                    UserInfoModel userInfoModel = new UserInfoModel();
                    userInfoModel.setUsername(username);
                    userInfoModel.setPassword(password);
                    loginListener.loginSuccess(userInfoModel);
                } else {
                    loginListener.loginFailed();
                }
            }
        }.start();
    }

    @Override
    public void onDestroy() {
        // TODO: 2018/1/25 销毁持有的引用
    }
}

创建 Presenter

Presenter 层主要是连接 View 层和 Model 层的桥梁:

public class Login1Presenter extends BasePresenter<Login1Contract.ILoginModel, Login1Contract.ILoginView> {

    @Inject
    public Login1Presenter(Login1Contract.ILoginModel model, Login1Contract.ILoginView view) {
        super(model, view);
    }

    private Handler mHandler = new Handler();

    /**
     * 模拟登陆
     */
    public void login() {
        mView.showLoading();
        mModel.login(mView.getUserName(), mView.getPassword(), new Login1Contract.OnLoginListener() {
            @Override
            public void loginSuccess(final UserInfoModel userInfoModel) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mView.toMainActivity(userInfoModel);
                        mView.hideLoading();
                    }
                });
            }

            @Override
            public void loginFailed() {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mView.showFailedError();
                        mView.hideLoading();
                    }
                });
            }
        });
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        // TODO: 2018/1/25 销毁持有的引用
    }

    /**
     * 清除账户名和密码
     */
    public void clear() {
        mView.clearUserName();
        mView.clearPassword();
    }
}

创建Activity

public class Login1Activity extends BaseMvpActivity<Login1Presenter> implements Login1Contract.ILoginView {

    private EditText usernameEt, passwordEt;
    private Button loginBtn, clearBtn;
    private ProgressDialog progressDialog;

    private Context mContext;

    private static final String TAG = "Login1Activity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login1);
        initView();
        mContext = this;
        DaggerLogin1Component.builder().login1Module(new Login1Module(this)).build().inject(this);
    }

    private void initView() {
        usernameEt = findViewById(R.id.username_et);
        passwordEt = findViewById(R.id.password_et);
        loginBtn = findViewById(R.id.login_btn);
        clearBtn = findViewById(R.id.clear_btn);
        loginBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mPresenter.login();
            }
        });
        clearBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mPresenter.clear();
            }
        });
        progressDialog = new ProgressDialog(this);
        progressDialog.setTitle("加载中");
    }

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

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

    @Override
    public void clearUserName() {
        usernameEt.setText("");
    }

    @Override
    public void clearPassword() {
        passwordEt.setText("");
    }

    @Override
    public void showLoading() {
        progressDialog.show();
    }

    @Override
    public void hideLoading() {
        progressDialog.dismiss();
    }

    @Override
    public void toMainActivity(UserInfoModel userInfoModel) {
        MainActivity.startAction(this, userInfoModel.getUsername());
        finish();
    }

    @Override
    public void showFailedError() {
        Log.d(TAG, "showFailedError: 登陆失败");
        Toast.makeText(mContext, "登陆失败,请重新尝试", Toast.LENGTH_SHORT).show();
    }
}

具体的代码 地址

猜你喜欢

转载自blog.csdn.net/Sean_css/article/details/79624156
今日推荐