MVP + Retrofit + RxJava 搭建一个基础的Android开发框架
2022/1/18 17:06:32
本文主要是介绍MVP + Retrofit + RxJava 搭建一个基础的Android开发框架,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
MVP + Retrofit + RxJava 搭建一个基础的Android开发框架
前言
- 本项目旨在搭建一个简易的Android开发结构,避免新手开发时出现代码混乱的问题,如有不同意见欢迎评论区提出
- 包含一个基础的框架搭建,讲解都在注释里
一、主要功能
- 提供基础的MVP结构,并集成相关的初始化操作
- 提供基础的网络管理框架,更方便的进行网络请求和管理
- 提供日志打印管理,可以在logcat自动打印指定级别的http日志,方便调试
- 提供简单的页面示例 SampleActivity
二、部分关键代码
1. 引入相关依赖
// blankj 工具包,包含了相当多的功能,强推 implementation 'com.blankj:utilcodex:1.30.6' // retrofit implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' // rx java implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation "me.jessyan:rxerrorhandler:2.1.1" // butterKnife 控件绑定 implementation 'com.jakewharton:butterknife:10.2.3' annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3'
2. 代码结构图
3. MVP 相关代码
- MVP 接口定义
public interface IModel { void onDestroy(); } public interface IView { /** * 显示进度条 */ default void showLoading(){ } /** * 隐藏进度条 */ default void hideLoading() { } /** * 显示报错的信息,默认使用ToastUtils提示,子类可重写 * @param msg 需要显示的信息 */ default void showMessage(String msg) { ToastUtils.showShort(msg); } } public interface IPresenter { /** * 向 presenter 生命周期中增加发射器 * View 和 Model 均可添加向其中添加需要注册的事件,不用担心生命周期 */ void addDisposable(Disposable... disposables); /** * 首次进入页面时的网络请求 */ default void initDataReq() { } void onDestroy(); }
- BaseModel 实现
import com.blankj.utilcode.util.ToastUtils; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import java.lang.reflect.ParameterizedType; import java.util.Objects; public abstract class BaseModel<P extends IPresenter, S> implements IModel { protected P mPresenter; Class<S> serviceClass; @SuppressWarnings("unchecked") public BaseModel(P mPresenter) { this.mPresenter = mPresenter; try { // 这一段代码,就是反射,通过泛型,获取指定的类 ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass(); if (type == null) { throw new RuntimeException("运行异常,初始化失败: " + getClass().getSimpleName()); } serviceClass = (Class<S>) type.getActualTypeArguments()[1]; } catch (Exception e) { e.printStackTrace(); } } //使用Retrofit获取了指定接口的实例 //通过Service执行某一个请求时,拼接Url并执行网络访问,并将返回结果按指定格式解析并返回 protected S obtainService() { return NetManager.getInstance().bindService(serviceClass);//谁拿到 ,谁指定Service } /** * 检查 code,如果返回值中 code 不是 {@link NetCode#Success} 则通知相应错误信息 * @param bean 需要检查的code * @return 如果成功则为 true */ protected boolean checkCode(CommonResBean<?> bean) { String needDisplay = bean.checkCode(); if (needDisplay == null) { return true; } // 向 presenter 中 增加通知错误信息线程 mPresenter.addDisposable(Observable.just(needDisplay) .observeOn(AndroidSchedulers.mainThread()) .filter(Objects::nonNull) .subscribe(ToastUtils::showShort)); return false; } @Override public void onDestroy() { mPresenter = null; } }
- BasePresenter 实现
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.Disposable; import java.lang.reflect.ParameterizedType; //BasePresenter 两个泛型,前者为视图的,后者为数据源的 public abstract class BasePresenter<V extends IView, M extends IModel> implements IPresenter { protected V mView;//V 泛型变量 protected M mModel;//M 泛型变量 // 这是一个集合,用来控制生命周期 private CompositeDisposable compositeDisposable; @SuppressWarnings("unchecked") public BasePresenter(V mView) { this.mView = mView; // 保存了上级 View try { // 一个泛型Model 实例 ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass(); if (type == null) { throw new RuntimeException("运行异常,初始化失败: " + getClass().getSimpleName()); } Class<M> classM = (Class<M>) type.getActualTypeArguments()[1]; this.mModel = (M) classM.getConstructors()[0].newInstance(this); } catch (Exception e) { e.printStackTrace(); } compositeDisposable = new CompositeDisposable(); } //从子管理传参到这里,再for循环出来数据 给compositeDisposable public void addDisposable(Disposable... disposables) { if (compositeDisposable == null) { return; } for (Disposable disposable : disposables) { compositeDisposable.add(disposable); } } @Override public void onDestroy() { mView = null; if (mModel != null) { mModel.onDestroy();//不等于空,就销毁 mModel = null; } // 在合适的时机取消未结束的网络请求 // 取消所有未完成的网络请求 // 因为视图已经销毁了,如果继续下去,会崩溃 if (compositeDisposable != null) { compositeDisposable.dispose(); compositeDisposable = null; } } }
- BaseActivity/BaseFragment 实现
import android.annotation.SuppressLint; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import androidx.annotation.CallSuper; import androidx.appcompat.app.AppCompatActivity; import butterknife.ButterKnife; /** * FileName: BaseActivity * Founder: * Create Date: * Email: * Profile: Base Activity 基类 */ public abstract class BaseActivity<P extends IPresenter> extends AppCompatActivity implements IView, InitialPro<P> { protected P mPresenter; protected View mContentView; @SuppressLint("InflateParams") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //Event后,在后台能接到消息; 要用Manager里面的eventMManager mPresenter = initPresenter();//被 泛型的某一个Presenter来初始化IPresenter 在Activity中 mContentView = LayoutInflater.from(this).inflate(getContentViewId(), null, false); setContentView(mContentView); ButterKnife.bind(this, mContentView); initView(); initData(); } @CallSuper protected void initData() { mPresenter.initDataReq(); } //解绑 @Override protected void onDestroy() { super.onDestroy(); if (mPresenter != null) { mPresenter.onDestroy(); mPresenter = null; } } }
import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import androidx.annotation.CallSuper; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import butterknife.ButterKnife; /** * FileName: BaseFragment * Founder: * Create Date: * Email: * Profile: Base Fragment * * 泛型未知,但是,主动继承IPresenter */ public abstract class BaseFragment<P extends IPresenter> extends Fragment implements IView, InitialPro<P> { protected P mPresenter; protected View mContentView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mPresenter = initPresenter();//被泛型的某一个Presenter来初始化(引入)IPresenter 在Fragment中 } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { mContentView = inflater.inflate(getContentViewId(), container, false); // Base View 主要做的,绑定 Presenter,初始化结构,绑定ButterKnife // ButterKnife 就是做了一个视图绑定,不用再findviewbyid ButterKnife.bind(this, mContentView); initView(); initData(); return mContentView; } @CallSuper protected void initData() { // 可以看到,在View 基类中,视图创建好了之后 // 会告知Presenter可以准备请求网络数据了 // 因为如果过早,视图还没创建,如果网络请求好了,那就会崩溃 // 所以这个时机让Presenter请求网络 哦。明白了。是的。。 mPresenter.initDataReq(); } @Override public void onDestroy() { super.onDestroy(); // 在视图销毁时,释放资源 if (mPresenter != null) { // 告知Presenter释放 mPresenter.onDestroy(); mPresenter = null; } } }
4. Retrofit 部分关键代码
import com.blankj.utilcode.util.GsonUtils; import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; import okhttp3.OkHttpClient; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; import java.util.concurrent.TimeUnit; public class NetManager { private static NetManager netManager; Retrofit retrofit; private NetManager() { // 我们使用的是Retrofit代管网络,这是他的初始化方法 retrofit = new Retrofit.Builder() .client(obtainOKHttpClient()) // 这是基础url,会跟 Service 中的 拼接 .baseUrl("https://www.7timer.info") .addConverterFactory(GsonConverterFactory.create(GsonUtils.getGson())) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); } private OkHttpClient obtainOKHttpClient() { return new OkHttpClient.Builder() .callTimeout(10, TimeUnit.SECONDS) .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS) .writeTimeout(10, TimeUnit.SECONDS) .addInterceptor(new RequestInterceptor(RequestInterceptor.Level.ALL)) .build(); } public static NetManager getInstance() { if (netManager == null) { throw new RuntimeException("你还没有初始化 NetManager"); } return netManager; } // 这两个操作,保证唯一,放到Application中 // 初始化,单例模式,保证唯一 public static void init(Context context) { netManager = new NetManager(); } // 释放资源 public static void release() { if (netManager != null) { netManager.retrofit = null; netManager = null; } } public <T> T bindService(Class<T> targetInterface) { return retrofit.create(targetInterface); } }
三、使用示例
1. 声明要访问的网络接口
import io.reactivex.Observable; import retrofit2.http.GET; import retrofit2.http.Query; public interface SampleServices { /** * <p>1. 可以请求一个地址为 https://www.7timer.info/bin/api.pl?lon=113.17&lat=23.09&product=astro&output=json 的接口,获取天气</p> * <p>2. 可以看到 四个参数刚好对应的就是链接中对应的四个参数,此外也可以传输文件,上传下载,post请求都可以极方便的实现。</p> * <p>关于 retrofit 的更多用法可以参考:<a href="https://www.jianshu.com/p/021a2c6e128b">Retrofit + RxJava使用详解</a></p> */ @GET("/bin/api.pl") Observable<SampleBeans.WeatherData> getWeather( @Query("lon") double lon, @Query("lat") double lat, @Query("product") String pro, @Query("output") String output ); }
2. 创建SampleModel调用请求
import cn.lzd.mvp.base.struct.BaseModel; import cn.lzd.mvp.base.struct.IPresenter; import io.reactivex.Observable; public class SampleModel extends BaseModel<IPresenter, SampleServices> { public SampleModel(IPresenter mPresenter) { super(mPresenter); } public Observable<SampleBeans.WeatherData> getWeather() { return obtainService().getWeather( 113.17, 23.09, "astro", "json" ); } }
3. 创建Presenter管理请求,并分发数据
import cn.lzd.mvp.base.net.RxUtils; import cn.lzd.mvp.base.struct.BasePresenter; public class SamplePresenter extends BasePresenter<SampleActivity, SampleModel> { public SamplePresenter(SampleActivity mView) { super(mView); } void reqWeather() { addDisposable(mModel.getWeather() .compose(RxUtils.applySchedulers(mView)) .subscribe(weatherData -> mView.onReceiveWeatherData(weatherData.getDatas()))); } }
4. 创建View显示视图
@SuppressLint("NonConstantResourceId") public class SampleActivity extends BaseActivity<SamplePresenter> { @BindView(R.id.reqResult) TextView tvReqResult; @BindView(R.id.loadingBG) View loadingBG; @BindView(R.id.loadingProgress) ProgressBar loadingProgress; @BindView(R.id.request) View request; @Override public int getContentViewId() { return R.layout.activity_sample; } @Override public void initView() { super.initView(); tvReqResult.setMovementMethod(ScrollingMovementMethod.getInstance()); } @OnClick({R.id.request, R.id.loadingBG}) public void onClick(View view) { // 对不同的控件做点击事件处理 switch (view.getId()) { case R.id.request: { tvReqResult.setText(""); view.setEnabled(false); mPresenter.reqWeather(); break; } case R.id.loadingBG:{ ToastUtils.showShort("请等待……"); break; } } } void onReceiveWeatherData(List<SampleBeans.DayData> weatherData) { StringBuilder stringBuilder = new StringBuilder(); for (SampleBeans.DayData dayData : weatherData) { stringBuilder.append(GsonUtils.toJson(dayData)).append("\n\n"); } tvReqResult.setText(stringBuilder); request.setEnabled(true); } @Override public void showLoading() { loadingBG.setVisibility(View.VISIBLE); loadingProgress.setVisibility(View.VISIBLE); } @Override public void hideLoading() { loadingBG.setVisibility(View.GONE); loadingProgress.setVisibility(View.GONE); } }
四、关于Observable数据流向的一个简要图示
五、运行结果示例
相关示例代码下载链接:MVP_DEMO
这篇关于MVP + Retrofit + RxJava 搭建一个基础的Android开发框架的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南