手把手带你搭建Mvp+Dagger架构
0. 序言
- 之前寫過一篇名為"看完不會(huì)寫MVP架構(gòu)我跪搓板"的博文,收到一些閱讀者的建議,希望能夠?qū)xjava的生命周期進(jìn)行管理以及添加Dagger到MVP架構(gòu)中,所以今天抽一點(diǎn)時(shí)間寫一篇拿來即可于實(shí)戰(zhàn)的Demo。
1. 博文目錄
添加依賴
創(chuàng)建項(xiàng)目基本目錄
實(shí)現(xiàn)Model
定義契約接口NewsInfoContract
實(shí)現(xiàn)Presenter
實(shí)現(xiàn)View
補(bǔ)充網(wǎng)絡(luò)配置代碼
適配Android28網(wǎng)絡(luò)請(qǐng)求
添加Dagger2
實(shí)現(xiàn)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' 復(fù)制代碼3. 創(chuàng)建項(xiàng)目基本目錄
4. 實(shí)現(xiàn)Model
- 創(chuàng)建實(shí)體類NewsInfo:
- 定義獲取網(wǎng)絡(luò)數(shù)據(jù)的接口類NetTask:
- 編寫NetTask的實(shí)現(xiàn)類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();} } 復(fù)制代碼7. 實(shí)現(xiàn)Presenter
- 編寫NewsInfoContract.Presenter接口的實(shí)現(xiàn)類NewsInfoPresenter:
6. 實(shí)現(xiàn)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();}} 復(fù)制代碼7. 補(bǔ)充網(wǎng)絡(luò)配置代碼
- Retrofit 管理類:
- 網(wǎng)絡(luò)請(qǐng)求接口服務(wù)類NewsService:
8. 適配Android28網(wǎng)絡(luò)請(qǐng)求
- 在res目錄下創(chuàng)建名為xml的文件夾,并在文件夾里面創(chuàng)建名為network_security_config的xml文件:
- AndroidManifest配置文件中添加配置:
9. 添加Dagger2
9.0 分析
這里我們需要把NewsInfoTask和MainActivity注入到了Presenter中,把Presenter注入到了MainActivity中。
9.1 Dagger2實(shí)現(xiàn)NewsInfoTask單例
- 去掉NewsInfoTask以下代碼:
- 新建名為NetTaskModule的Module:
說明:生成NewsInfoTask的實(shí)例對(duì)象,并用@Singleton修飾。
- 新建名為NetTaskComponent的Component:
說明:
① NetTaskModule 中的方法provideNewsInfoTask用@Singleton修飾,NetTaskComponent也必須用@Singleton修飾。
② NetTaskComponent中不需要指明注入的目標(biāo),而需要提供實(shí)例對(duì)象的時(shí)候,可以用“NetTask getNetTask();”這種形式表示,指明返回的是NetTask,返回值很重要。
- 實(shí)現(xiàn)NewsInfoTask在App全局單例:
@Singleton可以保證局部單例,即NetTaskComponent下的注入目標(biāo)中NewsInfoTask的內(nèi)存地址都是同一個(gè),而一旦創(chuàng)建其他Component并關(guān)聯(lián)NetTaskModule,此時(shí)創(chuàng)建出的NewsInfoTask的內(nèi)存地址就會(huì)發(fā)生變化,所以保證全局單例我們只能初始化一次Component,而初始化的地方就是Application:
說明:這里通過.builder().build()來獲取NetTaskComponent。需要NewsInfoTask只通過NetTaskComponent,就可以保證NewsInfoTask對(duì)象的內(nèi)存地址唯一了。
9.2 Presenter注入MainActivity
- @Inject修飾構(gòu)造方法
說明:@Inject修飾構(gòu)造方法意思是告訴Dagger2可以用這個(gè)構(gòu)造方法構(gòu)建NewsInfoPresenter。只有構(gòu)造方法上有@Inject注解修飾,NewsInfoPresenter才可以對(duì)外提供實(shí)例對(duì)象。
- NewsInfoContract.View添加setPresenter方法
- NewsInfoPresenter創(chuàng)建setPresenter方法,并用@Inject修飾
說明:@Inject修飾方法的意思是方法注入,這里是把NewsInfoPresenter注入給MainActivity。方法注入是在構(gòu)造方法后執(zhí)行的。方法注入需要構(gòu)造方法使用@Inject注解修飾,不然方法注入無法執(zhí)行。
- MainActivity中用@Inject修飾變量NewsInfoPresenter:
說明:@Inject修飾變量意思是NewsInfoPresenter需要依賴注入。
- MainActivity實(shí)現(xiàn)setPresenter方法
綜上:以上幾步完成了Persenter注入到MainActivity。
9.3 NewsInfoTask和MainActivity注入到了Presenter
- 創(chuàng)建名為ActivityScoped的自定義Scope:
- 創(chuàng)建NewsInfoModule的Module:
說明:這里是為了將NewsInfoContract.View注入給MainActivity。
- 創(chuàng)建名為MainActivityComponent的Component:
說明:
① dependencies意思是把NetTaskComponent的內(nèi)容也拿過來注入。
② @ActivityScoped之所以創(chuàng)建自定義Scope是因?yàn)槿绻鹍ependencies中的NetTaskComponent用了@Singleton修飾,這里就不能使用@Singleton修飾了。
- 修改MainActivity完成注入:
說明:因?yàn)镻resenter需要兩個(gè)參數(shù),所以這里一句話就把需要的兩個(gè)參數(shù)傳入了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;} 復(fù)制代碼說明:.newsInfoModule和.netTaskComponent接收Presenter需要的兩個(gè)參數(shù)。然后看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);} 復(fù)制代碼說明:這里把build()所在的Build傳入了DaggerMainActivityComponent的構(gòu)造方法,我們看下:
private DaggerMainActivityComponent(Builder builder) {assert builder != null;initialize(builder);} 復(fù)制代碼說明:再看下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); 復(fù)制代碼說明: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);} 復(fù)制代碼說明:再看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;} 復(fù)制代碼說明:用viewProvider封裝了NewsInfoContract.View;用netTaskProvider封裝了NetTask。他們調(diào)用給了get方法:
public NewsInfoPresenter get() {return MembersInjectors.injectMembers(newsInfoPresenterMembersInjector,new NewsInfoPresenter(viewProvider.get(), netTaskProvider.get()));} 復(fù)制代碼說明:看到這里,你會(huì)清晰的看到NetTask和MainActivity注入到了Presenter,而這個(gè)get方法何時(shí)調(diào)用的呢?我們看下inject方法:
public void inject(MainActivity mainActivity) {mainActivityMembersInjector.injectMembers(mainActivity);} 復(fù)制代碼說明:再接著看injectMembers方法:
public void injectMembers(MainActivity instance) {if (instance == null) {throw new NullPointerException("Cannot inject members into a null reference");}instance.mPresenter = mPresenterProvider.get();} 復(fù)制代碼說明:mPresenterProvider是誰呢:
private final Provider<NewsInfoPresenter> mPresenterProvider; 復(fù)制代碼說明:到這里會(huì)發(fā)現(xiàn)其實(shí)inject的目的就是把兩個(gè)參數(shù)賦值給this中的presenter,而賦值離不開new,自然離不開構(gòu)造方法,而構(gòu)造方法那里也離不開@Inject。而這也正是Dagger2的原理所在,通過工廠方法把實(shí)例對(duì)象賦值給注入目標(biāo)的用@Inject所修飾的成員變量。
10. 實(shí)現(xiàn)RetrofitManager單例
- 去除之前實(shí)現(xiàn)單例模式的以下代碼
- NetTaskModule中添加以下方法:
- NetTaskComponent中添加以下方法:
- 修改Applicaion的代碼:
說明:之前的方式需要傳入Context,但是NewsInfoTask中并沒有Context,所以我們這里修改為static,因?yàn)槭菃卫J?#xff0c;從創(chuàng)建就開始存在直到App應(yīng)用程序退出,所以不會(huì)有內(nèi)存泄露的情況。
- MainActivity和NewsInfoTask中修改獲取NetTaskComponent的代碼。
+qq群457848807:。獲取以上高清技術(shù)思維圖,以及相關(guān)技術(shù)的免費(fèi)視頻學(xué)習(xí)資料
總結(jié)
以上是生活随笔為你收集整理的手把手带你搭建Mvp+Dagger架构的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PDF编辑器哪个好,如何在PDF中插入图
- 下一篇: Sass 用法指南