MVP+Dagger2解耦开发

本文介绍如何利用Dagger2依赖注入框架减少MVP模式中的代码耦合性。通过具体示例展示了如何在MVP架构中引入Dagger2,实现更简洁、高效的代码结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


   本文转载自:http://blog.youkuaiyun.com/shareye1992/article/details/52690474

                        http://www.jianshu.com/p/01d3c014b0b1

  


MVP模式大家都不陌生,但是缺点应该也都清楚,相比MVC多了不少的代码量,而且还有着内存溢出的缺点,毕竟虽说是解耦,但是因为需要new出来p层或者M层,最后还是会产生耦合性,和我们androd的单一职责性不符,所以,我们就要想办法降低MVP之间的耦合性,所以就要用到了Dagger2,依赖注入。

Dagger2的注解用处:
注解
用法
@Module
Modules类里面的方法专门提供依赖,所以我们定义一个类,用@Module注解,这样Dagger在构造类的实例的时候,就知道从哪里去找到需要的 依赖。modules的一个重要特征是它们设计为分区并组合在一起(比如说,在我们的app中可以有多个组成在一起的modules)
@Provide
在modules中,我们定义的方法是用这个注解,以此来告诉Dagger我们想要构造对象并提供这些依赖。
@Singleton
当前提供的对象将是单例模式 ,一般配合@Provides一起出现
@Component
用于接口,这个接口被Dagger2用于生成用于模块注入的代码
@Inject
在需要依赖的地方使用这个注解。(你用它告诉Dagger这个 构造方法,成员变量或者函数方法需要依赖注入。这样,Dagger就会构造一个这个类的实例并满足他们的依赖。)
@Scope
Scopes可是非常的有用,Dagger2可以通过自定义注解限定注解作用域。
看看Dagger2 的流程:

Dagger2 流程


但是在上一张,我们也看到了,依赖注入,哪怕是最简单的,也还是需要一个注入(module),和一个注入接口,注入类用来实例化被注入类,同时向里面传入参数等等,而接口就是通过注解来将注入类中的实例注入到应用类(activity)里,那么,如果再加上MVP的话代码不是会多不少嘛?最起码P层关联view层一个吧,P层和Module层不还得一个?这......






不过实际上并没有那么难,来看下代码
先是view层继承的接口:
/**
* 类描述:定义包括四个方法,分别获取用户名;获取密码
* 显示登录提示,显示登录结果
* 姓名 :刘希鑫
*/

public interface ILoginView {
String getName();
String getPwd();

void showTip(String tip);
void setResult(String result);
}

View层
public class MainActivity extends AppCompatActivity implements ILoginView{

private EditText edtName;
private EditText edtPwd;
private Button btnLogin;
private TextView txtShow;

@Inject //这是注入的类,如果没有使用dagger2的话就是正常的实例化
LoginPresenter presenter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edtName = (EditText) findViewById(R.id.edt_name);
edtPwd = (EditText) findViewById(R.id.edt_pwd);
btnLogin = (Button) findViewById(R.id.btn_login);
txtShow = (TextView) findViewById(R.id.txt_show);

//初始化presenter 使用dagger2就不需要手动实现了
// presenter = new LoginPresenter(this);
DaggerLoginActivityComponent.builder()//套路要求
.loginModule(new LoginModule(this))//显示传入,LoginPresenter必要的参数ILoginView
.build()//套路要求
.inject(this);//绑定生命周期


//X的拉姆达表达式
btnLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
boolean checkinput = checkinput();
if (checkinput){
presenter.doLogin();
}
}
});
}
//输入检查
private boolean checkinput(){
if (edtName.getText().toString().equals("")){
showTip("请输入姓名");
return false;
}

if (edtPwd.getText().toString().equals("")){
showTip("请输入密码");
return false;
}
return true;
}
//传递用户名
@Override
public String getName() {
String s = edtName.getText().toString();
return s;
}
//传递密码
@Override
public String getPwd() {
String s2 = edtPwd.getText().toString();
return s2;
}

//显示提示
@Override
public void showTip(String tip) {
Toast.makeText(MainActivity.this,tip,Toast.LENGTH_LONG).show();
}
//显示结果
@Override
public void setResult(String result) {
txtShow.setText(result);
}
}

然后是P层
/**
* 类描述:p
* 姓名 :刘希鑫
*/

public class LoginPresenter {
private MainActivity loginView; //main对象
private LoginBiz loginBiz; //M层的对象
public LoginPresenter(MainActivity iLoginView){
this.loginView=iLoginView;
//这里只是将view层和P层进行了解耦,M层暂时没动
loginBiz=new LoginBiz();
}
public void doLogin(){
//通过main对象调用了里面实现的接口方法,打印数据
loginView.showTip("Loading.......");
//M层只是进行了一个组合完成假的处理
String result=loginBiz.login(loginView.getName(),loginView.getPwd());
loginView.showTip("Success!!!!!!!!");
loginView.setResult(result);
}}

Module层

/**
* 类描述:M
* 姓名 :刘希鑫
*/

public class LoginBiz {
//把用户名和密码连接成一个串假,假装是登录
public String login(String name,String pwd){
String result = "UserName:" + name +"\nPassword:" + pwd;
return result;
}
}
Mainactivity的布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="text.bwie.com.mvpdagger2.v.MainActivity">
<EditText
android:id="@+id/edt_name"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/edt_pwd"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/btn_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Login"/>
<TextView
android:id="@+id/txt_show"
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

这样,一个简单的MVP框架就完成了,只要将那个注入的换成new的就行,那么,怎么注入呢?接下来就是了。不过有一点好处,就是依赖注入的时候,不需要改变P层和Module层,就连View层也只是改变了P层的注入方法而已。


先是创建一个P层的Module,通过构造方法实例化P层需要的View的this,如果P层有需要的参数,就需要在这里表明,然后通过注解的方法将属性传入。
/**
* 类描述:daggermodule
* 姓名 :刘希鑫
*/
@Module //为登陆提供点东西
public class LoginModule {
//因为loginpresenter构造器需要一个这玩意,所以放进了该Module的构造参数
//这样,在loginActivity初始化是就必然传递该参数
private MainActivity loginView;
//有参数的module构造器要求必须显示的传入本实体,必需带参数
public LoginModule(MainActivity loginView){
this.loginView=loginView;
}

@Provides //这个注解表明会被自动处理
public LoginPresenter getLoginPresenter(){
return new LoginPresenter(loginView);
}
}

随后,就是注入的接口
/**
* 类描述:
* 这里决定怎么组装”Component
* 1.决定伴随生命周期(inject方法和参数),
* 2.将会包含哪些实体(各module类中的@Provide返回类型)
* 姓名 :刘希鑫
*/
@Component(modules = LoginModule.class)//这里还可以有一个依赖,但是没添加
public interface LoginActivityComponent {
void inject(MainActivity activity);//mainactivity实现初始化,并绑定他的生命周期
}

到了这里,一个简单的View层和P层之间的依赖注入就完成了。

而如果要将M层也加入进来呢?只要在P层改一下构造器,在改一下注入Module类就可以了。


修改后的P层的构造器
//使用Dagger2需要修改的构造器
public LoginPresenter(MainActivity loginView, LoginBiz loginBiz){
this.loginView=loginView;
this.loginBiz=loginBiz;
}

修改后的注入Module类
/**
* 类描述:daggermodule
* 姓名 :刘希鑫
*/
@Module //为登陆提供点东西
public class LoginModule {
//因为loginpresenter构造器需要一个这玩意,所以放进了该Module的构造参数
//这样,在loginActivity初始化是就必然传递该参数
private MainActivity loginView;
//有参数的module构造器要求必须显示的传入本实体,必需带参数
public LoginModule(MainActivity loginView){
this.loginView=loginView;
}



@Provides //这个注解表明会被自动处理
public LoginPresenter getLoginPresenter(){
//实例化P层,传入两个参数,ViewModule
return new LoginPresenter(loginView,getloginBiz());
}
@Provides //这个注解表明会被自动处理
public LoginBiz getloginBiz(){
//实例化返回M层对象
return new LoginBiz();
}

}

这样,MVP框架就完成了,个人感觉,这种方式就是通过在注入的module层里设置一个构造方法,接收到View层传来的参数,然后设置一个方法,用@Provides修饰,表示会自动处理,然后返回值设置为P层的类名,返回的就是new的P层对象,用有参构造器传入参数,这样View和Module层全都传入到了P层里,执行操作,而通过依赖注入,P层和View层并没有耦合上,Module层和P层也一样。

但是有一个问题:MVP是通过接口回调来返回数据的,那Module层里调用P层的对象怎么弄?


后来我试了一下,原来我是多次一举,P层的对象是通过M层的对象调用里面的方法传入的,既然已经将M层的对象注入到了P层里,那么调用方法,还不简单?而接口回调,尤其是重写了接口里面的方法的,不也是一个对象调用自身的方法的吗?这样一算。
完全无压力啊!只需要一个注入类和注入接口,就解决了MVP的耦合性啊!下面就是P层和M层的示意:
/**
* 类描述:M
* 姓名 :刘希鑫
*/

public class LoginBiz {
//获得P层对象
Pjiekou p;
public void getp(Pjiekou p1){
this.p=p1;
}

//把用户名和密码连接成一个串假,假装是登录
public String login(String name,String pwd){
//只是随意的掉了一个接口方法实验
p.getName();
String result = "UserName:" + name +"\nPassword:" + pwd;
return result;
}
}
P层:

/**
* 类描述:p
* 姓名 :刘希鑫
*/

public class LoginPresenter implements Pjiekou{
private MainActivity loginView; //main对象
private LoginBiz loginBiz; //M层的对象

//使用Dagger2需要修改的构造器
public LoginPresenter(MainActivity loginView, LoginBiz loginBiz){
this.loginView=loginView;
this.loginBiz=loginBiz;
}

public void doLogin(){
//通过main对象调用了里面实现的接口方法,打印数据
loginView.showTip("Loading.......");
//Module层传入对象
loginBiz.getp(this);
//M层只是进行了一个组合完成假的处理
String result=loginBiz.login(loginView.getName(),loginView.getPwd());
loginView.showTip("Success!!!!!!!!");
loginView.setResult(result);

}

//重写的接口方法
@Override
public String getName() {
return null;
}

@Override
public String getPwd() {
return null;
}

@Override
public void showTip(String tip) {

}

@Override
public void setResult(String result) {

}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值