日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

手把手带你搭建Mvp+Dagger架构

發(fā)布時(shí)間:2025/3/15 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 手把手带你搭建Mvp+Dagger架构 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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:
public class NewsInfo {private String reason;private ResultBean result;...public static class ResultBean {private String stat;private List<DataBean> data;...public static class DataBean {private String uniquekey;private String title;private String date;private String category;private String author_name;private String url;private String thumbnail_pic_s;private String thumbnail_pic_s02;private String thumbnail_pic_s03;...}} } 復(fù)制代碼
  • 定義獲取網(wǎng)絡(luò)數(shù)據(jù)的接口類NetTask:
public interface NetTask {void execute(LifecycleProvider lifecycleProvider, String type, LoadTasksCallBack callBack); } 復(fù)制代碼public interface LoadTasksCallBack {void OnSuccess(NewsInfo newsInfo);void OnStart();void onFailed();void onFinish(); } 復(fù)制代碼
  • 編寫NetTask的實(shí)現(xiàn)類NewsInfoTask:
public class NewsInfoTask implements NetTask {private Disposable mDisposable;private NewsInfoTask() {}public static NewsInfoTask getInstance() {return NewsInfoTaskHolder.sNewsInfoFask;}private static class NewsInfoTaskHolder {private static final NewsInfoTask sNewsInfoFask = new NewsInfoTask();}@Overridepublic void execute(LifecycleProvider lifecycleProvider,String type, final LoadTasksCallBack callBack) {RetrofitManager.getInstance().getRetrofit(Constant.BASEURL).create(NewsService.class).getNewsInfo(type, BuildConfig.NewKey).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).compose(lifecycleProvider.<Long>bindUntilEvent(Lifecycle.Event.ON_DESTROY)).subscribe(new Observer<NewsInfo>() {@Overridepublic void onSubscribe(Disposable disposable) {mDisposable= disposable;callBack.OnStart();}@Overridepublic void onNext(NewsInfo newsInfo) {callBack.OnSuccess(newsInfo);}@Overridepublic void onError(Throwable e) {callBack.onFailed();}@Overridepublic void onComplete() {callBack.onFinish();mDisposable.dispose();}});} } 復(fù)制代碼

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:
public class NewsInfoPresenter implements NewsInfoContract.Presenter,LoadTasksCallBack {private NetTask mNetTask;private NewsInfoContract.View mView;public NewsInfoPresenter(NetTask netTask,NewsInfoContract.View view) {mNetTask = netTask;mView = view;}@Overridepublic void getNewsInfo(LifecycleProvider lifecycleProvider, String type) {mNetTask.execute(lifecycleProvider,type,this);}@Overridepublic void OnSuccess(NewsInfo newsInfo) {mView.setNewsInfo(newsInfo);}@Overridepublic void OnStart() {mView.showLoading();}@Overridepublic void onFailed() {mView.showError();mView.hideLoading();}@Overridepublic void onFinish() {mView.hideLoading();} } 復(fù)制代碼

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;@Overrideprotected 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);});}@Overridepublic void setNewsInfo(NewsInfo newsInfo) {if (newsInfo != null &amp;&amp; newsInfo.getResult() != null &amp;&amp; newsInfo.getResult().getData() != null) {mNew_Content.setText(newsInfo.getResult().getData().get(0).getTitle());}}@Overridepublic void showLoading() {mDialog.show();}@Overridepublic void hideLoading() {if (mDialog.isShowing())mDialog.dismiss();}@Overridepublic void showError() {Toast.makeText(this, R.string.toast_net_tip, Toast.LENGTH_SHORT).show();}} 復(fù)制代碼

7. 補(bǔ)充網(wǎng)絡(luò)配置代碼

  • Retrofit 管理類:
public class RetrofitManager {private static Retrofit sRetrofit = null;private static String sUrl = "";private static final int TIMEOUT = 20;private RetrofitManager() {}public static RetrofitManager getInstance() {return RetrofitManagerHolder.sInstance;}private static class RetrofitManagerHolder {private static final RetrofitManager sInstance = new RetrofitManager();}public Retrofit getRetrofit(String baseUrl) {sUrl = baseUrl;if (sRetrofit == null) {return create();} else {return sRetrofit;}}private Retrofit create() {HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();if (BuildConfig.DEBUG) {loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);} else {loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BASIC);}OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(loggingInterceptor).connectTimeout(TIMEOUT,TimeUnit.SECONDS).readTimeout(TIMEOUT, TimeUnit.SECONDS).writeTimeout(TIMEOUT, TimeUnit.SECONDS).retryOnConnectionFailure(true).build();sRetrofit = new Retrofit.Builder().baseUrl(sUrl).addConverterFactory(GsonConverterFactory.create()).addCallAdapterFactory(RxJava2CallAdapterFactory.create()).client(okHttpClient).build();return sRetrofit;} } 復(fù)制代碼
  • 網(wǎng)絡(luò)請(qǐng)求接口服務(wù)類NewsService:
public interface NewsService {@GET("toutiao/index")Observable<NewsInfo> getNewsInfo(@Query("type") String type, @Query("key")String key); } 復(fù)制代碼

8. 適配Android28網(wǎng)絡(luò)請(qǐng)求

  • 在res目錄下創(chuàng)建名為xml的文件夾,并在文件夾里面創(chuàng)建名為network_security_config的xml文件:
<?xml version="1.0" encoding="utf-8"?> <network-security-config><base-config cleartextTrafficPermitted="true" /> </network-security-config> 復(fù)制代碼
  • AndroidManifest配置文件中添加配置:
android:networkSecurityConfig="@xml/network_security_config" 復(fù)制代碼

9. 添加Dagger2

9.0 分析

這里我們需要把NewsInfoTask和MainActivity注入到了Presenter中,把Presenter注入到了MainActivity中。

9.1 Dagger2實(shí)現(xiàn)NewsInfoTask單例

  • 去掉NewsInfoTask以下代碼:
private NewsInfoTask() {}public static NewsInfoTask getInstance() {return NewsInfoTaskHolder.sNewsInfoFask;}private static class NewsInfoTaskHolder {private static final NewsInfoTask sNewsInfoFask = new NewsInfoTask();} 復(fù)制代碼
  • 新建名為NetTaskModule的Module:
@Module public class NetTaskModule {@Singleton@Providespublic NetTask provideNewsInfoTask(){return new NewsInfoTask();} } 復(fù)制代碼

說明:生成NewsInfoTask的實(shí)例對(duì)象,并用@Singleton修飾。

  • 新建名為NetTaskComponent的Component:
@Singleton @Component(modules = NetTaskModule.class) public interface NetTaskComponent {NetTask getNetTask(); } 復(fù)制代碼

說明:
① 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:
public class App extends Application {private NetTaskComponent mNetTaskComponent;@Overridepublic void onCreate() {super.onCreate();mNetTaskComponent = DaggerNetTaskComponent.builder().build();}public static App get(Context context){return (App)context.getApplicationContext();}public NetTaskComponent getNetTaskComponent() {return mNetTaskComponent;} } 復(fù)制代碼

說明:這里通過.builder().build()來獲取NetTaskComponent。需要NewsInfoTask只通過NetTaskComponent,就可以保證NewsInfoTask對(duì)象的內(nèi)存地址唯一了。

9.2 Presenter注入MainActivity

  • @Inject修飾構(gòu)造方法
@Injectpublic NewsInfoPresenter(NewsInfoContract.View view,NetTask netTask) {mView = view;mNetTask = netTask;} 復(fù)制代碼

說明:@Inject修飾構(gòu)造方法意思是告訴Dagger2可以用這個(gè)構(gòu)造方法構(gòu)建NewsInfoPresenter。只有構(gòu)造方法上有@Inject注解修飾,NewsInfoPresenter才可以對(duì)外提供實(shí)例對(duì)象。

  • NewsInfoContract.View添加setPresenter方法
public interface NewsInfoContract {interface Presenter{void getNewsInfo(LifecycleProvider lifecycleProvider, String type);}interface View {void setNewsInfo(NewsInfo newsInfo);void showLoading();void hideLoading();void showError();void setPresenter(NewsInfoPresenter presenter);} } 復(fù)制代碼
  • NewsInfoPresenter創(chuàng)建setPresenter方法,并用@Inject修飾
@Injectvoid setPresenter(){mView.setPresenter(this);} 復(fù)制代碼

說明:@Inject修飾方法的意思是方法注入,這里是把NewsInfoPresenter注入給MainActivity。方法注入是在構(gòu)造方法后執(zhí)行的。方法注入需要構(gòu)造方法使用@Inject注解修飾,不然方法注入無法執(zhí)行。

  • MainActivity中用@Inject修飾變量NewsInfoPresenter:
@InjectNewsInfoPresenter mPresenter; 復(fù)制代碼

說明:@Inject修飾變量意思是NewsInfoPresenter需要依賴注入。

  • MainActivity實(shí)現(xiàn)setPresenter方法
@Overridepublic void setPresenter(NewsInfoPresenter presenter) {mPresenter = presenter;} 復(fù)制代碼

綜上:以上幾步完成了Persenter注入到MainActivity。

9.3 NewsInfoTask和MainActivity注入到了Presenter

  • 創(chuàng)建名為ActivityScoped的自定義Scope:
@Scope @Documented @Retention(RUNTIME) public @interface ActivityScoped { } 復(fù)制代碼
  • 創(chuàng)建NewsInfoModule的Module:
@Module public class NewsInfoModule {private NewsInfoContract.View mView;public NewsInfoModule(NewsInfoContract.View view) {mView = view;}@Providespublic NewsInfoContract.View provideNewsInfoContractView() {return mView;}} 復(fù)制代碼

說明:這里是為了將NewsInfoContract.View注入給MainActivity。

  • 創(chuàng)建名為MainActivityComponent的Component:
@ActivityScoped @Component(modules = NewsInfoModule.class,dependencies =NetTaskComponent.class) public interface MainActivityComponent {void inject(MainActivity mainActivity); } 復(fù)制代碼

說明:
① dependencies意思是把NetTaskComponent的內(nèi)容也拿過來注入。
② @ActivityScoped之所以創(chuàng)建自定義Scope是因?yàn)槿绻鹍ependencies中的NetTaskComponent用了@Singleton修飾,這里就不能使用@Singleton修飾了。

  • 修改MainActivity完成注入:
DaggerMainActivityComponent.builder().newsInfoModule(new NewsInfoModule(this)).netTaskComponent(App.get(this).getNetTaskComponent()).build().inject(this); 復(fù)制代碼

說明:因?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;@Overridepublic 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方法:

@Overridepublic NewsInfoPresenter get() {return MembersInjectors.injectMembers(newsInfoPresenterMembersInjector,new NewsInfoPresenter(viewProvider.get(), netTaskProvider.get()));} 復(fù)制代碼

說明:看到這里,你會(huì)清晰的看到NetTask和MainActivity注入到了Presenter,而這個(gè)get方法何時(shí)調(diào)用的呢?我們看下inject方法:

@Overridepublic void inject(MainActivity mainActivity) {mainActivityMembersInjector.injectMembers(mainActivity);} 復(fù)制代碼

說明:再接著看injectMembers方法:

@Overridepublic 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)單例模式的以下代碼
private RetrofitManager() {}public static RetrofitManager getInstance() {return RetrofitManagerHolder.sInstance;}private static class RetrofitManagerHolder {private static final RetrofitManager sInstance = new RetrofitManager();} 復(fù)制代碼
  • NetTaskModule中添加以下方法:
@Singleton@Providespublic RetrofitManager provideRetrofitManager(){return new RetrofitManager();} 復(fù)制代碼
  • NetTaskComponent中添加以下方法:
@Singleton @Component(modules = NetTaskModule.class) public interface NetTaskComponent {NetTask getNetTask();RetrofitManager getRetrofitManager(); } 復(fù)制代碼
  • 修改Applicaion的代碼:
public class App extends Application {private static NetTaskComponent mNetTaskComponent;@Overridepublic void onCreate() {super.onCreate();mNetTaskComponent = DaggerNetTaskComponent.builder().build();}public static NetTaskComponent getNetTaskComponent() {return mNetTaskComponent;} } 復(fù)制代碼

說明:之前的方式需要傳入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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。