# MVPDemo **Repository Path**: WB_LZD/mvpdemo ## Basic Information - **Project Name**: MVPDemo - **Description**: MVP 基础架构 + Retrofit + RxJava + RequestInterceptor 的框架搭建,以及使用的示例代码 - **Primary Language**: Android - **License**: AGPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 1 - **Created**: 2022-01-18 - **Last Updated**: 2024-09-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## MVP + Retrofit + RxJava 搭建一个基础的Android开发框架 #### 前言 - 本项目旨在搭建一个简易的Android开发结构,避免新手开发时出现代码混乱的问题,如有不同意见欢迎评论区提出 - 包含一个基础的框架搭建,讲解都在注释里 #### 一、主要功能 1. 提供基础的MVP结构,并集成相关的初始化操作 2. 提供基础的网络管理框架,更方便的进行网络请求和管理 3. 提供日志打印管理,可以在logcat自动打印指定级别的http日志,方便调试 4. 提供简单的页面示例 SampleActivity #### 二、部分关键代码 ##### 1. 引入相关依赖 ```groovy // 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 接口定义 ```java 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 实现 ```java 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
implements IModel {
protected P mPresenter;
Class extends AppCompatActivity implements IView, InitialPro {
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;
}
}
}
```
```java
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 extends Fragment implements IView, InitialPro {
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 部分关键代码
```java
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 1. 可以请求一个地址为 https://www.7timer.info/bin/api.pl?lon=113.17&lat=23.09&product=astro&output=json 的接口,获取天气 2. 可以看到 四个参数刚好对应的就是链接中对应的四个参数,此外也可以传输文件,上传下载,post请求都可以极方便的实现。 关于 retrofit 的更多用法可以参考:Retrofit + RxJava使用详解 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) 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 实现
```java
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import java.lang.reflect.ParameterizedType;
//BasePresenter 两个泛型,前者为视图的,后者为数据源的
public abstract class BasePresenter