说说我是怎么封装使用Retrofi+Rxjava的

网上都说Retrofit+Rxjava 也又说RxAndroid的 这种网络请求框架好,也有很多实例,但单个的例子毕竟是单个的例子,用到具体的项目里面有成百上千个接口,直接把例子套过来不一定就合适了,需要进行一定的封装用起来才方便。不知道各位高手是怎么用的,我先说说我的简单的封装算是抛砖引玉了,有什么不对的地方欢迎大家批评指正。


1.HttpManager

package com.example.main.net.manager;
import com.example.main.base.BaseApplication;
import com.example.main.finance.bean.AppData;
import com.example.main.net.service.HttpService;
import com.example.main.utils.Constants;
import com.example.main.utils.MD5;
import com.example.main.utils.log.okHttpLog.HttpLoggingInterceptorM;
import com.example.main.utils.log.okHttpLog.LogInterceptor;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;

/**
 * Created by zhougang on 2016/10/19.
 */
public class HttpManager {

    //public static final String BASE_URL = "http://hltm-api.tomoya.cn";
    //请求金融
    public static final String BASE_URL = Constants.JINRONG_ROOT;
    //短缓存有效期为1分钟
    // public static final int CACHE_STALE_SHORT = 60;
    //长缓存有效期为7天
    public static final int CACHE_STALE_LONG = 60 * 60 * 24 * 7;
    //public static final String CACHE_CONTROL_AGE = "Cache-Control: public, max-age=";
    //查询缓存的Cache-Control设置,为if-only-cache时只查询缓存而不会请求服务器,max-stale可以配合设置缓存失效时间
    //  public static final String CACHE_CONTROL_CACHE = "only-if-cached, max-stale=" + CACHE_STALE_LONG;
    //查询网络的Cache-Control设置,头部Cache-Control设为max-age=0时则不会使用缓存而请求服务器
    // public static final String CACHE_CONTROL_NETWORK = "max-age=0";

    private static OkHttpClient mOkHttpClient;
    private volatile static HttpManager INSTANCE;
    private static HttpService sApiService;

    //设置连接超时的值
    private static final int TIMEOUT = 20;

    private HttpManager() {
        initOkHttpClient();
        initRetrofit();
    }

    private void initRetrofit() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(mOkHttpClient)
                .addConverterFactory(CustomGsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();
        sApiService = retrofit.create(HttpService.class);
    }

    public static HttpManager getHttpManager() {
        if (null == INSTANCE) {
            synchronized (HttpManager.class) {
                if (null == INSTANCE) {
                    INSTANCE = new HttpManager();
                }
            }
        }
        return INSTANCE;
    }

    public HttpService getHttpService() {
        return sApiService;
    }

    private void initOkHttpClient() {

//        日志输出拦截器
//        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
//        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

//        格式化的日志输出
        HttpLoggingInterceptorM formattedLoggingInterceptor = new HttpLoggingInterceptorM(new LogInterceptor("OkHttp"));
        formattedLoggingInterceptor.setLevel(HttpLoggingInterceptorM.Level.BODY);

        if (mOkHttpClient == null) {
            synchronized (HttpManager.class) {
                if (mOkHttpClient == null) {
                    //application/json;
                    mOkHttpClient = new OkHttpClient.Builder()
                            .addInterceptor(addHeader)   //Header
//                          .sslSocketFactory(SSLHelper.getSSLCertifcation(BaseApplication.get_context()))//为OkHttp对象设置SocketFactory用于双向认证
                            .addInterceptor(formattedLoggingInterceptor)   // 通过配置拦截器 :在转换成对象前对json字符串进行监控
                            .addInterceptor(addQueryParameterInterceptor)   //公共参数
                            .retryOnConnectionFailure(true)
                            .readTimeout(TIMEOUT, TimeUnit.SECONDS)
                            .writeTimeout(TIMEOUT, TimeUnit.SECONDS)
                            .connectTimeout(TIMEOUT, TimeUnit.SECONDS)
                            .build();
                }
            }
        }

  }

    //Header
    Interceptor addHeader = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request originalRequest = chain.request();
            Request request;
            request = originalRequest.newBuilder()
                    .addHeader("Accept", "application/json")
                    .build();
            return chain.proceed(request);
        }
    };

    //公共参数
    Interceptor addQueryParameterInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request originalRequest = chain.request();
            Request request;
            HttpUrl modifiedUrl = originalRequest.url().newBuilder()
                    .addQueryParameter("tokenId", getToken())
                    .addQueryParameter("sign", getDefaultToken())
                    .addQueryParameter("clientType", getClientType())
                    .addQueryParameter("version", getVersion())
                    .addQueryParameter("timestampApp", str_timeStamp)
                    .build();
            request = originalRequest.newBuilder().url(modifiedUrl).build();
            return chain.proceed(request);

        }
    };

    public Map<String, String> getDefoautParame() {
        Map<String, String> map = new HashMap<String, String>();
        map.put("tokenId", getToken());
        map.put("clientType", getClientType());
        map.put("version", getVersion());
        map.put("timestampApp", getTimeStamp());
        return map;
    }

    private String token_id = "";
    private String str_timeStamp = "";

    private String getToken() {
        token_id = BaseApplication.getApplication().getUserInfo().getTokenId();
        return token_id;
    }

    //tokenId 放在header里面
    Interceptor mTokenInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request originalRequest = chain.request();
            Request authorised = originalRequest.newBuilder()
                    .header("tokenId", getToken())
                    .build();
            return chain.proceed(authorised);
        }
    };

    private String getClientType() {
        return AppData.getInstance().getPlatformName();
    }

    private String getVersion() {
        return AppData.getInstance().getVersiontName();
    }

    private String getTimeStamp() {
        return AppData.getInstance().getTimeData();
    }
}



2. HttpService 
package com.example.main.net.service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Query;
import retrofit2.http.QueryMap;
import rx.Observable;

/**
 * Created by zhoguang on 2016/11/24.
 */
public interface HttpService {

    @GET("member/userLogin")
    Observable<RXBase<LoginBean>> login(@QueryMap Map<String, String> map);

    //    获取产品列表
    @POST("product/list")
    Observable<RXBase<ProductListBean>> getLiCaiList(@Query("pageNum") String pageNo, @Query("pageSize") String pageSize);

    //    获取产品详情
    @GET("product/details")
    Observable<RXBase<ProductDetailBean>> getLiCaiDetail(@Query("id") String ygbMoneyflowId);
 
    //   获取状态
    @GET("fproductApp/ygbMoneyflow/isNew")
    Observable<RXBase<String>> isInvest(@QueryMap Map<String, String> params);
}



3. RXBase
/**
*
*  使用 RxJava+Retrofit网络框架,接收返回值的公用JavaBean
 *
 *    调试一个接口的几个步骤
 *     以获取消息列表为例
 *
 *    1.创建 BMessage (BMessage 只需要包含json串datas字段的的属性(或data数组里的取一个对象的属性)
 *
 *    2.在HttpService里添加请求url:
 *           @GET("a/jlwnotice/jlwNotice/selectNotice")
 *           Observable<RXBase<BMessage>> getMessage(@Query("userid") String userId);
 *
 *    3.在MessageActivity里面发起请求:
 *             HttpManager.getHttpManager().getHttpService().getMessage(userInfo.getUserId())
 *                          .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
 *                          .subscribe(new BaseSubscriber<RXBase<BMessage>>(MassageActivity.this) {
 *                              @Override
 *                              public void onNext(RXBase<BMessage>  rxBase) {
 *                                  ArrayList<BMessage> list = rxBase.getData();
 *                                  if(rxBase.isSuccess() && list!=null && list.size()>0){
 *                                      listMessageItem.addAll(list);
 *                                      mAdapter.notifyDataSetChanged();
 *                                  }
 *                              }
 *                          });
 *
 *
 *
*  @author zhougang
*  @date 2016/12/22 16:36
*
*/
public class RXBase <T> {
    /**
     * 是否成功
     */
    protected boolean isSuccess;

    /**
     * 返回码
     */
    protected int rtnCode;

   protected String rtnMsg;

    protected T datas;

    public boolean isSuccess() {
        return isSuccess;
    }

    public void setSuccess(boolean isSuccess) {
        this.isSuccess = isSuccess;
    }

    public int getRtnCode() {
        return rtnCode;
    }

    public void setRtnCode(int rtnCode) {
        this.rtnCode = rtnCode;
    }

    public String getRtnMsg() {
        return rtnMsg;
    }

    public void setRtnMsg(String rtnMsg) {
        this.rtnMsg = rtnMsg;
    }

    public  T  getDatas() {
        return datas;
    }
}


4.具体的业务Bean(和接口返回的son数据datas节点内的数据对应的),我举个例子,这个接口是获取理财产品列表,我需要一个Bean存放。

 
public class InvestmentBean {
 
    private boolean isNewRecord;
    private String contractId;
    private String contractNumber;
    private String contractName;
    private String userId;
    private String partyA;
    private String guarantor;
    private String contractType;
    private int productId;
    private String productName;
    private String startTime;
    private String endTime;
    private String returnRate;
    private String totalMoney;
    private String surplusMoney;
    private String contractTime;
    private String contractStatus;
    private String contractSort;
    private String orderType;

    public boolean isIsNewRecord() {
        return isNewRecord;
    }

    public void setIsNewRecord(boolean isNewRecord) {
        this.isNewRecord = isNewRecord;
    }

    public String getContractId() {
        return contractId;
    }

    public void setContractId(String contractId) {
        this.contractId = contractId;
    }

    public String getContractNumber() {
        return contractNumber;
    }

    public void setContractNumber(String contractNumber) {
        this.contractNumber = contractNumber;
    }

    public String getContractName() {
        return contractName;
    }

    public void setContractName(String contractName) {
        this.contractName = contractName;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getPartyA() {
        return partyA;
    }

    public void setPartyA(String partyA) {
        this.partyA = partyA;
    }

    public String getGuarantor() {
        return guarantor;
    }

    public void setGuarantor(String guarantor) {
        this.guarantor = guarantor;
    }

    public String getContractType() {
        return contractType;
    }

    public void setContractType(String contractType) {
        this.contractType = contractType;
    }

    public int getProductId() {
        return productId;
    }

    public void setProductId(int productId) {
        this.productId = productId;
    }

    public String getProductName() {
        return productName;
    }

    public void setProductName(String productName) {
        this.productName = productName;
    }

    public String getStartTime() {
        return startTime;
    }

    public void setStartTime(String startTime) {
        this.startTime = startTime;
    }

    public String getEndTime() {
        return endTime;
    }

    public void setEndTime(String endTime) {
        this.endTime = endTime;
    }

    public String getReturnRate() {
        return returnRate;
    }

    public void setReturnRate(String returnRate) {
        this.returnRate = returnRate;
    }

    public String getTotalMoney() {
        return totalMoney;
    }

    public void setTotalMoney(String totalMoney) {
        this.totalMoney = totalMoney;
    }

    public String getSurplusMoney() {
        return surplusMoney;
    }

    public void setSurplusMoney(String surplusMoney) {
        this.surplusMoney = surplusMoney;
    }

    public String getContractTime() {
        return contractTime;
    }

    public void setContractTime(String contractTime) {
        this.contractTime = contractTime;
    }

    public String getContractStatus() {
        return contractStatus;
    }

    public void setContractStatus(String contractStatus) {
        this.contractStatus = contractStatus;
    }

    public String getContractSort() {
        return contractSort;
    }

    public void setContractSort(String contractSort) {
        this.contractSort = contractSort;
    }

    public String getOrderType() {
        return orderType;
    }

    public void setOrderType(String orderType) {
        this.orderType = orderType;
    }
}



5.BaseSubscriber
import android.content.Context;
import android.widget.Toast;

import java.net.ConnectException;
import java.net.SocketTimeoutException;

import rx.Subscriber;

/**
 * Created by zhougang on 2016/11/24.
 */
public abstract class BaseSubscriber<T> extends Subscriber<T> {

    Context context;

    public BaseSubscriber( Context context) {
        this.context = context;
    }

    @Override
    public void onStart() {
//        Toast.makeText(context,"开始请求数据...",Toast.LENGTH_LONG).show();
    }

    /**
     * 完成
     */
    @Override
    public void onCompleted() {
//        Toast.makeText(context, "onCompleted()....", Toast.LENGTH_SHORT).show();
    }

    /**
     * 对错误进行统一处理
     * @param e
     */
    @Override
    public void onError(Throwable e) {
        if (e instanceof SocketTimeoutException) {
            Toast.makeText(context, "网络中断,请检查您的网络状态", Toast.LENGTH_SHORT).show();
        } else if (e instanceof ConnectException) {
            Toast.makeText(context, "网络中断,请检查您的网络状态", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(context, "error:" + e.getMessage(), Toast.LENGTH_SHORT).show();
        }

    }

    @Override
    public abstract void onNext(T t);
}
6.Activity里调用
    public void getListData(final int page) {
        showViewLoading(true);
        Map<String, String> map = new HashMap<>();
        map.put("productId", productId);
        map.put("pageNo", page + "");
        map.put("pageSize", "20");

        HttpManager.getHttpManager().getHttpService() .getFinanceInvestList(map) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) 
.subscribe(new BaseSubscriber<RXBase<ArrayList<InvestmentBean>>>(InvestmentHistoryActivity.this) {
                    @Override
                    public void onNext(RXBase<ArrayList<InvestmentBean>> bean) {
                        showViewLoading(false);
                        investment_refresh.refreshSuccess();
                        if (bean.getRtnCode() == 100) {
                           list.addAll(bean.getDatas());
                          
                        } else {
                            ToastUtil.ShowToastCommon(InvestmentHistoryActivity.this, bean.getRtnMsg(), 1);
                        }
                    }
                    @Override
                    public void onError(Throwable e) {
                        showViewLoading(false);
                        super.onError(e);
                    }
                });
    }



6. HttpManager的一些处理技巧 
   我给我的OkHttpClient添加了一些拦截器:
.addInterceptor(formattedLoggingInterceptor)   // 通过配置拦截器 :在转换成对象前对json字符串进行监控,打印返回数据
.addInterceptor(addQueryParameterInterceptor)   //公共参数
刚开始使用Retrofit最烦恼的就是log里面看不到返回的数据,只能调试看,很麻烦,后来知道了可以使用拦截器打印日志。这里面我为了更方便的查看日志,我使用了大神提供
的一个带格式的json日志打印的控件Android 网络框架 HttpLoggingInterceptor优化
  
另外,有的地方服务器端由于种种原因返回的json有点小瑕疵,不符合resultful要求,服务器端说改起来有困难,我也是个不愿意勉强被人的人,与其多费口舌,不如自己修改一下。
   
 private void initRetrofit() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(mOkHttpClient)
                .addConverterFactory(CustomGsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();
        sApiService = retrofit.create(HttpService.class);
    }

package com.example.main.net.manager;

import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;

public final class CustomGsonConverterFactory extends Converter.Factory {
    /**
     * Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
     * decoding from JSON (when no charset is specified by a header) will use UTF-8.
     */
    public static CustomGsonConverterFactory create() {
        return create(new Gson());
    }

    /**
     * Create an instance using {@code gson} for conversion. Encoding to JSON and
     * decoding from JSON (when no charset is specified by a header) will use UTF-8.
     */
    public static CustomGsonConverterFactory create(Gson gson) {
        return new CustomGsonConverterFactory(gson);
    }

    private final Gson gson;

    private CustomGsonConverterFactory(Gson gson) {
        if (gson == null) throw new NullPointerException("gson == null");
        this.gson = gson;
    }

    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
                                                            Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new CustomGsonResponseBodyConverter<>(gson, adapter);
    }

    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type,
                                                          Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new CustomGsonRequestBodyConverter<>(gson, adapter);
    }
}
CustomGsonRequestBodyConverter
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;

public final class CustomGsonConverterFactory extends Converter.Factory {
    /**
     * Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
     * decoding from JSON (when no charset is specified by a header) will use UTF-8.
     */
    public static CustomGsonConverterFactory create() {
        return create(new Gson());
    }

    /**
     * Create an instance using {@code gson} for conversion. Encoding to JSON and
     * decoding from JSON (when no charset is specified by a header) will use UTF-8.
     */
    public static CustomGsonConverterFactory create(Gson gson) {
        return new CustomGsonConverterFactory(gson);
    }

    private final Gson gson;

    private CustomGsonConverterFactory(Gson gson) {
        if (gson == null) throw new NullPointerException("gson == null");
        this.gson = gson;
    }
    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
                                                            Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new CustomGsonResponseBodyConverter<>(gson, adapter);
    }

    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type,
                                                          Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new CustomGsonRequestBodyConverter<>(gson, adapter);
    }
}

CustomGsonResponseBodyConverter

import com.google.gson.Gson;
import com.google.gson.TypeAdapter;

import java.io.IOException;
import okhttp3.ResponseBody;
import retrofit2.Converter;

/**
 * 过滤掉不符合规定的json(很重要)
 *
 * Created by zhougang on 2017/1/9
 */
public class CustomGsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
    private final Gson gson;
    private final TypeAdapter<T> adapter;

    CustomGsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
        this.gson = gson;
        this.adapter = adapter;
    }

    @Override public T convert(ResponseBody value) throws IOException {
//      JsonReader jsonReader = gson.newJsonReader(value.charStream());
        try {
            //正常情况下返回的可能是对象或是数组,没有值的情况下却返回一个空字符串,解析会有问题,这里做一下处理。将 ‘ "data":"",’ 直接去掉
            String str1 = "\"data\":"+"\"\",";
            String str2 = "";
            return adapter.fromJson(value.string().replace(str1,str2).replace("\\","").replace("\"{","{").replace("}\"","}"));
        } finally {
            value.close();
        }
    }
}

几个需要注意到的地方注意到RXBase里面datas那个泛型,使得我们的datas 参数可以接收字符串,数组,对象。HttpService里面,调用的时候都要注意这个Obsavable里面的参数类型。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值