Retrofit+RxJava2的封装使用

公司上个项目用的是rxjava1.0,最近看了各种rxjava2.0的介绍,自己也摸索着来,所以打算封装一下,用到项目中,与时俱进嘛!先不多逼逼了,直截了当,上货......
先看一下关于怎么配置Retrofit,这个大家都差不多,就不多解释了。。。base_url直接换成自己公司服务器的地址就可以了
github地址:https://github.com/Veken/RxJava2Retrofit
1 封装

Retrofit配置类 
/**
 * Retrofit配置
 */
public class RetrofitConnect {
    private Retrofit retrofit;
    private Service service;
    /**
     * 网络请求超时时间毫秒
     */
    int DEFAULT_TIMEOUT = 20000;

    /**
     *   你们公司自己的服务器地址
     */
    public static String BASE_URL = "";

    private RetrofitConnect() {
       /* HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);*/

        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
            @Override
            public void log(String message) {
                try {
                    String text = URLDecoder.decode(message, "utf-8");
                    LogUtils.e("OKHttp-----", text);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                    LogUtils.e("OKHttp-----", message);
                }
            }
        });
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        File cacheFile = new File(Utils.getContext().getCacheDir(), "cache");
        Cache cache = new Cache(cacheFile, 1024 * 1024 * 100); //100Mb

        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .readTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)
                .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)
                .addInterceptor(interceptor)
                .addNetworkInterceptor(new HttpCacheInterceptor())
                .cache(cache)
                .build();

        Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").serializeNulls().create();

        retrofit = new Retrofit.Builder()
                .client(okHttpClient)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .baseUrl(BASE_URL)
                .build();
        service = retrofit.create(Service.class);
    }

    //  创建单例
    private static class SingletonHolder {
        private static final RetrofitConnect INSTANCE = new RetrofitConnect();
    }
    public static Service getApiService() {
        return SingletonHolder.INSTANCE.service;
    }

    class HttpCacheInterceptor implements Interceptor {

        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            if (!NetworkUtils.isConnected()) {  //没网强制从缓存读取
                request = request.newBuilder()
                        .cacheControl(CacheControl.FORCE_CACHE)
                        .build();
                LogUtils.d("Okhttp", "no network");
            }


            Response originalResponse = chain.proceed(request);
            if (NetworkUtils.isConnected()) {
                //有网的时候读接口上的@Headers里的配置,你可以在这里进行统一的设置
                String cacheControl = request.cacheControl().toString();
                return originalResponse.newBuilder()
                        .header("Cache-Control", cacheControl)
                        .removeHeader("Pragma")
                        .build();
            } else {
                return originalResponse.newBuilder()
                        .header("Cache-Control", "public, only-if-cached, max-stale=2419200")
                        .removeHeader("Pragma")
                        .build();
            }
        }
    }
}

接下来第一步封装,把请求的一些网络线程等等封装在一个类SubScriberHandler里面
并且把post请求的参数进行sha加密,参数可以根据公司自己的要求,自己更改

public class SubScriberHandler {

    /**
     * @param o
     * @param <T>
     */
    public <T> void toSubscribe(Observable<T> o, DefaultObserver observer) {
        o.subscribeOn(Schedulers.io())      //网络耗时操作在io线程处理
                .unsubscribeOn(Schedulers.io()) //网络耗时操作在io线程处理
                .observeOn(AndroidSchedulers.mainThread())  //更新数据在主线程
                .subscribe(observer);
    }

    /**
     * 添加共同参数 SHA1加密
     * @param fields
     */
    public void handleFields(Map<String, Object> fields) {
        fields.put("appKey", "00001");
        fields.put("v", "1.0");
        String sessionId = SpConfig.getInstance().getString(Constants.SESSIONID_STRING);
        if(!TextUtils.isEmpty(sessionId))
            fields.put(Constants.SESSIONID_STRING, sessionId);

        String sha1 = null;
        try {
            sha1 = SHA1.SHA1(fields);
        } catch (DigestException e) {
            e.printStackTrace();
        }
        fields.put("sign", sha1);
    }
}

接下来是关于自定义的实现Observer的类DefalutObserver,同时也添加了一个加载数据时候的progressdialog,可以根据公司的需求更改成自己的progressdialog,我这只是简单的调用普通的。各位客官也可以自己看心情来封装

**
 * @author Veken
 */
public abstract class DefaultObserver<T extends BaseRespond> implements Observer<T>,ProgressCancelListener {
    private Context context;
    private boolean isAddInStop = false;
    private ProgressDialogHandler mProgressDialogHandler;
    //取消订阅
    private Disposable mDisposable;

    public DefaultObserver(Context context, boolean isShowLoading) {
        this.context = context;
        mProgressDialogHandler = new ProgressDialogHandler(context,this,true);
        if (isShowLoading) {
            showProgressDialog();
        }
    }

    private void showProgressDialog(){
        if (mProgressDialogHandler != null) {
            mProgressDialogHandler.obtainMessage(ProgressDialogHandler.SHOW_PROGRESS_DIALOG).sendToTarget();
        }
    }

    private void dismissProgressDialog(){
        if (mProgressDialogHandler != null) {
            mProgressDialogHandler.obtainMessage(ProgressDialogHandler.DISMISS_PROGRESS_DIALOG).sendToTarget();
            mProgressDialogHandler = null;
        }
    }

    @Override
    public void onSubscribe(Disposable d) {
        mDisposable =d;
    }

    @Override
    public void onNext(T response) {
        dismissProgressDialog();
        if (response.getResCode().equals("200")) {
            onSuccess(response);
        } else {
            onFail(response);
        }
    }


    @Override
    public void onError(Throwable e) {
        LogUtils.e("Retrofit", e.getMessage());
//        dismissProgress();
        dismissProgressDialog();
        if (e instanceof HttpException) {     //   HTTP错误
            onException(ExceptionReason.BAD_NETWORK);
        } else if (e instanceof ConnectException
                || e instanceof UnknownHostException) {   //   连接错误
            onException(ExceptionReason.CONNECT_ERROR);
        } else if (e instanceof InterruptedIOException) {   //  连接超时
            onException(ExceptionReason.CONNECT_TIMEOUT);
        } else if (e instanceof JsonParseException
                || e instanceof JSONException
                || e instanceof ParseException) {   //  解析错误
            onException(ExceptionReason.PARSE_ERROR);
        } else {
            onException(ExceptionReason.UNKNOWN_ERROR);
        }
    }

    @Override
    public void onComplete() {
        dismissProgressDialog();
    }

    /**
     * 请求成功
     *
     * @param response 服务器返回的数据
     */
    abstract public void onSuccess(T response);

    /**
     * 服务器返回数据,但响应码不为200
     *
     * @param response 服务器返回的数据
     */
    public void onFail(T response) {
        String message = response.getResDesc();
        if (TextUtils.isEmpty(message)) {
            ToastUtils.show(R.string.response_return_error);
        } else {
            ToastUtils.show(message);
        }
    }

    /**
     * 请求异常
     *
     * @param reason
     */
    public void onException(ExceptionReason reason) {
        switch (reason) {
            case CONNECT_ERROR:
                ToastUtils.show(R.string.connect_error, Toast.LENGTH_SHORT);
                break;

            case CONNECT_TIMEOUT:
                ToastUtils.show(R.string.connect_timeout, Toast.LENGTH_SHORT);
                break;

            case BAD_NETWORK:
                ToastUtils.show(R.string.bad_network, Toast.LENGTH_SHORT);
                break;

            case PARSE_ERROR:
                ToastUtils.show(R.string.parse_error, Toast.LENGTH_SHORT);
                break;

            case UNKNOWN_ERROR:
            default:
                ToastUtils.show(R.string.unknown_error, Toast.LENGTH_SHORT);
                break;
        }
    }

    /**
     * 请求网络失败原因
     */
    public enum ExceptionReason {
        /**
         * 解析数据失败
         */
        PARSE_ERROR,
        /**
         * 网络问题
         */
        BAD_NETWORK,
        /**
         * 连接错误
         */
        CONNECT_ERROR,
        /**
         * 连接超时
         */
        CONNECT_TIMEOUT,
        /**
         * 未知错误
         */
        UNKNOWN_ERROR,
    }

    /**
     * 取消ProgressDialog的时候,取消对observable的订阅,同时也取消了http请求
     */
    @Override
    public void onCancelProgress() {
        if (!mDisposable.isDisposed()) {
            mDisposable.dispose();
        }
    }
}

现在就是大家耳熟能详的Service类,这就没什么可说的,你要什么请求,就是什么,比如你要登录就写一个login的service,然后Map中装你需要请求的参数,以此类推。

/**
 * @author Veken
 */
public interface Service {


    /**
     * 登录的service
     * @param fields
     * @return
     */
    @FormUrlEncoded
    @POST(Constants.URLEND)
    Observable<LoginRespond> login(@FieldMap Map<String, Object> fields);

}

现在到了正儿八经的封装了,前面的都是开胃菜,配置都差不多,大同小异,到上真货的时候了

public class UserInfoRequest extends SubScriberHandler {

    private UserInfoBean userInfoBean;
    private Context context;

    public UserInfoRequest(Context context,UserInfoBean userInfoBean) {
        this.context = context;
        this.userInfoBean = userInfoBean;
    }

    public void login() {

        Map<String, Object> fields = new HashMap<>();
        //调用的接口方法,比如login方法
        fields.put("method", "user.login");
        //加密和传一些常用参数
        handleFields(fields);
        //需要传递的参数
        fields.put("phoneNo", userInfoBean.getPhoneNum());
        fields.put("password", userInfoBean.getPwd());
        //申请网络
        Observable observable = RetrofitConnect.getApiService().login(fields);
        toSubscribe(observable, new DefaultObserver(context,true) {
            //数据返回在onNext
            @Override
            public void onSuccess(BaseRespond response) {
            }

           //数据返回
            @Override
            public void onNext(@NonNull BaseRespond response) {
                //将结果封装在javabean的onSuccess方法里面
                userInfoBean.onSuccess(response);
            }

            @Override
            public void onError(Throwable e) {
                super.onError(e);
                userInfoBean.onError(e);
            }
        });
    }

}

2 调用
下面就是具体调用了,看一下在MainActivity中怎么简单的调用吧
实现UserInfoBean,这样可以在重写的方法中传入我们需要的参数,当然也可以不写一个bean,直接用String传也可以,但是习惯了bean,数据处理也在bean中,简单明了。
初始化你的UserInfoPresent网络请求
private UserInfoRequest userInfoRequest;
userInfoRequest= new UserInfoRequest(this,this);
如果没有实现bean的话,UserInfoPresent()方法中的参数会报错,如果不想调用bean,可以自己简单的修改一下
剩下的就简单了,在自己想要请求网络的地方,调用 userInfoPresent.login();一句代码就可以了

public class MainActivity extends BaseActivity implements UserInfoBean {
    private Button btn;
    private UserInfoRequest userInfoRequest;
    private TextView tv;

    @Override
    protected int getLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    protected void initData(Bundle savedInstanceState) {
    }

    @Override
    protected void initView() {
        btn = (Button) findViewById(R.id.btn);
        tv = (TextView) findViewById(R.id.tv);
        userInfoRequest= new UserInfoRequest(this,this);

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                userInfoRequest.login();
            }
        });
    }

    //传递的用户
    @Override
    public String getPhoneNum() {
        //根据需要,传递相应的数据
        return "登录账号";
    }

    //传递的密码
    @Override
    public String getPwd() {
        //根据需要,传递相应的数据
        return "登录密码";
    }

    //数据返回
    @Override
    public void onSuccess(Object object) {
        LoginRespond loginRespond = (LoginRespond) object;
        Log.d("登录信息:", loginRespond.getResDesc());
        tv.setText(loginRespond.getData().getTelphone());
    }

    @Override
    public void onError(Throwable e) {

    }
}

想必有老铁就问了,如果一个界面有多处需要请求网络的,那该怎么办呢?
因为我们是通过实现javabean的方法,java是单继承,多实现吗。这不就清楚了
当然你还可以直接使用

 Map<String, Object> fields = new HashMap<>();
        //调用的接口方法,比如login方法
        fields.put("method", "user.login");
        //加密和传一些常用参数
        handleFields(fields);
        //传递需要传递的参数
        fields.put("phoneNo", userInfoBean.getPhoneNum());
        fields.put("password", userInfoBean.getPwd());
        //申请网络
        Observable observable = RetrofitConnect.getApiService().login(fields);
        toSubscribe(observable, new DefaultObserver(context,true) {
            //数据返回在onNext
            @Override
            public void onSuccess(BaseRespond response) {
            }

            @Override
            public void onNext(@NonNull BaseRespond response) {
                userInfoBean.onSuccess(response);
            }

            @Override
            public void onError(Throwable e) {
                super.onError(e);
                userInfoBean.onError(e);
            }
        });

初始化UserInfoRequest,就可以了。
还有很多不足的地方,希望各位老爷批评指正,大家共同进步,自己项目实战过的,不是demo,所以可以直接拿来用,有什么问题,还烦请指教、、、
PS:没有用到太多的RxJava的操作符,刚接触,还不是很熟悉,还不会灵活运用,见谅!!!
在这里要感谢那些为我们分享贡献的前辈,感谢他们的辛勤耕耘,才有我们菜鸟的不断进步。
特此感谢:
用水管讲解rxjava和retroft使用的:http://www.jianshu.com/p/464fa025229e
以及这位前辈提供的demo参考:https://github.com/zhpanvip/Retrofit2

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335