欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

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

发布时间:2025/3/15 编程问答 33 豆豆
生活随笔 收集整理的这篇文章主要介绍了 手把手带你搭建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:
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;...}} } 复制代码
  • 定义获取网络数据的接口类NetTask:
public interface NetTask {void execute(LifecycleProvider lifecycleProvider, String type, LoadTasksCallBack callBack); } 复制代码public interface LoadTasksCallBack {void OnSuccess(NewsInfo newsInfo);void OnStart();void onFailed();void onFinish(); } 复制代码
  • 编写NetTask的实现类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();}});} } 复制代码

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:
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();} } 复制代码

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;@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();}} 复制代码

7. 补充网络配置代码

  • 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;} } 复制代码
  • 网络请求接口服务类NewsService:
public interface NewsService {@GET("toutiao/index")Observable<NewsInfo> getNewsInfo(@Query("type") String type, @Query("key")String key); } 复制代码

8. 适配Android28网络请求

  • 在res目录下创建名为xml的文件夹,并在文件夹里面创建名为network_security_config的xml文件:
<?xml version="1.0" encoding="utf-8"?> <network-security-config><base-config cleartextTrafficPermitted="true" /> </network-security-config> 复制代码
  • AndroidManifest配置文件中添加配置:
android:networkSecurityConfig="@xml/network_security_config" 复制代码

9. 添加Dagger2

9.0 分析

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

9.1 Dagger2实现NewsInfoTask单例

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

说明:生成NewsInfoTask的实例对象,并用@Singleton修饰。

  • 新建名为NetTaskComponent的Component:
@Singleton @Component(modules = NetTaskModule.class) public interface NetTaskComponent {NetTask getNetTask(); } 复制代码

说明:
① NetTaskModule 中的方法provideNewsInfoTask用@Singleton修饰,NetTaskComponent也必须用@Singleton修饰。
② NetTaskComponent中不需要指明注入的目标,而需要提供实例对象的时候,可以用“NetTask getNetTask();”这种形式表示,指明返回的是NetTask,返回值很重要。

  • 实现NewsInfoTask在App全局单例:
    @Singleton可以保证局部单例,即NetTaskComponent下的注入目标中NewsInfoTask的内存地址都是同一个,而一旦创建其他Component并关联NetTaskModule,此时创建出的NewsInfoTask的内存地址就会发生变化,所以保证全局单例我们只能初始化一次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;} } 复制代码

说明:这里通过.builder().build()来获取NetTaskComponent。需要NewsInfoTask只通过NetTaskComponent,就可以保证NewsInfoTask对象的内存地址唯一了。

9.2 Presenter注入MainActivity

  • @Inject修饰构造方法
@Injectpublic NewsInfoPresenter(NewsInfoContract.View view,NetTask netTask) {mView = view;mNetTask = netTask;} 复制代码

说明:@Inject修饰构造方法意思是告诉Dagger2可以用这个构造方法构建NewsInfoPresenter。只有构造方法上有@Inject注解修饰,NewsInfoPresenter才可以对外提供实例对象。

  • 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);} } 复制代码
  • NewsInfoPresenter创建setPresenter方法,并用@Inject修饰
@Injectvoid setPresenter(){mView.setPresenter(this);} 复制代码

说明:@Inject修饰方法的意思是方法注入,这里是把NewsInfoPresenter注入给MainActivity。方法注入是在构造方法后执行的。方法注入需要构造方法使用@Inject注解修饰,不然方法注入无法执行。

  • MainActivity中用@Inject修饰变量NewsInfoPresenter:
@InjectNewsInfoPresenter mPresenter; 复制代码

说明:@Inject修饰变量意思是NewsInfoPresenter需要依赖注入。

  • MainActivity实现setPresenter方法
@Overridepublic void setPresenter(NewsInfoPresenter presenter) {mPresenter = presenter;} 复制代码

综上:以上几步完成了Persenter注入到MainActivity。

9.3 NewsInfoTask和MainActivity注入到了Presenter

  • 创建名为ActivityScoped的自定义Scope:
@Scope @Documented @Retention(RUNTIME) public @interface ActivityScoped { } 复制代码
  • 创建NewsInfoModule的Module:
@Module public class NewsInfoModule {private NewsInfoContract.View mView;public NewsInfoModule(NewsInfoContract.View view) {mView = view;}@Providespublic NewsInfoContract.View provideNewsInfoContractView() {return mView;}} 复制代码

说明:这里是为了将NewsInfoContract.View注入给MainActivity。

  • 创建名为MainActivityComponent的Component:
@ActivityScoped @Component(modules = NewsInfoModule.class,dependencies =NetTaskComponent.class) public interface MainActivityComponent {void inject(MainActivity mainActivity); } 复制代码

说明:
① dependencies意思是把NetTaskComponent的内容也拿过来注入。
② @ActivityScoped之所以创建自定义Scope是因为如果dependencies中的NetTaskComponent用了@Singleton修饰,这里就不能使用@Singleton修饰了。

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

说明:因为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;@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); 复制代码

说明: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方法:

@Overridepublic NewsInfoPresenter get() {return MembersInjectors.injectMembers(newsInfoPresenterMembersInjector,new NewsInfoPresenter(viewProvider.get(), netTaskProvider.get()));} 复制代码

说明:看到这里,你会清晰的看到NetTask和MainActivity注入到了Presenter,而这个get方法何时调用的呢?我们看下inject方法:

@Overridepublic void inject(MainActivity mainActivity) {mainActivityMembersInjector.injectMembers(mainActivity);} 复制代码

说明:再接着看injectMembers方法:

@Overridepublic 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单例

  • 去除之前实现单例模式的以下代码
private RetrofitManager() {}public static RetrofitManager getInstance() {return RetrofitManagerHolder.sInstance;}private static class RetrofitManagerHolder {private static final RetrofitManager sInstance = new RetrofitManager();} 复制代码
  • NetTaskModule中添加以下方法:
@Singleton@Providespublic RetrofitManager provideRetrofitManager(){return new RetrofitManager();} 复制代码
  • NetTaskComponent中添加以下方法:
@Singleton @Component(modules = NetTaskModule.class) public interface NetTaskComponent {NetTask getNetTask();RetrofitManager getRetrofitManager(); } 复制代码
  • 修改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;} } 复制代码

说明:之前的方式需要传入Context,但是NewsInfoTask中并没有Context,所以我们这里修改为static,因为是单例模式,从创建就开始存在直到App应用程序退出,所以不会有内存泄露的情况。

  • MainActivity和NewsInfoTask中修改获取NetTaskComponent的代码。

+qq群457848807:。获取以上高清技术思维图,以及相关技术的免费视频学习资料


总结

以上是生活随笔为你收集整理的手把手带你搭建Mvp+Dagger架构的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。