网络(三):MVP+RxJava2+Retrofit2+OkHttp3

网络(三):MVP+RxJava2+Retrofit2+OkHttp3

参考:
https://www.jianshu.com/p/0ad99e598dba
https://www.jianshu.com/p/df4eee78085c

文章分析重新优化,先给个下载链接

github地址:https://github.com/LPTim/MVP-Retrofit2-okhttp3-Rxjava2
csdn地址:https://download.csdn.net/download/loocanp/11229241

相关业务需求及解决方案

1、Retrofit配置及各情况处理
2、Retrofit,Gson解析,自定义解析内容(如code=1全部解析,code=0不做解析)
3、Retrofit,Gson解析,请求返回的类型不统一,假如double返回的是null
4、Retrofit实现cookie自动化管理
5、Retrofit文件上传
6、Retrofit文件下载(稍等给连接)

代码结构如下

在这里插入图片描述

最终实现效果如下图

在这里插入图片描述

1.引用依赖包

 //网络请求
    compile 'com.squareup.okhttp3:okhttp:3.9.1'
    compile 'com.squareup.retrofit2:retrofit:2.3.0'
    //ConverterFactory的Gson依赖包
    compile 'com.squareup.retrofit2:converter-gson:2.3.0'
    //CallAdapterFactory的Rx依赖包
    compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'

    compile 'io.reactivex.rxjava2:rxandroid:2.0.2'
2、retrofit基类代码实现,对日志参数进行了拦截

注:get请求参数打印会拼接在url之后,post打印单独显示
打印框架 logger,日志结构很直观(推荐使用)

/**
 * File descripition:  创建Retrofit
 *
 * @author lp
 * @date 2018/6/19
 */

public class ApiRetrofit {
    public final String BASE_SERVER_URL = BaseContent.baseUrl;
    private String TAG = "ApiRetrofit %s";
    private static ApiRetrofit apiRetrofit;
    private Retrofit retrofit;
    private ApiServer apiServer;
    private static Gson gson;
    private static final int DEFAULT_TIMEOUT = 15;


    public ApiRetrofit() {
        OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
        httpClientBuilder
                .cookieJar(new CookieManger(App.getContext())) //这块是添加的管理cookie方法
                .addInterceptor(interceptor)//日志拦截
                .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true);//错误重联

        retrofit = new Retrofit.Builder()
                .baseUrl(BASE_SERVER_URL)
                .addConverterFactory(GsonConverterFactory.create())//添加json转换框架
                //支持RxJava2
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(httpClientBuilder.build())
                .build();
        apiServer = retrofit.create(ApiServer.class);
    }

    public static ApiRetrofit getInstance() {
        if (apiRetrofit == null) {
            synchronized (Object.class) {
                if (apiRetrofit == null) {
                    apiRetrofit = new ApiRetrofit();
                }
            }
        }
        return apiRetrofit;
    }

    public ApiServer getApiService() {
        return apiServer;
    }

    /**
     * 请求访问quest
     * response拦截器
     */
    private Interceptor interceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            long startTime = System.currentTimeMillis();
            Response response = chain.proceed(chain.request());
            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;
            MediaType mediaType = response.body().contentType();
            String content = response.body().string();
//            analyzeJson("data", "", content);
            Logger.wtf(TAG, "----------Request Start----------------");
            printParams(request.body());
            Logger.e(TAG, "| " + request.toString() + "===========" + request.headers().toString());
            Logger.json(content);
            Logger.e(content);
            Logger.wtf(TAG, "----------Request End:" + duration + "毫秒----------");

            return response.newBuilder()
                    .body(ResponseBody.create(mediaType, content))
                    .build();
        }
    };

    /**
     * 请求参数日志打印
     *
     * @param body
     */
    private void printParams(RequestBody body) {
        if (body != null) {
            Buffer buffer = new Buffer();
            try {
                body.writeTo(buffer);
                Charset charset = Charset.forName("UTF-8");
                MediaType contentType = body.contentType();
                if (contentType != null) {
                    charset = contentType.charset(UTF_8);
                }
                String params = buffer.readString(charset);
                Logger.e(TAG, "请求参数: | " + params);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

4.创建ApiServer类,注释的都是请求案例

public interface ApiServer {
    //示例    多种类型请求方式

//    @POST("api/Activity/get_activities?")
//    Observable<BaseModel<List<>>> getApi1(@Query("time") String requestType);

//    @GET("api/Activity/get_activities?")
//    Observable<BaseModel<List<>>> getApi1(@Query("time") String requestType);

//    @FormUrlEncoded
//    @POST("api/Activity/get_activities?")
//    Observable<BaseModel<List<>>> getApi1(@Field("time") String requestType);

//    @FormUrlEncoded
//    @POST("api/Activity/get_activities?")
//    Observable<BaseModel<List<>>> getApi1(@FieldMap HashMap<String, String> params);

//    @Multipart
//    @POST("api/Activity/get_activities?")
//    Observable<BaseModel<List<>>> getApi1(@PartMap Map<String, RequestBody> map);

    @POST("api/Activity/get_activities?")
    Observable<BaseModel<List<MainBean>>> getMain(@Query("time") String requestType);
}

5.创建BaseView基类,用于添加自定义回调,根据需求可做扩展,此处只封装了些最为常用的方法(复制粘贴即可使用)

/**
 * File descripition:   基本回调 可自定义添加所需回调
 *
 * @author lp
 * @date 2018/6/19
 */

public interface BaseView {
    /**
     * 显示dialog
     */
    void showLoading();
    /**
     * 隐藏 dialog
     */

    void hideLoading();
    /**
     * 显示错误信息
     *
     * @param msg
     */
    void showError(String msg);
    /**
     * 错误码
     */
    void onErrorCode(BaseModel model);
}

6.创建Presenter基类,提供M层和V层通讯桥梁(复制粘贴即可使用)

/**
 * File descripition:   创建Presenter基类
 *
 * @author lp
 * @date 2018/6/19
 */
public class BasePresenter<V extends BaseView> {
    private CompositeDisposable compositeDisposable;
    public V baseView;
    protected ApiServer apiServer = ApiRetrofit.getInstance().getApiService();

    public BasePresenter(V baseView) {
        this.baseView = baseView;
    }
    /**
     * 解除绑定
     */
    public void detachView() {
        baseView = null;
        removeDisposable();
    }
    /**
     * 返回 view
     *
     * @return
     */
    public V getBaseView() {
        return baseView;
    }

    public void addDisposable(Observable<?> observable, BaseObserver observer) {
        if (compositeDisposable == null) {
            compositeDisposable = new CompositeDisposable();
        }
        compositeDisposable.add(observable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeWith(observer));
    }

    public void removeDisposable() {
        if (compositeDisposable != null) {
            compositeDisposable.dispose();
        }
    }
}

8.实体类基类搭建,有俩个字段,一个是msg,一个是code,一般情况下后台会提供俩个最基本的值来代表各种信息,搭建本框架时,注意修改成和后台字段名一样

import java.io.Serializable;

/**
 * File descripition:   mode基类
 *
 * @author lp
 * @date 2018/6/19
 */
public class BaseModel<T> implements Serializable {
    private String msg;
    private int code;
    private T data;

    public BaseModel(String message, int code) {
        this.msg = message;
        this.code = code;
    }

    public int getErrcode() {
        return code;
    }

    public void setErrcode(int code) {
        this.code = code;
    }

    public String getErrmsg() {
        return msg;
    }

    public void setErrmsg(String message) {
        this.msg = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T result) {
        this.data = result;
    }

    @Override
    public String toString() {
        return "BaseModel{" +
                "code=" + code +
                ", msg='" + msg + '\'' +
                ", result=" + data +
                '}';
    }
}

9.较为重要的一步,数据处理基类,此处处理数据请求成功,开始解析并分发到成功与失败回调

1、onStart方法所处理业务,网络开始请求,我们需要显示一个dialog来让用户感受到数据正在请求,所以,onStart回调我们在BaseView中定义的方法showLoading(),所以

@Override
    protected void onStart() {
        if (view != null) {
            view.showLoading();
        }
    }

2、onNext方法所处理业务,执行到这里,证明网络已经请求成功,这是我们可以让刚才显示的dialog消失,也可以将回调消失的方法放到onComplete中,onNext(T o) 其中o是服务器请求下来的数据,我们开始解析判断BaseModel model = (BaseModel) o;强转成我们需要的类型,有人说强转是不是不好,其实字段名和类型我们已经明确,并且不会有误差,只强转俩个字段code和msg,性能的开销可以忽略不计,属于多态的特性,如果不想强转,Gson解析也是可以的,我们的目的是拿到code值,来判断请求是否成功,如果等于1(假如1是正常请求)将数据赋予abstract void onSuccess(T o),当我们new BaseObserver时候需要重写onSuccess就能拿到对应数据了,如果不是1就回掉BaseView中定义的方法onErrorCode(model ),并将BaseBean给它,这样对应的activity或者fragment也可以拿到code值做相对于的操作

@Override
    public void onNext(T o) {
        try {
            // loading写到这里没有延迟效果
            if (view != null) {
                view.hideLoading();
            }
            BaseModel model = (BaseModel) o;
            if (model.getErrcode() == CODE) {
                onSuccess(o);
            } else {
                if (view != null) {
                    view.onErrorCode(model);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            onError(e.toString());
        }
    }

3、onError方法所处理业务,执行到这个方法,也就是说网络请求失败了,没有拿到服务器返回的值,所以我们需要判断为何失败,是什么异常

@Override
    public void onError(Throwable e) {
        if (view != null) {
            view.hideLoading();
        }
        if (e instanceof HttpException) {
            //   HTTP错误
            onException(BAD_NETWORK, "");
        } else if (e instanceof ConnectException
                || e instanceof UnknownHostException) {
            //   连接错误
            onException(CONNECT_ERROR, "");
        } else if (e instanceof InterruptedIOException) {
            //  连接超时
            onException(CONNECT_TIMEOUT, "");
        } else if (e instanceof JsonParseException
                || e instanceof JSONException
                || e instanceof ParseException) {
            //  解析错误
            onException(PARSE_ERROR, "");
            e.printStackTrace();
        }  else {
            if (e != null) {
                onError(e.toString());
            } else {
                onError("未知错误");
            }
        }
    }

4、onComplete方法所处理业务,代表业务处理完毕,所以说dialog消失写到这里也是可以的

全部代码如下

/**
 * File descripition:   数据处理基类
 *
 * @author lp
 * @date 2018/6/19
 */
public abstract class BaseObserver<T> extends DisposableObserver<T> {
    /**
     * 于服务器约定  返回code为几是正常请求
     */
    public static final int CODE = BaseContent.basecode;
    protected BaseView view;
    /**
     * 网络连接失败  无网
     */
    public static final int NETWORK_ERROR = 100000;
    /**
     * 解析数据失败
     */
    public static final int PARSE_ERROR = 1008;
    /**
     * 网络问题
     */
    public static final int BAD_NETWORK = 1007;
    /**
     * 连接错误
     */
    public static final int CONNECT_ERROR = 1006;
    /**
     * 连接超时
     */
    public static final int CONNECT_TIMEOUT = 1005;
    public BaseObserver(BaseView view) {
        this.view = view;
    }
    @Override
    protected void onStart() {
        if (view != null) {
            view.showLoading();
        }
    }
    @Override
    public void onNext(T o) {
        try {
            // loading写到这里没有延迟效果
            if (view != null) {
                view.hideLoading();
            }
            BaseModel model = (BaseModel) o;
            if (model.getErrcode() == CODE) {
                onSuccess(o);
            } else {
                if (view != null) {
                    view.onErrorCode(model);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            onError(e.toString());
        }
    }
    @Override
    public void onError(Throwable e) {
        if (view != null) {
            view.hideLoading();
        }
        if (e instanceof HttpException) {
            //   HTTP错误
            onException(BAD_NETWORK, "");
        } else if (e instanceof ConnectException
                || e instanceof UnknownHostException) {
            //   连接错误
            onException(CONNECT_ERROR, "");
        } else if (e instanceof InterruptedIOException) {
            //  连接超时
            onException(CONNECT_TIMEOUT, "");
        } else if (e instanceof JsonParseException
                || e instanceof JSONException
                || e instanceof ParseException) {
            //  解析错误
            onException(PARSE_ERROR, "");
            e.printStackTrace();
        }  else {
            if (e != null) {
                onError(e.toString());
            } else {
                onError("未知错误");
            }
        }
    }
    /**
     * 中间拦截一步  判断是否有网络  为确保准确  此步去除也可以
     *
     * @param unknownError
     * @param message
     */
    private void onException(int unknownError, String message) {
        BaseModel model = new BaseModel(message, unknownError);
        if (!NetWorkUtils.isAvailableByPing()) {
            model.setErrcode(NETWORK_ERROR);
            model.setErrmsg("网络不可用,请检查网络连接!");
        }
        onExceptions(model.getErrcode(), model.getErrmsg());
        if (view != null) {
            view.onErrorCode(model);
        }
    }
    private void onExceptions(int unknownError, String message) {
        switch (unknownError) {
            case CONNECT_ERROR:
                onError("连接错误");
                break;
            case CONNECT_TIMEOUT:
                onError("连接超时");
                break;
            case BAD_NETWORK:
                onError("网络超时");
                break;
            case PARSE_ERROR:
                onError("数据解析失败");
                break;
            //网络不可用
            case NETWORK_ERROR:
                onError("网络不可用,请检查网络连接!");
                break;
            default:
                break;
        }
    }
    //loading消失写到这 有一定的延迟  对dialog显示有影响
    @Override
    public void onComplete() {
       /* if (view != null) {
            view.hideLoading();
        }*/
    }
    public abstract void onSuccess(T o);
    public abstract void onError(String msg);
}

至此,请求内部模块已经写完,以下内容为如何请求

**

10.所需请求代码封装到activity基类,这样在activity省略了很多重复代码,对代码的阅读性提升了很多

**

import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import com.lp.mvp_network.base.mvp.BaseModel;
import com.lp.mvp_network.base.mvp.BasePresenter;
import com.lp.mvp_network.base.mvp.BaseView;
import com.lp.mvp_network.promptdialog.PromptDialog;
import com.lp.mvp_network.utils.StatusBarUtil;

import static com.lp.mvp_network.base.mvp.BaseObserver.NETWORK_ERROR;

/**
 * File descripition: activity基类
 * <p>
 *
 * @author lp
 * @date 2018/5/16
 */
public abstract class BaseActivity<P extends BasePresenter> extends AppCompatActivity implements BaseView {
    protected final String TAG = this.getClass().getSimpleName();
    public Context mContext;
    protected P mPresenter;
    protected abstract P createPresenter();
    //错误提示框  警告框  成功提示框 加载进度框 (只是提供个案例 可自定义)
    private PromptDialog promptDialog;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = this;
        setContentView(getLayoutId());
        mPresenter = createPresenter();
        setStatusBar();

        this.initToolbar(savedInstanceState);
        this.initData();
    }
    /**
     * 获取布局ID
     *
     * @return
     */
    protected abstract int getLayoutId();
    /**
     * 处理顶部title
     *
     * @param savedInstanceState
     */
    protected abstract void initToolbar(Bundle savedInstanceState);
    /**
     * 数据初始化操作
     */
    protected abstract void initData();
    /**
     * 此处设置沉浸式地方
     */
    protected void setStatusBar() {
        StatusBarUtil.setTranslucentForImageViewInFragment(this, 0, null);
    }
    /**
     * 封装toast方法(自行去实现)
     *
     * @param str
     */
    public void showToast(String str) {
    }

    public void showLongToast(String str) {
    }
    @Override
    public void showError(String msg) {
        showToast(msg);
    }
    /**
     * 返回所有状态  除去指定的值  可设置所有(根据需求)
     *
     * @param model
     */
    @Override
    public void onErrorCode(BaseModel model) {
        if (model.getErrcode() == NETWORK_ERROR) {

        }
    }
    //显示加载进度框回调
    @Override
    public void showLoading() {
        showLoadingDialog();
    }
    //隐藏进度框回调
    @Override
    public void hideLoading() {
        closeLoadingDialog();
    }
    /**
     * 进度款消失
     */
    public void closeLoadingDialog() {
        if (promptDialog != null) {
            promptDialog.dismiss();
        }
    }
    /**
     * 加载中...
     */
    public void showLoadingDialog() {
        if (promptDialog == null) {
            promptDialog = new PromptDialog(this);
        }
        promptDialog.showLoading("加载中...",false);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mPresenter != null) {
            mPresenter.detachView();
        }
    }
}

11.BaseFragment基类如下

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.lp.mvp_network.base.mvp.BaseModel;
import com.lp.mvp_network.base.mvp.BasePresenter;
import com.lp.mvp_network.base.mvp.BaseView;


/**
 * File descripition:   ftagment 基类
 *
 * @author lp
 * @date 2018/6/19
 */

public abstract class BaseFragment<P extends BasePresenter> extends Fragment implements BaseView {
    public View view;

    public Context mContext;
    protected P mPresenter;

    protected abstract P createPresenter();
//错误提示框  警告框  成功提示框
    public PromptDialog promptDialog;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        view = inflater.inflate(getLayoutId(), container, false);

        mContext = getActivity();
        mPresenter = createPresenter();

        this.initToolbar(savedInstanceState);
        this.initData();

        return view;
    }

    /**
     * 获取布局ID
     *
     * @return
     */
    protected abstract int getLayoutId();

    /**
     * 处理顶部title
     *
     * @param savedInstanceState
     */
    protected abstract void initToolbar(Bundle savedInstanceState);


    /**
     * 数据初始化操作
     */
    protected abstract void initData();

    public void showToast(String str) {
    }

    public void showLongToast(String str) {
    }

    @Override
    public void showError(String msg) {
        showToast(msg);
    }

    @Override
    public void onErrorCode(BaseModel model) {
    }

   @Override
    public void showLoading() {
//        showLoadingDialog();
    }

    @Override
    public void hideLoading() {
        closeLoadingDialog();
    }

    public void closeLoadingDialog() {
        if (mLodingDialog != null && mLodingDialog.isShowing()) {
            mLodingDialog.dismiss();
        }
    }

    /**
     * 加载中...
     */
    public void showLoadingDialog() {
        if (promptDialog == null) {
            promptDialog = new PromptDialog(this);
        }
        promptDialog.showLoading("加载中...",false);
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        this.view = null;
        if (mPresenter != null) {
            mPresenter.detachView();
        }
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
    }
}

以上内容为MVP+Retrofit2+okhttp3+Rxjava2全部封装,其间有些地方需根据自己项目内容所做修改,下边为大家演示下如何在对应activity请求数据

请求时有三个步骤,步骤如下

1.新建接口实体类,注意内容,抛去baseModel里边的内容,也就是抛去每个接口固定返回的字段,如code,message

比如实体类如下

/**
 * File descripition:
 *
 * @author lp
 * @date 2018/9/19
 */
public class MainBean {
    /**
     * id : 11
     * act_logo : http://www.energy-link.com.cn/upload/admin/20180828/s_29a692567d0f0d84d515eb5cf5be98d0.jpg
     * play_time : 2018-06-10
     * name : 中国生物质能源产业联盟会员代表大会
     * province : 北京市
     * city : 西城区
     */
    private int id;
    private String act_logo;
    private String play_time;
    private String name;
    private String province;
    private String city;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getAct_logo() {
        return act_logo;
    }
    public void setAct_logo(String act_logo) {
        this.act_logo = act_logo;
    }

    public String getPlay_time() {
        return play_time;
    }
    public void setPlay_time(String play_time) {
        this.play_time = play_time;
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    public String getProvince() {
        return province;
    }
    public void setProvince(String province) {
        this.province = province;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
}

2.新建对应的接口回调view

import com.lp.mvp_network.base.mvp.BaseModel;
import com.lp.mvp_network.base.mvp.BaseView;
import java.util.List;
/**
 * File descripition:
 *
 * @author lp
 * @date 2018/6/19
 */
public interface MainView extends BaseView {
    void onMainSuccess(BaseModel<List<MainBean>> o);
}

3.新建对应的请求Presenter

import com.lp.mvp_network.base.mvp.BaseModel;
import com.lp.mvp_network.base.mvp.BaseObserver;
import com.lp.mvp_network.base.mvp.BasePresenter;

import java.util.List;

/**
 * File descripition:
 *
 * @author lp
 * @date 2018/6/19
 */

public class MainPresenter extends BasePresenter<MainView> {
    public MainPresenter(MainView baseView) {
        super(baseView);
    }

    public void commentAdd() {
        addDisposable(apiServer.getMain("year"), new BaseObserver(baseView) {
            @Override
            public void onSuccess(Object o) {
                baseView.onMainSuccess((BaseModel<List<MainBean>>) o);
            }

            @Override
            public void onError(String msg) {
                if (baseView != null) {
                    baseView.showError(msg);
                }
            }
        });
    }
}

4.在activity实现Presenter,比如mainActivity

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.lp.mvp_network.R;
import com.lp.mvp_network.base.BaseActivity;
import com.lp.mvp_network.base.mvp.BaseModel;
import java.util.List;
public class MainActivity extends BaseActivity<MainPresenter> implements MainView, View.OnClickListener {
    private TextView tv_msg;
    private Button btn;
    @Override
    protected MainPresenter createPresenter() {
        return new MainPresenter(this);
    }
    @Override
    protected int getLayoutId() {
        return R.layout.activity_main;
    }
    @Override
    protected void initToolbar(Bundle savedInstanceState) {

    }
    @Override
    protected void initData() {
        tv_msg = findViewById(R.id.tv_msg);
        btn = findViewById(R.id.btn);
        btn.setOnClickListener(this);
    }
    @Override
    public void onMainSuccess(BaseModel<List<MainBean>> o) {
        //数据返回
        tv_msg.setText(o.getData().toString());
    }
    @Override
    public void onClick(View v) {
        //数据请求
        mPresenter.commentAdd();
    }
}

后记

问:有人问dialog加载圈封装的不够好,这样每个接口都得显示加载圈,不想实现都不行

答:BaseActivity和BaseFragment中都有这俩个方法

 //显示加载进度框回调
    @Override
    public void showLoading() {
        showLoadingDialog();
    }
    //隐藏进度框回调
    @Override
    public void hideLoading() {
        closeLoadingDialog();
    }

如果说我本页面都不想显示Loading动画,那就在对应的Activity重写下父类的方法,比如

@Override
    public void showLoading() {
    //    super.showLoading();  //将super去掉  就不会显示Loading动画了
    }

如果我们需要显示就在对应的Fragment调用请求方法之后手动掉一下父类的显示Loading方法,如下:

mPresenter.collectApi("id");
 showLoadingDialog();

问:假如接口返回1001,代表重写登录或者token失效,我想在对应activity拿到状态或者做统一操作

答:可以在BaseActivity判断跳页面

//BaseActivity代码
 @Override
    public void onErrorCode(BaseModel model) {
       if (model.getErrcode() == 1001) {
            startLogin();
        }
    }

    private void startLogin() {
        startActivity(LoginActivity.class);
    }

如果想在对应Activity操作,那就在对应Activity重写此方法

//对应Activity代码
 @Override
    public void onErrorCode(BaseModel model) {
        //super.onErrorCode(model);
     if (model.getErrcode()==1001){
            //............................................
        }else if (model.getErrcode()==1002){
                  //............................................
        }
    }

MVP+Retrofit2+okhttp3+Rxjava2网络请求封装完成

github地址:https://github.com/LPTim/MVP-Retrofit2-okhttp3-Rxjava2
csdn地址:https://download.csdn.net/download/loocanp/11229241

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,以下是一个简单的 MVP 框架,包含 Okhttp+Retrofit 网络封装,Base 基类的抽取以及 APPLocation 的代码: 1. 首先创建一个 BaseView 接口,定义一些公共的 UI 操作方法: ```java public interface BaseView { void showLoading(); void hideLoading(); void showError(String error); } ``` 2. 接着创建一个 BasePresenter 类,定义一些公共的 Presenter 操作方法: ```java public class BasePresenter<V extends BaseView> { private WeakReference<V> mViewRef; public void attachView(V view) { mViewRef = new WeakReference<>(view); } public void detachView() { if (mViewRef != null) { mViewRef.clear(); mViewRef = null; } } public boolean isViewAttached() { return mViewRef != null && mViewRef.get() != null; } public V getView() { return mViewRef.get(); } public void checkViewAttached() { if (!isViewAttached()) throw new RuntimeException("Please call attachView() before requesting data to the Presenter"); } } ``` 3. 创建一个 BaseActivity 类,作为所有 Activity 的基类,包含一些公共的操作: ```java public abstract class BaseActivity<P extends BasePresenter> extends AppCompatActivity implements BaseView { protected P mPresenter; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(getLayoutId()); mPresenter = createPresenter(); if (mPresenter != null) { mPresenter.attachView(this); } initView(); } @Override protected void onDestroy() { super.onDestroy(); if (mPresenter != null) { mPresenter.detachView(); } } protected abstract int getLayoutId(); protected abstract P createPresenter(); protected abstract void initView(); } ``` 4. 接着创建一个 BaseFragment 类,作为所有 Fragment 的基类,也包含一些公共的操作: ```java public abstract class BaseFragment<P extends BasePresenter> extends Fragment implements BaseView { protected P mPresenter; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mPresenter = createPresenter(); if (mPresenter != null) { mPresenter.attachView(this); } } @Override public void onDestroy() { super.onDestroy(); if (mPresenter != null) { mPresenter.detachView(); } } protected abstract P createPresenter(); } ``` 5. 创建一个 AppApplication 类,作为整个应用程序的入口,包含一些公共的配置信息和初始化操作: ```java public class AppApplication extends Application { private static AppApplication sInstance; @Override public void onCreate() { super.onCreate(); sInstance = this; // 初始化网络请求 RetrofitClient.getInstance().init(this); } public static AppApplication getInstance() { return sInstance; } } ``` 6. 创建一个 RetrofitClient 类,用于封装 Okhttp+Retrofit 网络请求: ```java public class RetrofitClient { private static final String TAG = "RetrofitClient"; private static final int DEFAULT_TIMEOUT = 30; private Retrofit mRetrofit = null; private OkHttpClient mOkHttpClient = null; private RetrofitClient() {} public static RetrofitClient getInstance() { return SingletonHolder.INSTANCE; } private static class SingletonHolder { private static final RetrofitClient INSTANCE = new RetrofitClient(); } public void init(Context context) { HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); mOkHttpClient = new OkHttpClient.Builder() .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) .addInterceptor(loggingInterceptor) .addInterceptor(new TokenInterceptor()) .build(); mRetrofit = new Retrofit.Builder() .baseUrl(ApiService.BASE_URL) .client(mOkHttpClient) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); } public ApiService getApiService() { return mRetrofit.create(ApiService.class); } } ``` 7. 创建一个 ApiService 接口,定义所有的网络请求接口: ```java public interface ApiService { String BASE_URL = "https://www.example.com/"; @POST("login") Observable<BaseResponse<User>> login(@Query("username") String username, @Query("password") String password); } ``` 8. 最后,我们可以创建一个 LoginPresenter 类,来处理登录相关的业务逻辑: ```java public class LoginPresenter extends BasePresenter<LoginContract.View> implements LoginContract.Presenter { private ApiService mApiService; public LoginPresenter() { mApiService = RetrofitClient.getInstance().getApiService(); } @Override public void login(String username, String password) { checkViewAttached(); getView().showLoading(); mApiService.login(username, password) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<BaseResponse<User>>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(BaseResponse<User> userBaseResponse) { getView().hideLoading(); if (userBaseResponse.getCode() == 0) { getView().loginSuccess(userBaseResponse.getData()); } else { getView().showError(userBaseResponse.getMsg()); } } @Override public void onError(Throwable e) { getView().hideLoading(); getView().showError(e.getMessage()); } @Override public void onComplete() { } }); } } ``` 以上就是一个简单的 MVP 框架的实现,您可以根据自己的需求进行修改和扩展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值