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架构相关推荐

  1. vaex 处理海量数据_核心业务“瘦身”进行时!手把手带你搭建海量数据实时处理架构...

    01 背景在线交易服务平台目的是减轻核心系统计算压力和核心性能负荷压力,通过该平台可以将核心系统的交易数据实时捕获.实时计算加工.计算结果保存于SequoiaDB中.并能实时的为用户提供在线交易查询服 ...

  2. 从 0 开始手把手带你搭建一套规范的 Vue3.x 项目工程环境

    Vue3 跟 Vite 正式版发布有很长一段时间了,生态圈也渐渐丰富起来,作者已在多个项目中使用,总结一下:就是快!也不用担心稳定性问题,开发体验真不是一般好!还没尝试的同学可以从本文开始学习,从 0 ...

  3. 手把手带你搭建个人博客系统(一)

    ⭐️前言⭐️ 该web开发系统涉及到的知识: Java基础 MySQL数据库 JDBC技术 前端三件套(HTML+CSS+JavaScript) Servlet 使用到的开发工具: idea vsco ...

  4. 手把手带大家搭建一个java个人网站(腾讯云为例)

    大家好,我是鸟哥.一个半路出家的程序员. 这次真是学妹要的!前几天鸟哥以腾讯云为例给大家分享了一篇如何搭建服务器的文章--手把手带大家搭建一台服务器(腾讯云为例),文章结尾表示过几天带大家搭建一个网站 ...

  5. 毕业设计无从下手?四个步骤手把手带你搭建一个后台微服务架构

    更多精彩文件点击访问:https://blog.csdn.net/weixin_45692705?spm=1011.2124.3001.5343 教程目录 后台技术栈 准备工作 一. 创建父工程 二. ...

  6. mysql主从架构搭建_技术 | 手把手教你搭建MySQL主从架构

    1 什么是MySQL的复制 MySQL的主从复制可以实现将数据从一台数据库服务器(master)复制到一台或多台数据库服务器(slave)上,进而可以保证数据有多份冗余. 默认情况下,属于异步复制,所 ...

  7. linux配置usb主从_技术 | 手把手教你搭建MySQL主从架构

    黑马程序员 微信号:heiniu526 传智播客旗下互联网资讯,学习资源免费分享平台 1 什么是MySQL的复制 MySQL的主从复制可以实现将数据从一台数据库服务器(master)复制到一台或多台数 ...

  8. SSM框架练手项目【虎牙个人博客】手把手带你搭建自己的个人博客

    今天分享给大家的是个人博客项目,对Spring+SpringMVC+MyBatis三大经典开发框架的综合应用,提高大家对这三大框架的的综合实战能力,加深对这三大框架的理解. 项目分为前台项目和后台项目 ...

  9. 手把手带大家搭建一台服务器(腾讯云为例)

    今天带大家入门如何搭建服务器,主要是面向小白读者.先说好,我自己也不是专业做后端的,只不过平时爱折腾点项目玩玩,所以有点小经验,本文就是基于这点小经验讲解的,如有不当之处还请谅解. 一.什么是服务器? ...

最新文章

  1. MathType在手,公式不求人!
  2. Java基础概念(一)
  3. oracle删除本地文件权限,使用 UNIX 权限保护文件
  4. python交叉验证函数_python – 在sklearn中使用交叉验证和AUC-ROC作为逻辑回归模型...
  5. Clob类型转换为String
  6. Qt工作笔记-把QTableWidget数据存为XML,启动时加载XML
  7. X大佬:建议被降级降薪员工主动辞职,网友炸了
  8. python编程(webpy + gunicorn + nginx部署)
  9. Python将彩色图像转为灰度图像
  10. 学习廖雪峰Git教程后对Git知识点的一些总结(4)
  11. [树莓派][GPIO][风扇][断点直播]树莓派4B加装风扇并实现风力和CPU温度控制
  12. SHELL命令 -- 查看显卡型号
  13. 下列python语句的输出结果是_下列Python语句的输出结果是 __________ 。
  14. “值得”关注公司:我们应该向优衣库学习什么?
  15. Android 常用 RGB值以及中英文名称
  16. ML-czy的小组任务2
  17. R语言如何合并Excel多行的重复数据
  18. Python出现Non-ASCII character '\xe6' in file错误解决方法(pycharm)
  19. Extract - 凤凰牌老熊-现代支付系统设计
  20. 高数笔记基础篇(更完)

热门文章

  1. 4.openstack之mitaka搭建glance镜像服务
  2. 移动端页面0.5px border的实现
  3. 【Python3】POP3协议收邮件
  4. NHibernate学习--初识NHibernate
  5. 图论算法(三)--最短路径 的Bellman-Flod [ 带负权值图 ] 的解法(JAVA )
  6. Win10强制更新怎么关闭 彻底禁止Windows自动更新
  7. vscode怎样导入数据_【Python开发】用VSCode+Jupyter notebook 编写 Python
  8. 三星java3倍拍照手机_全世界拍照最强的两款手机,一个是三星,一个是它
  9. mysql shell 所有表_删除mysql数据库中所有表的shell脚本
  10. 浏览器快捷键_浏览器快捷键,让你事半功倍