Android MVP开发模式与Rxjava+Retrofit结合的使用(进阶版)_android mvp+retrofit+rxjava循环

二、实现步骤

1、基于哪些基础?

首先一定有个大前提,就是所有接口返回的数据格式,都是一样的,比如说现在我的接口返回数据格式是这样的

{
    "code": 200,
    "message": "提交成功"
}


又或者是这样的

{
    "code": 200,
    "message": "",
    "data": {
        "userName": "张三",
        "headImage": "http://192.168.3.11/file/user/hf6d4g88a.jpg",
        "sex": 1,
        "bir": "2020-01-01"
    }
}


他们都有些共同点,如code和message,那么data就是泛型了!所以定义的响应体接收的类为

public class CallResult<T> {
    public int code;
    public String message;
    public T data;
}


2、封装Retrofit

考虑到有时候需要在请求的header中加各种数据,比如说appVersion等,并且上传文件和普通的接口超时时间一般是不同的,因此就有了这种封装

2.1开始封装
import android.text.TextUtils;
import android.util.Log;

import com.example.mvp.OnHttpResultListener;
import com.example.mvp.retrofit2.convert.MyConverterFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.Interceptor;
import okhttp3.OkHttpClient.Builder;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;

/**
 * @author Administrator
 */
public class Retrofit2Manager {
    /**
     * 默认的请求时间
     */
    private long timeOut = 20000L;
    /**
     * 监听请求过程
     */
    private OnHttpResultListener onHttpResultListener;
    /**
     * 服务器地址
     */
    private final String baseUrl;
    /**
     * 请求头
     */
    private final Map<String, String> map = new HashMap<>();
    /**
     * 自定义拦截器
     */
    private final List<Class<? extends Interceptor>> interceptors = new ArrayList<>();

    /**
     * 静态方法,入口
     *
     * @param baseUrl 路径
     * @return this
     */
    public static Retrofit2Manager with(String baseUrl) {
        return new Retrofit2Manager(baseUrl);
    }

    /**
     * 私有构造方法
     *
     * @param baseUrl 服务器路径
     */
    private Retrofit2Manager(String baseUrl) {
        this.baseUrl = baseUrl;
    }

    /**
     * 超时时间
     *
     * @param timeOut timeOut
     * @return this
     */
    public Retrofit2Manager setTimeOut(long timeOut) {
        this.timeOut = timeOut;
        return this;
    }

    /**
     * 监听请求过程
     *
     * @param onHttpResultListener onHttpResultListener
     * @return this
     */
    public Retrofit2Manager setOnHttpResultListener(OnHttpResultListener onHttpResultListener) {
        this.onHttpResultListener = onHttpResultListener;
        return this;
    }

    /**
     * 添加自定义请求头
     *
     * @param key   key
     * @param value value
     * @return this
     */
    public Retrofit2Manager addHeadres(String key, String value) {
        if (TextUtils.isEmpty(key)) {
            return this;
        }
        if (TextUtils.isEmpty(value)) {
            value = "";
        }
        map.put(key, value);
        return this;
    }

    public Retrofit2Manager add(Class<? extends Interceptor> mClass) {
        interceptors.add(mClass);
        return this;


    }

    /**
     * 返回retrofit2的实例
     *
     * @return retrofit2
     */
    public Retrofit retrofit() {
        Builder okBuilder = new Builder();
        okBuilder.readTimeout(this.timeOut, TimeUnit.MILLISECONDS);
        okBuilder.writeTimeout(this.timeOut, TimeUnit.MILLISECONDS);
        okBuilder.connectTimeout(this.timeOut, TimeUnit.MILLISECONDS);
        okBuilder.addInterceptor(new LogInterceptor(map, onHttpResultListener));
        try {
            for (Class<? extends Interceptor> mClass : interceptors) {
                okBuilder.addInterceptor(mClass.newInstance());
            }
        } catch (Exception e) {
            Log.e("mvp[error]", e.getMessage());
            e.printStackTrace();
        }
        return (new Retrofit.Builder()).client(okBuilder.build())
                .baseUrl(this.baseUrl)
                //自定义解析
                .addConverterFactory(MyConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
    }
}


2.2为什么要自定义解析?

当服务器返回的数据为

{
    "code": 200,
    "message": "",
    "data": [
        {
            "userName": "李四",
            "headImage": "http://192.168.3.11/file/user/hf6d4g3243288a.jpg",
            "sex": 1,
            "bir": "2020-01-01"
        },
        {
            "userName": "张三",
            "headImage": "http://192.168.3.11/file/user/hf6d4g84348a.jpg",
            "sex": 2,
            "bir": "2020-01-17"
        },
        {
            "userName": "王五",
            "headImage": "http://192.168.3.11/file/user/hf6d4345436g88a.jpg",
            "sex": 1,
            "bir": "2020-03-01"
        }
    ]
}


时,我们定义的实体类可以正常接收数据。如果接口返回的数据是

{
    "code": 401,
    "message": "登录状态已失效",
    "data": null
}


的时候,你会发现直接json转换闪退,因为null无法转换成list,因此我们要自己定义解析工厂,以下是部分代码

    @Override
    public T convert(@NonNull ResponseBody value) {
        String str = "";
        Object var3;
        try {
            if (value.contentLength() != 0L) {
                str = value.source().readUtf8();
                var3 = this.convert(str, this.type);
                return (T) var3;
            }
            str = "{\"code\":90000,\"message\":\"服务器无响应\"}";
            var3 = this.convert(str, CallResult.class);
        } catch (Exception var8) {
            //当转换出现异常,就用Void进行转换
            Object var4 = this.convert(str, CallResult.class);
            return (T) var4;
        } finally {
            value.close();
        }
        return (T) var3;
    }



3、创建mvp的各种Base基类

3.1 model层BaseModel

OnHttpResultListener是自己定义的,用来接收接口参数,对调试非常好用,上线版本可以忽略

import android.util.Log;

import com.example.mvp.OnHttpResultListener;
import com.example.mvp.retrofit2.Retrofit2Manager;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;

public class BaseModel implements OnHttpResultListener {

    protected <T> T createService(String ip, Class<T> mClass) {
        return Retrofit2Manager.with(ip).setOnHttpResultListener(this).retrofit().create(mClass);
    }

    @Override
    public void onResponse(String method, String requestUrl, String requestHeaders, String requestParams, int responseCode, String responseData) {
        String sb = "\n【请求方法】:" + method +
                "\n【请求路径】:" + requestUrl +
                "\n【请求头】:" + requestHeaders +
                "\n【请求参数】:" + requestParams +
                "\n【返回参数】:" + responseData;
        Log.d("exccd(mvp-http)", sb);
    }

    /**
     * 发起请求,并且在ui线程执行回调
     *
     * @param observable observable
     * @param <T>        泛型
     */
    protected <T> Observable<T> callBackOnUi(Observable<T> observable) {
        return observable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }

    /**
     * 发起请求,并且在新的子线程执行回调
     *
     * @param observable observable
     * @param <T>        泛型
     */
    protected <T> Observable<T> callBackOnThread(Observable<T> observable) {
        return observable.subscribeOn(Schedulers.io())
                .observeOn(Schedulers.newThread());
    }
}


3.2 视图层IBaseView

为了让ui实现这个回调更加简单,我这里将服务器返回的message和其他所有可能有的提示都通过s字段来返回了,因此不管是“登录状态已失效”还是“网络连接异常”,都是在s回调的。根据项目不用,有需要的可以拆分。

/**
 * ui回调
 *
 * @param <T> 泛型
 */
public interface IBaseView<T> {
    /**
     * ui回调
     *
     * @param b    是否请求成功
     * @param i    类型
     * @param s    描述
     * @param data 泛型
     */
    void onCallBack(boolean b, int i, String s, T data);
}


3.3 Presenter层

这一层最关键的是IBasePresenter和它的实现类BasePresenter

3.3.1 IBasePresenter

start方法是发起请求的入口,使用时需要将model的方法传进去,然后跟视图绑定起来。

/**
 * presenter需要具备的基础方法
 */
public interface IBasePresenter {
    /**
     * 开始发起请求
     *
     * @param observable model层返回的obs
     * @param iBaseView  视图,回调
     * @param <T>        泛型
     */
    <T> void start(Observable<CallResult<T>> observable, IBaseView<T> iBaseView);

    /**
     * 成功回调
     *
     * @param iBaseView 视图、回调
     * @param data      数据
     * @param <T>       泛型
     */
    <T> void viewCallBackSuccess(IBaseView<T> iBaseView, CallResult<T> data);

    /**
     * 错误回调
     *
     * @param iBaseView 视图、回调
     * @param e         错误信息
     * @param <T>       泛型
     */
    <T> void viewCallBackError(IBaseView<T> iBaseView, Throwable e);

    /**
     * 解绑
     */
    void detachView();
}


3.3.2 BasePresenter

BasePresenter处理一些回调,将一些非正常接口请求的结果转换成中文(指定描述)在回调给view,这里的所有数据都是可以自己定义的,另外如果在某种情况下需要弹窗退出登录,建议您新建一个MyBasePresenter extend BasePresenter,然后重写onTokenErrorCallBack()即可,但判断的逻辑需要更改一下。

public abstract class BasePresenter<M> implements IBasePresenter {
    /**
     * 未授权登录,登录状态已失效
     */
    public static final int UNAUTHORIZED = 401;
    /**
     * 请求成功
     */
    public static final int SUCCESS = 200;
    /**
     * 请求被禁止
     */
    public static final int FORBIDDEN = 403;
    /**
     * 接口失效
     */
    public static final int NOT_FOUND = 404;
    /**
     * 请求超时
     */
    public static final int REQUEST_TIMEOUT = 408;
    /**
     * 服务器错误
     */
    public static final int INTERNAL_SERVER_ERROR = 500;
    /**
     * 错误的网关
     */
    public static final int BAD_GATEWAY = 502;
    /**
     * 服务器不可用
     */
    public static final int SERVICE_UNAVAILABLE = 503;
    /**
     * 网络超时
     */
    public static final int GATEWAY_TIMEOUT = 504;
    /**
     * 在默认线程回调
     */
    private boolean callBackInLoop = false;
    /**
     * 是否已经解绑了,避免重复解绑
     */
    private boolean isDttached = false;
    /**
     * model层
     */
    protected M module;
    /**
     * 视图
     */
    private final Map<Integer, IBaseView<?>> mapView = new HashMap<>();
    /**
     * 视图引用
     */
    private final Map<Integer, WeakReference<?>> mapReference = new HashMap<>();
    /**
     * 请求对象
     */
    private final Map<Integer, Disposable> mapDisposables = new HashMap<>();
    /**
     * 主线程
     */
    protected Handler handler;

    /**
     * 构造方法
     * 您需要手动{@link #detachView()}解绑
     */
    public BasePresenter() {
        onCreate(null);
    }

    /**
     * 构造方法
     *
     * @param activity activity的实例
     */
    public BasePresenter(Activity activity) {
        onCreate(activity);
    }

    /**
     * 构造方法
     *
     * @param context 如果这是个activity的实例,那么不需要手动{@link #detachView()}即可解绑,否则您需要调用他
     */
    public BasePresenter(Context context) {
        if (context instanceof Activity) {
            onCreate((Activity) context);
        } else {
            onCreate(null);
        }
    }

    /**
     * 初始化方法
     */
    private void onCreate(Activity activity) {
        this.handler = new Handler(Looper.getMainLooper());
        if (this.module == null) {
            this.module = this.createModel();
        }
        if (activity != null) {
            String acName = activity.getLocalClassName();
            Application app = activity.getApplication();
            Application.ActivityLifecycleCallbacks callbacks = new Application.ActivityLifecycleCallbacks() {
                @Override
                public void onActivityCreated(Activity activity, Bundle bundle) {

                }

                @Override
                public void onActivityStarted(Activity activity) {

                }

                @Override
                public void onActivityResumed(Activity activity) {

                }

                @Override
                public void onActivityPaused(Activity activity) {

                }

                @Override
                public void onActivityStopped(Activity activity) {

                }

                @Override
                public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {

                }

                @Override
                public void onActivityDestroyed(Activity activity) {
                    if (acName.equals(activity.getLocalClassName())) {
                        detachView();
                        app.unregisterActivityLifecycleCallbacks(this);
                    }
                }
            };
            app.registerActivityLifecycleCallbacks(callbacks);
        }
    }

    /**
     * 绑定
     *
     * @param view 视图
     */
    @SuppressWarnings("all")
    private <T, V extends IBaseView<T>> void attachView(V view) {
        if (view != null) {
            WeakReference<V> weakReference = new WeakReference<V>(view);
            mapReference.put(view.hashCode(), weakReference);
            ClassLoader classLoader = view.getClass().getClassLoader();
            Class<?>[] interfaces = view.getClass().getInterfaces();
            InvocationHandler invocationHandler = new MvpViewHandler((IBaseView) weakReference.get());
            IBaseView<T> v = (V) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
            mapView.put(view.hashCode(), v);
        }
    }

    /**
     * 是否在默认线程回调
     *
     * @param callBackInLoop 如果是false,回调会在ui线程处理,否则就是在发起默认的线程回调
     */
    public void setCallBackInLoop(boolean callBackInLoop) {
        this.callBackInLoop = callBackInLoop;
    }

    /**
     * 页面是否已经不存在了
     *
     * @param iBaseView 视图
     * @param <T>       泛型
     * @return true存在,则回调,否则忽略
     */
    protected <T> boolean isViewAttached(IBaseView<T> iBaseView) {
        if (iBaseView == null) {
            return false;
        }
        int key = iBaseView.hashCode();
        IBaseView<?> view = mapView.get(key);
        WeakReference<?> weakReference = mapReference.get(key);
        return view != null && weakReference != null && weakReference.get() != null;
    }

    /**
     * 创建module
     *
     * @return M
     */
    protected abstract M createModel();

    /**
     * 请求是否成功
     *
     * @param data 响应体
     * @return 成功true,失败false
     */
    protected <T> boolean isSuccess(CallResult<T> data) {
        return data != null && data.code == SUCCESS;
    }

    /**
     * 开始发起请求
     *
     * @param observable model层返回的obs
     * @param baseView   视图、回调
     * @param <T>        泛型
     */
    @Override
    public <T> void start(Observable<CallResult<T>> observable, IBaseView<T> baseView) {
        attachView(baseView);
        mapDisposables.put(baseView.hashCode(), observable
                .subscribe(data -> viewCallBackSuccess(baseView, data), e -> viewCallBackError(baseView, e)));
    }

    /**
     * 成功回调
     *
     * @param view 视图、回调
     * @param data 数据
     * @param <T>  泛型
     */
    @Override
    public <T> void viewCallBackSuccess(IBaseView<T> view, CallResult<T> data) {
        if (callBackInLoop) {
            _viewCallBackSuccess(view, data);
        } else {
            if (Looper.myLooper() == Looper.getMainLooper()) {
                _viewCallBackSuccess(view, data);
            } else {
                handler.post(() -> _viewCallBackSuccess(view, data));
            }
        }
    }

    /**
     * 错误回调
     *
     * @param view 视图、回调
     * @param e    错误信息
     * @param <T>  泛型
     */
    @Override
    public <T> void viewCallBackError(IBaseView<T> view, Throwable e) {
        if (callBackInLoop) {
            _viewCallBackError(view, e);
        } else {
            if (Looper.myLooper() == Looper.getMainLooper()) {
                _viewCallBackError(view, e);
            } else {
                handler.post(() -> _viewCallBackError(view, e));
            }
        }
    }

    /**
     * 解绑
     */
    @Override
    public void detachView() {
        if (isDttached) {
            return;
        }
        isDttached = true;
//        this.module = null;
        this.handler.removeCallbacksAndMessages(null);
        for (WeakReference<?> weakReference : mapReference.values()) {
            if (weakReference != null) {
                weakReference.clear();
            }
        }
        mapReference.clear();
        mapView.clear();
        try {
            for (Disposable disposable : mapDisposables.values()) {
                if (disposable != null && !disposable.isDisposed()) {
                    disposable.dispose();
                }
            }
        } catch (Exception e) {
            Log.e("mvp[error]", e.getMessage());
        }
    }

    /**
     * 统一执行成功回调,看{@link #viewCallBackSuccess}
     */
    private <T> void _viewCallBackSuccess(IBaseView<T> view, CallResult<T> data) {
        if (data.code == UNAUTHORIZED) {
            onTokenErrorCallBack(data.message);
        }
        if (isViewAttached(view)) {
            view.onCallBack(data.code == SUCCESS, data.code, data.message, data.data);
        }
    }

    /**
     * 统一执行错误回调,看{@link #viewCallBackError}
     */
    private <T> void _viewCallBackError(IBaseView<T> view, Throwable e) {
        if (isViewAttached(view)) {
            try {
                if (e instanceof HttpException) {
                    HttpException httpException = (HttpException) e;
                    switch (httpException.code()) {
                        case UNAUTHORIZED:
                            callBackError(view, "登录验证已过期");
                            onTokenErrorCallBack("登录验证已过期");
                            break;
                        case INTERNAL_SERVER_ERROR:
                            callBackError(view, "服务器错误");
                            break;
                        case FORBIDDEN:
                        case NOT_FOUND:
                            callBackError(view, "无效的请求");
                            break;
                        case REQUEST_TIMEOUT:
                        case GATEWAY_TIMEOUT:
                        case BAD_GATEWAY:
                        case SERVICE_UNAVAILABLE:
                        default:
                            callBackError(view, httpException.getMessage());
                            break;
                    }
                } else if (e instanceof ConnectException) {
                    callBackError(view, "网络连接异常,请检查您的网络状态");
                } else if (e instanceof SocketTimeoutException) {
                    callBackError(view, "网络连接超时,请检查您的网络状态,稍后重试");
                } else if (e instanceof UnknownHostException) {
                    callBackError(view, "网络异常,请检查您的网络状态");
                } else if (e instanceof JSONException


#### 最后是今天给大家分享的一些独家干货:

**【Android开发核心知识点笔记】**

![](https://img-blog.csdnimg.cn/img_convert/032269b0a3fe4be9daf0900e7c9bd2af.webp?x-oss-process=image/format,png)

**【Android思维脑图(技能树)】**

![](https://img-blog.csdnimg.cn/img_convert/f2a48aabffb5d2e6a30be6de5c4076bb.webp?x-oss-process=image/format,png)

**【Android核心高级技术PDF文档,BAT大厂面试真题解析】**

![](https://img-blog.csdnimg.cn/img_convert/7d07ea13785f95ada489711e9e924033.webp?x-oss-process=image/format,png)

**【Android高级架构视频学习资源】**




**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618156601)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

ceof SocketTimeoutException) {
                    callBackError(view, "网络连接超时,请检查您的网络状态,稍后重试");
                } else if (e instanceof UnknownHostException) {
                    callBackError(view, "网络异常,请检查您的网络状态");
                } else if (e instanceof JSONException


#### 最后是今天给大家分享的一些独家干货:

**【Android开发核心知识点笔记】**

[外链图片转存中...(img-XrJ7sVRH-1714285139630)]

**【Android思维脑图(技能树)】**

[外链图片转存中...(img-tjFpFBL9-1714285139631)]

**【Android核心高级技术PDF文档,BAT大厂面试真题解析】**

[外链图片转存中...(img-2azFn1KM-1714285139631)]

**【Android高级架构视频学习资源】**




**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618156601)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于Android项目中的网络请求,RxJavaRetrofitMVP是常用的框架组合。下面是一个简单的网络框架封装示例: 首先,在项目中引入RxJavaRetrofit的依赖。 ``` implementation 'io.reactivex.rxjava2:rxjava:2.2.19' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0' ``` 然后,创建一个Retrofit的单例类,用于进行网络请求的初始化和配置。 ```java public class RetrofitClient { private static Retrofit retrofit; private static final String BASE_URL = "https://api.example.com/"; public static Retrofit getClient() { if (retrofit == null) { retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); } return retrofit; } } ``` 接下来,创建一个ApiService接口,定义网络请求的方法。 ```java public interface ApiService { @GET("users") Observable<List<User>> getUsers(); } ``` 然后,创建一个DataManager类,用于管理网络请求。 ```java public class DataManager { private ApiService apiService; public DataManager() { apiService = RetrofitClient.getClient().create(ApiService.class); } public Observable<List<User>> getUsers() { return apiService.getUsers(); } } ``` 最后,在MVP的Presenter中调用DataManager类进行网络请求。 ```java public class UserPresenter { private UserView userView; private DataManager dataManager; public UserPresenter(UserView userView) { this.userView = userView; dataManager = new DataManager(); } public void getUsers() { dataManager.getUsers() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<List<User>>() { @Override public void onSubscribe(Disposable d) { // 在请求开始时的操作 } @Override public void onNext(List<User> users) { // 请求成功返回数据时的操作 userView.showUsers(users); } @Override public void onError(Throwable e) { // 请求失败时的操作 userView.showError(e.getMessage()); } @Override public void onComplete() { // 请求完成时的操作 } }); } } ``` 这样,就完成了一个简单的Android RxJava + Retrofit + MVP网络框架封装。你可以根据自己的需要,进行进一步的封装和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值