本文主要是介绍Dagger2和MVP的结合,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
先挖个坑,这里会有两篇整理后的dagger2和MVP的博客链接
dagger2 入门 MVP示例
Dagger2通过注解的方式,来实现对象的统一管理(简化初始化);
MVP 主要是减少Activity/Fragment的代码量,只留下清晰的数据和界面的衔接(或者说数据填充);通过使用接口搭建关系,将耦合甩给抽象出来的接口,表现上就是界面逻辑、数据交接集中到了P层;数据的计算、处理是在M层;
mvp有一个明显的好处:即便没有界面,也可通过“单纯的Java”将业务处理完毕,以等带界面衔接。这一点尤其适用于美工瞎几把改图不断完善设计的情况。
在我没有将这两个东西结合起来使用的时候,我一直认为这是一件很复杂的事:
1. P层持有的V的句柄是从界面传过来的,而界面持有P的实例来调用触发方法,就这么来看,一个PV的逻辑就要提供两个Component…..好恐怖的感觉。
2. MVP已经比普通的类数量增加了2~3倍,再加上dagger2的接近两倍,我的天呐!
3. 没试过,劳资的内心就是抵触,怎么滴吧!
接下来直接来个例子吧,废话少说(因为废话都在前两篇说够了),以登录作为典型案例来处理。
V:
/*** Created by ShuaiZhang on 2016/9/19.* 定义接口包括四个方法,分别是获取用户名;获取密码;* 显示登陆提示;显示登陆结果*/
public interface ILoginView {String getName();String getPwd();void showTip(String tip);void setResult(String result);
}
M:
/*** Created by ShuaiZhang on 2016/9/19.* 我不想说话,你么也别打我*/
public class LoginBiz {//把用户名和密码连接成一个串假,假装是登录public String login(String name, String pwd){String result = "UserName:" + name +"\nPassword:" + pwd;return result;}
}
P:
/*** Created by ShuaiZhang on 2016/9/19.* MVP,我还是啥也不想说*/
public class LoginPresenter {private ILoginView loginView;private LoginBiz loginBiz;public LoginPresenter(ILoginView loginView) {this.loginView = loginView;loginBiz = new LoginBiz();}public void doLogin(){loginView.showTip("Loading。。。");String result = loginBiz.login(loginView.getName(), loginView.getPwd());loginView.showTip("Success!");loginView.setResult(result);}
}
为了增加篇幅,activity_login.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical" android:layout_width="match_parent"android:layout_height="match_parent"><EditTextandroid:id="@+id/edt_name"android:layout_width="match_parent"android:layout_height="wrap_content" /><EditTextandroid:id="@+id/edt_pwd"android:layout_width="match_parent"android:layout_height="wrap_content" /><Buttonandroid:id="@+id/btn_login"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="Login"/><TextViewandroid:id="@+id/txt_show"android:layout_marginTop="20dp"android:layout_width="match_parent"android:layout_height="wrap_content" />
</LinearLayout>
LoginActivity.class:
/*** Created by ShuaiZhang on 2016/9/19.* 登陆界面,实现登陆的抽象View ILoginView接口*/
public class LoginActivity extends AppCompatActivity implements ILoginView {LoginPresenter presenter;@BindView(R.id.edt_name)EditText edtName; // 用户名@BindView(R.id.edt_pwd)EditText edtPwd; // 密码@BindView(R.id.btn_login)Button btnLogin; //登录按钮@BindView(R.id.txt_show)TextView txtShow; //显示登录结果@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_login);ButterKnife.bind(this);presenter = new LoginPresenter(this);//初始化presenter//装X的拉姆达表达式btnLogin.setOnClickListener(v -> {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;}//传递用户名@Overridepublic String getName() {return edtName.getText().toString();}//传递密码@Overridepublic String getPwd() {return edtPwd.getText().toString();}//显示提示@Overridepublic void showTip(String tip) {Toast.makeText(this,tip,Toast.LENGTH_SHORT).show();}//显示结果@Overridepublic void setResult(String result) {txtShow.setText(result);}
}
到这里,一个以Login为逻辑的MVP基本示例算是都有了。
那么接下来,就是Dagger2了。
想想前面三个疑问,握草,算了,还是慢慢写吧,先写个module试试?
/*** Created by ShuaiZhang on 2016/9/19.* 先写着试试*/
@Module //为登录提供点东西
public class LoginModule {//因为LoginPresenter构造器需要一个这玩意,所以放进了该Module的构造参数//这样,在LoginActivity初始化时就必然传递该参数private ILoginView loginView;//有参数的module构造器要求必须显式的传入本实体 必须携带参数public LoginModule(ILoginView loginView) {this.loginView = loginView;}@Provides //这个注解表名会被自动处理public LoginPresenter getLoginPresenter() {return new LoginPresenter(loginView);}
}
Module有了,来个Component?
/*** Created by ShuaiZhang on 2016/9/19.* 这里决定怎么“组装”Component* 1.决定伴随生命周期(inject方法和参数),* 2.将会包含哪些实体(各module类中的@Provide返回类型)*/
@Component(modules=LoginModule.class)//这里还可以有一个依赖,我没搞懂,没添加
public interface LoginActivityComponent {void inject(LoginActivity activity);//有LoginActivity实现初始化,并绑定它的生命周期
}
按照dagger2的套路下一步Build一下:
注意:就是菜单栏的Build àRebuild Project;而Sync是没有用的,有时候这两个效果一样,但是这里不一样。
接下来就是修改LoginActivity的代码了(只提供修改部分,因为其与的没差别):
@Inject
LoginPresenter presenter;
为LoginPresenter添加@Inject注解,是它能自动获取dagger生成的对象。
//dagger不需要这里手动实现了
//presenter = new LoginPresenter(this);//初始化presenter
DaggerLoginActivityComponent.builder()//套路要求.loginModule(new LoginModule(this))//显式传入,LoginPresenter必要的参数ILoginView.build()//套路要求.inject(this);//绑定生命周期
这里注释掉不在需要的presenter的初始化,然后添加DaggerLoginActivityComponent的初始化(名字好特么长)。
Dagger2对MVP的影响只是在关系建立的"方式"上,事实上不对MVP的逻辑关系造成任何影响。它甚至不改变连接的结构,而是以一种新的衔接形式。
一句话描述:dagger2为mvp提供了一种新的、统配的方式来建立相互的联系。
没了,写完了,dagger2+mvp就这样搞定了,我擦,那我前面的顾虑呢?好吧,回头再看一下:
问题:P层持有的V的句柄是从界面传过来的,而界面持有P的实例来调用触发方法,就这么来看,一个PV的逻辑就要提供两个Component…..好恐怖的感觉。
其实这是个误解,Presenter的实例化只是需要一个参数,这个参数是作为presenter的一部分,也就是presenter不再需要独立的Component。之所以我会有这个疑问,其实还是我自己对MVP的理解没有更好的深入,这个….
问题:MVP已经比普通的类数量增加了2~3倍,再加上dagger2的接近两倍,我的天呐!
这个是逻辑分块,清晰化后的代价,换句话说:吃好的,就要多花钱;其实逻辑方面的简洁是优于代码量增加带来的不便的,如果你还在纠结代码量增加了,那么我只能说:兄弟,你代码量还不够,继续加油吧!
问题:没试过,劳资的内心就是抵触,怎么滴吧!
两个字:呵呵!
你们以为到这就完了?图样森破!
现在来看,LoginBiz类是不需要参数的,好像prenter里面那样写,没啥问题,也对;但是既然我们有了dagger,那么我们为什么不试着让它“更加dagger2”一些呢?
修改presenter的构造方法:
public LoginPresenter(ILoginView loginView, LoginBiz loginBiz) {this.loginView = loginView;this.loginBiz = loginBiz;
}
这个时候LoginModule也需要修改:
@Provides //这个注解表名会被自动处理
public LoginPresenter getLoginPresenter() {return new LoginPresenter(loginView,new LoginBiz());
}
No!这不够dagger2!
再改LoginModule:
@Provides //这个注解表名会被自动处理
public LoginPresenter getLoginPresenter(LoginBiz loginBiz) {return new LoginPresenter(loginView,loginBiz);
}
@Provides
public LoginBiz getLoginBiz(){return new LoginBiz();
}
这里的getLoginPresenter的参数LoginBiz将会由下面的方法提供。
那么,如何更加更加dagger2,接下来就自己开发吧,水平所限,我只能装逼到这了……
提交的时候发现少个图,算了,哪天心情好哪天补上吧这篇关于Dagger2和MVP的结合的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!