MVP+Dagger2解耦开发


   本文转载自:http://blog.csdn.net/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 + " \n Password:" + 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层有需要的参数,就需要在这里表明,然后通过注解的方法将属性传入。
/**
* 类描述: dagger module
* 姓名 :刘希鑫
*/
@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类
/**
* 类描述: dagger module
* 姓名 :刘希鑫
*/
@Module // 为登陆提供点东西
public class LoginModule {
// 因为 loginpresenter 构造器需要一个这玩意,所以放进了该 Module 的构造参数
// 这样,在 loginActivity 初始化是就必然传递该参数
private MainActivity loginView ;
// 有参数的 module 构造器要求必须显示的传入本实体,必需带参数
public LoginModule(MainActivity loginView){
this . loginView =loginView;
}



@Provides // 这个注解表明会被自动处理
public LoginPresenter getLoginPresenter(){
// 实例化 P 层,传入两个参数, View Module
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 + " \n Password:" + 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) {

}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值