手把手带你搭建Mvp+Dagger架构
0. 序言
- 之前写过一篇名为"看完不会写MVP架构我跪搓板"的博文,收到一些阅读者的建议,希望能够对Rxjava的生命周期进行管理以及添加Dagger到MVP架构中,所以今天抽一点时间写一篇拿来即可于实战的Demo。
1. 博文目录
添加依赖
创建项目基本目录
实现Model
定义契约接口NewsInfoContract
实现Presenter
实现View
补充网络配置代码
适配Android28网络请求
添加Dagger2
实现RetrofitManager单例
2. 添加依赖
implementation 'com.squareup.retrofit2:retrofit:2.5.0'implementation 'com.squareup.retrofit2:converter-gson:2.5.0'implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'implementation 'io.reactivex.rxjava2:rxjava:2.2.4'implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'implementation 'com.squareup.okhttp3:okhttp:3.12.0'implementation 'com.squareup.okhttp3:logging-interceptor:3.5.0'implementation 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle:2.2.1' 复制代码3. 创建项目基本目录
4. 实现Model
- 创建实体类NewsInfo:
- 定义获取网络数据的接口类NetTask:
- 编写NetTask的实现类NewsInfoTask:
6. 定义契约接口NewsInfoContract:
public interface NewsInfoContract {interface Presenter{void getNewsInfo(LifecycleProvider lifecycleProvider, String type);}interface View {void setNewsInfo(NewsInfo newsInfo);void showLoading();void hideLoading();void showError();} } 复制代码7. 实现Presenter
- 编写NewsInfoContract.Presenter接口的实现类NewsInfoPresenter:
6. 实现View
public class MainActivity extends AppCompatActivity implements NewsInfoContract.View {private NewsInfoContract.Presenter mPresenter = new NewsInfoPresenter(NewsInfoTask.getInstance(),this);LifecycleProvider<Lifecycle.Event> lifecycleProvider = AndroidLifecycle.createLifecycleProvider(this);private TextView mNew_Content;private Dialog mDialog;protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mNew_Content = findViewById(R.id.tv_content);mDialog = new ProgressDialog(this);mDialog.setTitle(R.string.dialog_get_info);findViewById(R.id.bt_get_news).setOnClickListener(v -> {mPresenter.getNewsInfo(lifecycleProvider,Constant.DEFAULT_TYPE);});}public void setNewsInfo(NewsInfo newsInfo) {if (newsInfo != null && newsInfo.getResult() != null && newsInfo.getResult().getData() != null) {mNew_Content.setText(newsInfo.getResult().getData().get(0).getTitle());}}public void showLoading() {mDialog.show();}public void hideLoading() {if (mDialog.isShowing())mDialog.dismiss();}public void showError() {Toast.makeText(this, R.string.toast_net_tip, Toast.LENGTH_SHORT).show();}} 复制代码7. 补充网络配置代码
- Retrofit 管理类:
- 网络请求接口服务类NewsService:
8. 适配Android28网络请求
- 在res目录下创建名为xml的文件夹,并在文件夹里面创建名为network_security_config的xml文件:
- AndroidManifest配置文件中添加配置:
9. 添加Dagger2
9.0 分析
这里我们需要把NewsInfoTask和MainActivity注入到了Presenter中,把Presenter注入到了MainActivity中。
9.1 Dagger2实现NewsInfoTask单例
- 去掉NewsInfoTask以下代码:
- 新建名为NetTaskModule的Module:
说明:生成NewsInfoTask的实例对象,并用@Singleton修饰。
- 新建名为NetTaskComponent的Component:
说明:
① NetTaskModule 中的方法provideNewsInfoTask用@Singleton修饰,NetTaskComponent也必须用@Singleton修饰。
② NetTaskComponent中不需要指明注入的目标,而需要提供实例对象的时候,可以用“NetTask getNetTask();”这种形式表示,指明返回的是NetTask,返回值很重要。
- 实现NewsInfoTask在App全局单例:
@Singleton可以保证局部单例,即NetTaskComponent下的注入目标中NewsInfoTask的内存地址都是同一个,而一旦创建其他Component并关联NetTaskModule,此时创建出的NewsInfoTask的内存地址就会发生变化,所以保证全局单例我们只能初始化一次Component,而初始化的地方就是Application:
说明:这里通过.builder().build()来获取NetTaskComponent。需要NewsInfoTask只通过NetTaskComponent,就可以保证NewsInfoTask对象的内存地址唯一了。
9.2 Presenter注入MainActivity
- @Inject修饰构造方法
说明:@Inject修饰构造方法意思是告诉Dagger2可以用这个构造方法构建NewsInfoPresenter。只有构造方法上有@Inject注解修饰,NewsInfoPresenter才可以对外提供实例对象。
- NewsInfoContract.View添加setPresenter方法
- NewsInfoPresenter创建setPresenter方法,并用@Inject修饰
说明:@Inject修饰方法的意思是方法注入,这里是把NewsInfoPresenter注入给MainActivity。方法注入是在构造方法后执行的。方法注入需要构造方法使用@Inject注解修饰,不然方法注入无法执行。
- MainActivity中用@Inject修饰变量NewsInfoPresenter:
说明:@Inject修饰变量意思是NewsInfoPresenter需要依赖注入。
- MainActivity实现setPresenter方法
综上:以上几步完成了Persenter注入到MainActivity。
9.3 NewsInfoTask和MainActivity注入到了Presenter
- 创建名为ActivityScoped的自定义Scope:
- 创建NewsInfoModule的Module:
说明:这里是为了将NewsInfoContract.View注入给MainActivity。
- 创建名为MainActivityComponent的Component:
说明:
① dependencies意思是把NetTaskComponent的内容也拿过来注入。
② @ActivityScoped之所以创建自定义Scope是因为如果dependencies中的NetTaskComponent用了@Singleton修饰,这里就不能使用@Singleton修饰了。
- 修改MainActivity完成注入:
说明:因为Presenter需要两个参数,所以这里一句话就把需要的两个参数传入了Presenter。我们看下DaggerMainActivityComponent的源码:
public Builder newsInfoModule(NewsInfoModule newsInfoModule) {this.newsInfoModule = Preconditions.checkNotNull(newsInfoModule);return this;}public Builder netTaskComponent(NetTaskComponent netTaskComponent) {this.netTaskComponent = Preconditions.checkNotNull(netTaskComponent);return this;} 复制代码说明:.newsInfoModule和.netTaskComponent接收Presenter需要的两个参数。然后看build():
public MainActivityComponent build() {if (newsInfoModule == null) {throw new IllegalStateException(NewsInfoModule.class.getCanonicalName() + " must be set");}if (netTaskComponent == null) {throw new IllegalStateException(NetTaskComponent.class.getCanonicalName() + " must be set");}return new DaggerMainActivityComponent(this);} 复制代码说明:这里把build()所在的Build传入了DaggerMainActivityComponent的构造方法,我们看下:
private DaggerMainActivityComponent(Builder builder) {assert builder != null;initialize(builder);} 复制代码说明:再看下initialize方法:
this.provideNewsInfoContractViewProvider =NewsInfoModule_ProvideNewsInfoContractViewFactory.create(builder.newsInfoModule);this.getNetTaskProvider =new Factory<NetTask>() {private final NetTaskComponent netTaskComponent = builder.netTaskComponent;public NetTask get() {return Preconditions.checkNotNull(netTaskComponent.getNetTask(),"Cannot return null from a non-@Nullable component method");}};this.newsInfoPresenterProvider =NewsInfoPresenter_Factory.create(newsInfoPresenterMembersInjector,provideNewsInfoContractViewProvider,getNetTaskProvider); 复制代码说明:newsInfoModule得到provideNewsInfoContractViewProvider,netTaskComponent得到getNetTaskProvider,然后把两者,放入NewsInfoPresenter_Factory.create方法中:
public static Factory<NewsInfoPresenter> create(MembersInjector<NewsInfoPresenter> newsInfoPresenterMembersInjector,Provider<NewsInfoContract.View> viewProvider,Provider<NetTask> netTaskProvider) {return new NewsInfoPresenter_Factory(newsInfoPresenterMembersInjector, viewProvider, netTaskProvider);} 复制代码说明:再看NewsInfoPresenter_Factory
public NewsInfoPresenter_Factory(MembersInjector<NewsInfoPresenter> newsInfoPresenterMembersInjector,Provider<NewsInfoContract.View> viewProvider,Provider<NetTask> netTaskProvider) {assert newsInfoPresenterMembersInjector != null;this.newsInfoPresenterMembersInjector = newsInfoPresenterMembersInjector;assert viewProvider != null;this.viewProvider = viewProvider;assert netTaskProvider != null;this.netTaskProvider = netTaskProvider;} 复制代码说明:用viewProvider封装了NewsInfoContract.View;用netTaskProvider封装了NetTask。他们调用给了get方法:
public NewsInfoPresenter get() {return MembersInjectors.injectMembers(newsInfoPresenterMembersInjector,new NewsInfoPresenter(viewProvider.get(), netTaskProvider.get()));} 复制代码说明:看到这里,你会清晰的看到NetTask和MainActivity注入到了Presenter,而这个get方法何时调用的呢?我们看下inject方法:
public void inject(MainActivity mainActivity) {mainActivityMembersInjector.injectMembers(mainActivity);} 复制代码说明:再接着看injectMembers方法:
public void injectMembers(MainActivity instance) {if (instance == null) {throw new NullPointerException("Cannot inject members into a null reference");}instance.mPresenter = mPresenterProvider.get();} 复制代码说明:mPresenterProvider是谁呢:
private final Provider<NewsInfoPresenter> mPresenterProvider; 复制代码说明:到这里会发现其实inject的目的就是把两个参数赋值给this中的presenter,而赋值离不开new,自然离不开构造方法,而构造方法那里也离不开@Inject。而这也正是Dagger2的原理所在,通过工厂方法把实例对象赋值给注入目标的用@Inject所修饰的成员变量。
10. 实现RetrofitManager单例
- 去除之前实现单例模式的以下代码
- NetTaskModule中添加以下方法:
- NetTaskComponent中添加以下方法:
- 修改Applicaion的代码:
说明:之前的方式需要传入Context,但是NewsInfoTask中并没有Context,所以我们这里修改为static,因为是单例模式,从创建就开始存在直到App应用程序退出,所以不会有内存泄露的情况。
- MainActivity和NewsInfoTask中修改获取NetTaskComponent的代码。
+qq群457848807:。获取以上高清技术思维图,以及相关技术的免费视频学习资料
总结
以上是生活随笔为你收集整理的手把手带你搭建Mvp+Dagger架构的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: PDF编辑器哪个好,如何在PDF中插入图
- 下一篇: Sass 用法指南