本文转载自:http://blog.csdn.net/shareye1992/article/details/52690474
http://www.jianshu.com/p/01d3c014b0b1
MVP模式大家都不陌生,但是缺点应该也都清楚,相比MVC多了不少的代码量,而且还有着内存溢出的缺点,毕竟虽说是解耦,但是因为需要
new出来p层或者M层,最后还是会产生耦合性,和我们androd的单一职责性不符,所以,我们就要想办法降低MVP之间的耦合性,所以就要用到了Dagger2,依赖注入。
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) {
}
}