Dragger2与MVP与Retrofit实战

2024-06-23 04:08
文章标签 实战 retrofit mvp dragger2

本文主要是介绍Dragger2与MVP与Retrofit实战,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  • 1:MVP模块

    • 1.1:MVP与MVC区别,有何应用场景

    • 1.2如何写mvp

  • 2:dragger2框架

    • 2.1:为什么要用dragger2?

    • 2.2:深入解析dragger2?

    • 2.3:dragger2的使用

  • 3:retrofit的使用

MVP模块

MVP与MVC区别,有何应用场景

      在我们传统的mvc开发中经常会遇到M(javabean),V(layout,activity),C(activity),这里activity里会有大量的界面操作,业务逻辑操作。随着业务的拓展,后期如果修改一个地方,后续的修改非常的庞大,所以我们想着如果可以就把业务逻辑操作单独的放到另外一个地方,这样不仅美观上,后期拓展上,而且重复利用率上也能得到提升,mvp恰巧可以解决这个问题,我们可以把繁杂的业务逻辑放到p层开发,这样不仅是activity层显得不那么臃肿,而且不同的activity,fragment都可以使用重复的逻辑操作,减少相同逻辑的代码量。

如何写mvp

      下面看一个简单的登录模块。
      如果用mvc做的话

 mUsername = (EditText) findViewById(R.id.username);mPassword = (EditText) findViewById(R.id.password);dialog = new ProgressDialog(this);}/*** 按钮点击** @param view*/public void login(View view) {String username = mUsername.getText().toString();String password = mPassword.getText().toString();boolean checkUserInfo = checkUserInfo(username,password);if(checkUserInfo){dialog.show();final User user=new User();user.username=username;user.password=password;new Thread(){@Overridepublic void run() {UserLoginNet net=new UserLoginNet();if(net.sendUserLoginInfo(user)){// 登陆成功success();}else{//登陆失败failed();}}}.start();}else{Toast.makeText(MainActivity.this, R.string.check_info, Toast.LENGTH_SHORT).show();}}/*** 检验用户输入——界面相关逻辑处理* @param username* @param password* @return*/private boolean checkUserInfo(String username, String password) {if(TextUtils.isEmpty(username)||TextUtils.isEmpty(password)){return false;}return true;}/*** 登陆成功*/public void success(){runOnUiThread(new Runnable() {@Overridepublic void run() {// 登陆成功dialog.dismiss();Toast.makeText(MainActivity.this, getString(R.string.welcome)+mUsername.getText().toString(), Toast.LENGTH_SHORT).show();}});}/*** 登陆失败*/public void failed(){runOnUiThread(new Runnable() {@Overridepublic void run() {// 登陆失败dialog.dismiss();Toast.makeText(MainActivity.this, R.string.login_fail, Toast.LENGTH_SHORT).show();}});}

可以看出这里面业务逻辑代码和界面操作都融合在一起,那么我们有没有方式把业务逻辑抽取到p层,不仅美观上,后期拓展上,而且重复利用率上也能得到提升。

 /*** 钮点击** @param view*/public void login(View view) {String username = mUsername.getText().toString();String password = mPassword.getText().toString();boolean checkUserInfo = checkUserInfo(username, password);if (checkUserInfo) {dialog.show();presenter.login(username, password);} else {Toast.makeText(MainActivity.this, "用户名或密码不能为空", Toast.LENGTH_SHORT).show();}}/*** 检验用户输入——界面相关逻辑处理** @param username* @param password* @return*/private boolean checkUserInfo(String username, String password) {if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {return false;}return true;}/*** 登陆成功*/public void success() {runOnUiThread(new Runnable() {@Overridepublic void run() {// 登陆成功dialog.dismiss();Toast.makeText(MainActivity.this, "欢迎回来:" + mUsername.getText().toString(), Toast.LENGTH_SHORT).show();}});}/*** 登陆失败*/public void failed() {runOnUiThread(new Runnable() {@Overridepublic void run() {// 登陆失败dialog.dismiss();Toast.makeText(MainActivity.this, "用户名或密码输入有误", Toast.LENGTH_SHORT).show();}});}

在P层做业务逻辑处理

public MainActivityPresenter(MainActivity activity) {this.activity = activity;// 网络访问:// 第一步:创建Builder,指定baseUrl和数据解析工具Retrofit.Builder builder = new Retrofit.Builder();builder.baseUrl(Constant.BASEURL);builder.addConverterFactory(GsonConverterFactory.create());// Gson解析// 第二步:创建RetrofitRetrofit retrofit = builder.build();// 第三步:指定请求方式(get或post)和参数,通过定以接口的形式指定// 第三步通过接口com.itheima.mvp.presenter.api.ResponseInfoAPI// 第四步:将Retrofit和第三步的联网参数联系起来api = retrofit.create(ResponseInfoAPI.class);}/*** 用户登陆** @param username* @param password*/public void login(String username, String password) {Call<ResponseInfo> call = api.login(username, password);call.enqueue(new Callback<ResponseInfo>() {@Overridepublic void onResponse(Call<ResponseInfo> call, Response<ResponseInfo> response) {// 处理服务器回复内容if (response != null) {if (response.isSuccessful()) {// 登陆成功activity.success();}else{// 错误提示}}else{// 错误提示onFailure(call,new RuntimeException("服务器忙请稍后重试"));}}@Overridepublic void onFailure(Call<ResponseInfo> call, Throwable t) {// 异常处理//登陆失败activity.failed();}});}public void login1(String username, String password) {final User user = new User();user.username = username;user.password = password;new Thread() {@Overridepublic void run() {UserLoginNet net = new UserLoginNet();if (net.sendUserLoginInfo(user)) {// 登陆成功activity.success();} else {//登陆失败activity.failed();}}}.start();}

在Activity里面只需要拿到P层类的实例,调用login方法即刻
那么我们如何拿到Presenter实例?通过Presenter p=new Presenter();
答案肯定可以,但是不好,为什么?看下面详解为什么要用Dragger2。

dragger2框架

为什么要用dragger2

     mvp设计模式中我们的activity层中需要拿到p层的对象,那么在开发中有可能我们很多activity或者fragment都可能需要拿到这个p层对象的实例,这样就存在一个耦合度的问题,耦合度太高,假如我们p层类的构造发生变化我们要在很多地方都得进行修改,这就是耦合度太高的弊端,如何解决这个问题?这种思想不仅在MVP会遇到,在编程中解耦是亘古不变的话题,那么我们思考可以通过哪些方式解决这个耦合度的问题?

1:利用配置文件,使用反射的方式获取到需要加载的对象
譬如,清淡文件中的Mainactivity加载的时候,安卓就是要通过配置文件中packagename+class反射的方式加载Mainactivity对象。
2:设计模式,单例,工厂,观察者。
譬如通过单例获取到对象,我们只需要在那个方法里获取到对象的创建,修改的话只需要修改单例这个方法,假如类的结构发生变化我们只需要修改单例的对象就可以了。工厂也是,我们只需要修改工厂类就可以修改了(譬如不同的fragmen切换的时候我们可以通过工厂设计模式生产对象)

那我们除了上述的方式以外我们设想能不能有个容器,这个容器在我们需要用到某个对象的时候帮我们创建好需要的对象,像对象工厂一样,并且帮我们管理这些对象。沿着这种思想,dragger2应运而生。。。

dragger2
1:在容器中创建好需要的对象
2:获取到MainActivity实例做赋值的动作

Dagger2是为android和java平台提供的在编译时进行依赖注入的框架。
编译时:编译时生成代码(rebuild),我们完胜所需对象的注入,假设是反射,应该是什么时候起作用。
很多的依赖注入都是通过反射去做的,这个dagger2的好处在于没用用反射,而是在编译时就做好了注入,这样解决了反射带来的在性能和开发上的问题。
上面说在编译期就完成了注入,下面我们在rebuild以后看下文件目录,多生成了Presenter工厂类和Component实例类
这里写图片描述
下面我们下看都做了什么?
MainActivityModule_ProvideMainActivityPresenterFactory类

public final class MainActivityModule_ProvideMainActivityPresenterFactory implements Factory<MainActivityPresenter> {private final MainActivityModule module;public MainActivityModule_ProvideMainActivityPresenterFactory(MainActivityModule module) {assert module != null;this.module = module;}public MainActivityPresenter get() {return (MainActivityPresenter)Preconditions.checkNotNull(this.module.provideMainActivityPresenter(), "Cannot return null from a non-@Nullable @Provides method");}public static Factory<MainActivityPresenter> create(MainActivityModule module) {return new MainActivityModule_ProvideMainActivityPresenterFactory(module);}
}

DaggerMainActivityComponent类

private Provider<MainActivityPresenter> provideMainActivityPresenterProvider;private MembersInjector<MainActivity> mainActivityMembersInjector;private DaggerMainActivityComponent(DaggerMainActivityComponent.Builder builder) {assert builder != null;this.initialize(builder);}public static DaggerMainActivityComponent.Builder builder() {return new DaggerMainActivityComponent.Builder(null);}private void initialize(DaggerMainActivityComponent.Builder builder) {this.provideMainActivityPresenterProvider = MainActivityModule_ProvideMainActivityPresenterFactory.create(builder.mainActivityModule);this.mainActivityMembersInjector = MainActivity_MembersInjector.create(this.provideMainActivityPresenterProvider);}public void in(MainActivity activity) {this.mainActivityMembersInjector.injectMembers(activity);}public static final class Builder {private MainActivityModule mainActivityModule;private Builder() {}public MainActivityComponent build() {if(this.mainActivityModule == null) {throw new IllegalStateException(MainActivityModule.class.getCanonicalName() + " must be set");} else {return new DaggerMainActivityComponent(this, null);}}public DaggerMainActivityComponent.Builder mainActivityModule(MainActivityModule mainActivityModule) {this.mainActivityModule = (MainActivityModule)Preconditions.checkNotNull(mainActivityModule);return this;}}
}

关键就在于里面的in方法,这里的injectMembers方法进行了关联。

public void in(MainActivity activity) {this.mainActivityMembersInjector.injectMembers(activity);}
深入解析dragger2

1:指定创建对象的类和方法。
在MainActivityModule中用@Module注解指定创建对象的类
然后通过@Provides方法指定创建对象的方法。

@Module
public class MainActivityModule {private MainActivity activity;public MainActivityModule(MainActivity activity) {this.activity = activity;}@Providespublic MainActivityPresenter provideMainActivityPresenter(){return  new MainActivityPresenter(activity);}
}

2:指定接受者
创建好的对象赋值给指定目标,我们需要通过@Inject告诉dragger2容器。
把已经创建好的对象赋值给谁,

@Inject
MainActivityPresenter presenter;

3:将创建好的对象和接受者联系在一起
通过@Component注解指定这个工作由哪个接口来完成。
这个接口中我们可以看到组件和接受者。
我们先定义一个接口
@Component (modules = MainActivityModule.class)
public interface MainActivityComponent {
void in(MainActivity activity);
}
在activity中我们会创建这个接口对应的实例

MainActivityComponent component = DaggerMainActivityComponent.builder().mainActivityModule(new MainActivityModule(this)).build();component.in(this);

可以看出返回的就是Component对应的实例。这个实例中完成了关联

接下来我们断电进区看一看究竟:

在MainActivity中

 MainActivityComponent component = DaggerMainActivityComponent.builder().mainActivityModule(new MainActivityModule(this)).build();component.in(this);

断点进去
DaggerMainActivityComponent类中

@Overridepublic void in(MainActivity activity) {mainActivityMembersInjector.injectMembers(activity);}

再进入MainActivity_MembersInjector类中

@Override
public void injectMembers(MainActivity instance) {if (instance == null) {throw new NullPointerException("Cannot inject members into a null reference");}instance.presenter = presenterProvider.get();
}

这里写图片描述

这里写图片描述

可以看出一遍是拿到presenter的引用,一边拿到module应用然后把module对象,而这个module类是用于创建presenter对象的。这样就轻易的把二者关联到一起了。

dragger2的使用
引入配置
添加dagger2的依赖
compile 'com.google.dagger:dagger:2.6'
编译时生成代码的插件配置(android-apt)
project的gradle中添加buildscript {dependencies {classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'}}
apt插件的使用modle的gradle中添加apply plugin: 'com.neenbedankt.android-apt'
关联Dagger2dependencies {apt 'com.google.dagger:dagger-compiler:2.6'}
开始我犯了一个错误就是
添加apply plugin: 'com.neenbedankt.android-apt'
// 使用apt插件为Dagger2生成代码
apt 'com.google.dagger:dagger-compiler:2.6'
的时候我没有在module中添加,而是在app的 module添加了以至于一直没有注入成功,所以大家在使用的哪个module下面需要注入就在哪个module下添加
{
apply plugin: 'com.neenbedankt.android-apt' // 注释处理
}
{compile 'com.google.dagger:dagger:2.0.2'compile 'com.google.dagger:dagger-compiler:2.0.2'
}然后在project中grade中配置
{dependencies {classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'}
}

使用步骤分五步走:
这里写图片描述

retrofit的使用

Retrofit的介绍

Retorfit是一个功能强大的联网工具。可以看成是OKHttp+数据解析(json、xml等)的组合。
它可以自动的对我们返回的数据进行解析,这里的解析工具有很多种,

Converters can be added to support other types. Six sibling modules adapt popular serialization libraries for your convenience.Gson: com.squareup.retrofit2:converter-gson
Jackson: com.squareup.retrofit2:converter-jackson
Moshi: com.squareup.retrofit2:converter-moshi
Protobuf: com.squareup.retrofit2:converter-protobuf
Wire: com.squareup.retrofit2:converter-wire
Simple XML: com.squareup.retrofit2:converter-simplexml
Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars

需要在代码中配置一下就可以规定用哪种解析工具,一般常用的有Gson,SimpleXml,Jackson

一、 使用手册
1. 引入配置
λ 添加Retrofit依赖:
compile ‘com.squareup.retrofit2:retrofit:2.1.0’
λ 使用Gson进行数据解析
compile ‘com.google.code.gson:gson:2.2.4’
λ 将Retorfit与Gson关联
compile ‘com.squareup.retrofit2:converter-gson:2.1.0’

测试链接http://localhost:8080/TakeoutService/login?username=“zhang san”&password=”bj”

 //网络访问,创建builder和数据解析工具Retrofit.Builder builder = new Retrofit.Builder();builder.baseUrl("http://localhost:8080/");//确定解析工具builder.addConverterFactory(GsonConverterFactory.create());//第二步:创建retrofitRetrofit retrofit = builder.build();//第三步:指定请求方式,和参数,通过以接口形式指定。//第四步:将retrofit与第三步的联网参数联系在一起//相当于通过retrofit给ResponseInfoApi接口创建一个实例api = retrofit.create(ResponseInfoApi.class);

然后获取到ResponseInfoApi实例对象api,通过这个对象定义的方法返回一个Call对象,用于操作网络
Call login = api.login(username, password);

由于之前我们就规定好的接口方法。

//"TakeoutService/login"@GET("TakeoutService/login") Call<ResponseInfo> login(@Query("username") String username, @Query("password") String password);

可以看出返回的是一个Call对象的范型,范型的类型就是返回的数据解析后的bean类型,所以我们得提前用一个bean来接收。

public void login(String username, String password) {Call<ResponseInfo> login = api.login(username, password);//异步login.enqueue(new Callback<ResponseInfo>() {@Overridepublic void onResponse(Call<ResponseInfo> call, Response<ResponseInfo> response) {//服务器成功回复操作
//                ResponseInfo body = response.body();if (response != null) {if (response.isSuccessful()) {activity.success();} else {//请求提示}} else {onFailure(call, new RuntimeException("服务器请求异常"));}activity.success();}@Overridepublic void onFailure(Call<ResponseInfo> call, Throwable t) {//服务器失败操作activity.faile();}});}
替换原则:
1@Path - 替换参数
@GET("/group/{id}/users")
public Call<List<User>> groupList(@Path("id") int groupId);
2@Query - 添加查询参数
@GET("/group/{id}/users")
public Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
3@QueryMap - 如果有多个查询参数,把它们放在Map中
@GET("/group/{id}/users")
public Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);

这篇关于Dragger2与MVP与Retrofit实战的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1086180

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

滚雪球学Java(87):Java事务处理:JDBC的ACID属性与实战技巧!真有两下子!

咦咦咦,各位小可爱,我是你们的好伙伴——bug菌,今天又来给大家普及Java SE啦,别躲起来啊,听我讲干货还不快点赞,赞多了我就有动力讲得更嗨啦!所以呀,养成先点赞后阅读的好习惯,别被干货淹没了哦~ 🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎大家关注&&收藏!持续更新中,up!up!up!! 环境说明:Windows 10

springboot实战学习(1)(开发模式与环境)

目录 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 (3)前端 二、开发模式 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 Validation:做参数校验Mybatis:做数据库的操作Redis:做缓存Junit:单元测试项目部署:springboot项目部署相关的知识 (3)前端 Vite:Vue项目的脚手架Router:路由Pina:状态管理Eleme

深度学习实战:如何利用CNN实现人脸识别考勤系统

1. 何为CNN及其在人脸识别中的应用 卷积神经网络(CNN)是深度学习中的核心技术之一,擅长处理图像数据。CNN通过卷积层提取图像的局部特征,在人脸识别领域尤其适用。CNN的多个层次可以逐步提取面部的特征,最终实现精确的身份识别。对于考勤系统而言,CNN可以自动从摄像头捕捉的视频流中检测并识别出员工的面部。 我们在该项目中采用了 RetinaFace 模型,它基于CNN的结构实现高效、精准的

项目实战系列三: 家居购项目 第四部分

购物车 🌳购物车🍆显示购物车🍆更改商品数量🍆清空购物车&&删除商品 🌳生成订单 🌳购物车 需求分析 1.会员登陆后, 可以添加家居到购物车 2.完成购物车的设计和实现 3.每添加一个家居,购物车的数量+1, 并显示 程序框架图 1.新建src/com/zzw/furns/entity/CartItem.java, CartItem-家居项模型 /***

Birt报表开发实战

我就截图描述得了,没什么含金量,看图基本明白的。 1.开始 a.创建报表文件 b.数据源配置 c.配置数据集 2.网格报表 拖拉式操作,很方便 3.预览效果 其他报表的操作也基本不难,就不扯了! 2.级联参数 官方视频教程:http://demo.actuate.com/demos/cascade/cascade.html

[yolov5] --- yolov5入门实战「土堆视频」

1 项目介绍及环境配置 下载yolov5 tags 5.0源码,https://github.com/ultralytics/yolov5/tree/v5.0,解压 Pycharm 中创建conda虚拟环境 激活conda虚拟环境 根据作者提供的requirements.txt文件,pip install -r requirements.txt 如果作者没有提供requirement.txt文件

用Python实现时间序列模型实战——Day 14: 向量自回归模型 (VAR) 与向量误差修正模型 (VECM)

一、学习内容 1. 向量自回归模型 (VAR) 的基本概念与应用 向量自回归模型 (VAR) 是多元时间序列分析中的一种模型,用于捕捉多个变量之间的相互依赖关系。与单变量自回归模型不同,VAR 模型将多个时间序列作为向量输入,同时对这些变量进行回归分析。 VAR 模型的一般形式为: 其中: ​ 是时间  的变量向量。 是常数向量。​ 是每个时间滞后的回归系数矩阵。​ 是误差项向量,假