本文转载自:http://blog.youkuaiyun.com/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 +"\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层有需要的参数,就需要在这里表明,然后通过注解的方法将属性传入。
/**
*
类描述: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 +"\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) {
}
}