Retrofit+RxJava+OkHttp项目中的使用
近來比較火的網絡框架,自己項目中已經使用了,
1.Retrofit簡單的一句話就是通過通過代理方式和注解轉換成一個serviceMethod然后調用callFactory執行的okhttp3.Callt得到返回的數據serviceMethod.callAdapter.adapt(okHttpCall)來產生method所定義的返回值。
簡單使用
| @Path | GET | 用于替換Url路徑中的變量字符 |
| @Query | GET | 用于拼接在Url路徑后的查詢參數,但相對于直接在Url后拼接,@Query則是添加一個變量 |
| @QueryMap | GET | 效果等同于多個@Query 參數為Map類型 |
| @FormUrlEncoded/@Field | POST | @FormUrlEncoded修飾表單域,每個表單域子件key-value采用@Field修飾 |
| @Body | POST | 可以指定一個對象作為HTTP請求體@Body |
| @FormUrlEncoded/@Field | PUT | @FormUrlEncoded修飾表單域,每個表單域子件key-value采用@Field修飾 |
| @HTTP/@Body | DELETE | @HTTP修飾表單域,以指定一個對象作為HTTP請求體@Body,此時表單域一定要寫上hasBody = true |
| @Multipart/@Part或者@PartMap | POST | 文件上傳使用,@Multipart修飾表單域,參數@Part修飾或者參數使用@PartMap |
上面就是常用的注解
第一步
創建retrofit 對像
?private static Retrofit getRetrofit() {
? ? ? ? if (retrofit == null) {
? ? ? ? ? ? synchronized (Http.class) {
? ? ? ? ? ? ? ? if (retrofit == null) {
? ? ? ? ? ? ? ? ? ? //添加一個log攔截器,打印所有的log
? ? ? ? ? ? ? ? ? ? HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
? ? ? ? ? ? ? ? ? ? //可以設置請求過濾的水平,body,basic,headers
? ? ? ? ? ? ? ? ? ? httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
? ? ? ? ? ? ? ? ? ? //設置 請求的緩存的大小跟位置
? ? ? ? ? ? ? ? ? ? File cacheFile = new File(MyApplication.getInstance().getmContext().getCacheDir(), "cache");
? ? ? ? ? ? ? ? ? ? Cache cache = new Cache(cacheFile, 1024 * 1024 * 50); //50Mb 緩存的大小
? ? ? ? ? ? ? ? ? ? client = new OkHttpClient
? ? ? ? ? ? ? ? ? ? ? ? ? ? .Builder()
? ? ? ? ? ? ? ? ? ? ? ? ? ? .addInterceptor(addQueryParameterInterceptor())? //參數添加
? ? ? ? ? ? ? ? ? ? ? ? ? ? .addInterceptor(addHeaderInterceptor()) // token過濾
? ? ? ? ? ? ? ? ? ? ? ? ? ? .addInterceptor(httpLoggingInterceptor) //日志,所有的請求響應度看到
? ? ? ? ? ? ? ? ? ? ? ? ? ? .addInterceptor(addCacheInterceptor())//緩存信息
? ? ? ? ? ? ? ? ? ? ? ? ? ? .cache(cache)? //添加緩存
? ? ? ? ? ? ? ? ? ? ? ? ? ? .connectTimeout(12, TimeUnit.SECONDS)
? ? ? ? ? ? ? ? ? ? ? ? ? ? .readTimeout(12, TimeUnit.SECONDS)
? ? ? ? ? ? ? ? ? ? ? ? ? ? .writeTimeout(12, TimeUnit.SECONDS)
? ? ? ? ? ? ? ? ? ? ? ? ? ? .build();
? ? ? ? ? ? ? ? ? ? // 獲取retrofit的實例
? ? ? ? ? ? ? ? ? ? retrofit = new Retrofit
? ? ? ? ? ? ? ? ? ? ? ? ? ? .Builder()
? ? ? ? ? ? ? ? ? ? ? ? ? ? .baseUrl(UrlHelper.BASE_URL)? //自己配置
? ? ? ? ? ? ? ? ? ? ? ? ? ? .client(client)
? ? ? ? ? ? ? ? ? ? ? ? ? ? .addConverterFactory(ResponseConverterFactory.create())
? ? ? ? ? ? ? ? ? ? ? ? ? ? .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
? ? ? ? ? ? ? ? ? ? ? ? ? ? .build();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return retrofit;
? ? }
?在這一步的時候你可以常用信息放在里面作為頭部信息,在這里用到了單例模式.
第三步
?創建api 接口
加上@GET 標簽,標簽后面是這個接口的 尾址sign/login,完整的地址應該是 baseUrl+尾址 ,參數 使用@Query標簽,如果參數多的話可以用@QueryMap標 簽,接收一個Map。
常見的post請求和GET請求方式,如果要傳的表單形式記得要加上?@Multipart 同時注解里面@Part List<MultipartBody.Part> partList 這種方式就是常見的圖片和文字上傳。
從第二步可以看出創建http請求類,并在里面初始化并配置Retrofit和OkHttp: 同時采用建造者模式添加攔截比如addQueryParameterInterceptor(),addHeaderInterceptor(),
addQueryParameterInterceptor()類中:
這里設置基本信息,當hain.proceed(request)時表示進行okhttp下一步操作
addHeaderInterceptor()
設置頭的基本信息。
第四步進行數據返回,在返回時做些處理重新ResponseConverterFactory extends Converter.Factory 為什么處理呢?因為后臺返回來的數據有時返回有問題,
然后?通過GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> 這樣子的話我直接可以得到返回的值。
public class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
? ? private final Type type;
? ? public GsonResponseBodyConverter(Gson gson, Type type) {
? ? ? ? this.type = type;
? ? }
? ? /**
? ? ?* @param value
? ? ?* @return
? ? ?* @throws IOException
? ? ?*/
? ? @Override
? ? public T convert(ResponseBody value) {
? ? ? ? int? errorCode=0;
? ? ? ? String? errorMesage="";
? ? ? ? try {
? ? ? ? ? ? String result = value.string();
? ? ? ? ? ? JSONObject jsonObject = new JSONObject(result);
? ? ? ? ? ? if (ConstantUrl.IS_DENCRYPT) {
? ? ? ? ? ? ? ? String datas = jsonObject.optString("sign");
? ? ? ? ? ? ? ? if(jsonObject.optInt("error_code") != ConstantUrl.error_code1){
? ? ? ? ? ? ? ? ? ? jsonObject = new JSONObject(AESUtils.decrypt(datas));
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? if ((jsonObject.optInt("error_code") ==ConstantUrl.error_code3)||(jsonObject.optInt("error_code") == ConstantUrl.error_code2)) {
? ? ? ? ? ? ? ? String data = jsonObject.optString("data");
? ? ? ? ? ? ? ? //常規數據請求接口數據
? ? ? ? ? ? ? ? if (!TextUtils.isEmpty(data) && !data.equals("null")) {
? ? ? ? ? ? ? ? ? ? if(type != String.class){
? ? ? ? ? ? ? ? ? ? ? ? return new Gson().fromJson(data,type);
? ? ? ? ? ? ? ? ? ? }else{
? ? ? ? ? ? ? ? ? ? ? ? return (T)data;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? //data里面沒有數據
? ? ? ? ? ? ? ? ? ? errorCode=jsonObject.optInt("error_code");
? ? ? ? ? ? ? ? ? ? errorMesage=jsonObject.optString("error_message");
? ? ? ? ? ? ? ? ? ? throw new ResultException(jsonObject.optInt("error_code"), jsonObject.optString("error_message"));
? ? ? ? ? ? ? ? }
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? //ErrResponse 將msg解析為異常消息文本
? ? ? ? ? ? ? ? errorCode=jsonObject.optInt("error_code");
? ? ? ? ? ? ? ? errorMesage=jsonObject.optString("error_message");
? ? ? ? ? ? ? ? throw new ResultException(jsonObject.optInt("error_code"), jsonObject.optString("error_message"));
? ? ? ? ? ? }
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? throw new ResultException(0, UiUtils.getString(R.string.httpSubmitContextNull));
? ? ? ? } catch (JSONException e) {
? ? ? ? ? ? throw new ResultException(0, UiUtils.getString(R.string.JsonSyntaxException));
? ? ? ? } catch (RuntimeException e) {
? ? ? ? ? ? ErrResponse errResponse = new ErrResponse();
? ? ? ? ? ? errResponse.setMsg(UiUtils.getString(R.string.systemExpire));
? ? ? ? ? ? throw new ResultException(errorCode, errorMesage);
? ? ? ? }
? ? }
通過gson 方式把數據轉換成自己想要的,這個時候自己定義Exception處理類,
數據返回第二步 通過Rxjava把數據帶回,Exception處理分為2部分,本身Exception和服務器返回的Exception,
分開處理,
public abstract class AbsAPICallback<T> extends Subscriber<T> {
? ? protected? Context mContext;
? ? private ProgressBarDialog dialog = null;
? ? public? AbsAPICallback(Context context,boolean isLoadProgress) {
? ? ? ? this.mContext = context;
? ? ? ? if(isLoadProgress && dialog == null){
? ? ? ? ? ? dialog = new ProgressBarDialog(context);
? ? ? ? }
? ? ? ? if(isLoadProgress && dialog!=null){
? ? ? ? ? ? dialog.showProgress();
? ? ? ? }
? ? }
? ? @Override
? ? public void onError(Throwable e) {
? ? ? ? if(dialog!=null&&dialog.isShowing()){
? ? ? ? ? ? dialog.closeProgress();
? ? ? ? }
? ? ? ? Log.e("e","httpException = " +e);
? ? ? ? Throwable throwable = e;
? ? ? ? //獲取最根源的異常
? ? ? ? while (throwable.getCause() != null) {
? ? ? ? ? ? e = throwable;
? ? ? ? ? ? throwable = throwable.getCause();
? ? ? ? }
? ? ? ? if (e instanceof HttpException) {//HTTP錯誤
? ? ? ? ? ? HttpException httpException = (HttpException) e;
? ? ? ? ? ? switch (httpException.code()) {
? ? ? ? ? ? ? ? case IntegerUtil.ABS_UNAUTHORIZED:
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? case IntegerUtil.ABS_FORBIDDEN:
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? case IntegerUtil.ABS_NOT_FOUND:
? ? ? ? ? ? ? ? ? ? ToastUtil.showShort(UiUtils.getString(R.string.noNetWork));
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? case IntegerUtil.ABS_REQUEST_TIMEOUT:
? ? ? ? ? ? ? ? ? ? ToastUtil.showShort(UiUtils.getString(R.string.timeout));
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? case IntegerUtil.ABS_GATEWAY_TIMEOUT:
? ? ? ? ? ? ? ? ? ? ToastUtil.showShort(UiUtils.getString(R.string.timeout));
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? case IntegerUtil.ABS_INTERNAL_SERVER_ERROR:
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? case IntegerUtil.ABS_BAD_GATEWAY:
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? case IntegerUtil.ABS_SERVICE_UNAVAILABLE:
? ? ? ? ? ? ? ? ? ? ToastUtil.showShort(UiUtils.getString(R.string.unavailable));
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? default:
? ? ? ? ? ? ? ? ? ? LogUtils.d(UiUtils.getString(R.string.InternalServerError));
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? } else if (e instanceof SocketTimeoutException) {
? ? ? ? ? ? String message = UiUtils.getString(R.string.timeout);
? ? ? ? ? ? ToastUtil.showShort(message);
? ? ? ? ? ? ResultException resultException = new ResultException(0,message);
? ? ? ? ? ? onResultError(resultException);
? ? ? ? } else if (e instanceof ResultException) {//服務器返回的錯誤
? ? ? ? ? ? ResultException resultException = (ResultException) e;
? ? ? ? ? ? switchError(resultException);
? ? ? ? } else if (e instanceof JsonParseException || e instanceof JSONException || e instanceof ParseException) {
? ? ? ? ? ? LogUtils.d(UiUtils.getString(R.string.JsonSyntaxException));
? ? ? ? } else if(e instanceof ConnectException){
? ? ? ? ? ? String message = UiUtils.getString(R.string.noNetWork);
? ? ? ? ? ? ToastUtil.showShort(message);
? ? ? ? ? ? ResultException resultException = new ResultException(0,message);
? ? ? ? ? ? onResultError(resultException);
? ? ? ? }
? ? }
? ? /**
? ? ?* 服務器返回的錯誤
? ? ?*/
? ? protected abstract void onResultError(ResultException ex);
? ? protected abstract void onDone(T t);
? ? @Override
? ? public void onCompleted() {
? ? }
? ? private ConfirmDialog comfirmDialog;
? ? private void switchError(ResultException resultException){
? ? ? ? switch (resultException.getErrCode()){
? ? ? ? ? ? case IntegerUtil.ABS_TOKEN_FAIL://您的賬號登錄異常,請重新登錄!
? ? ? ? ? ? ? ? ToastUtil.showShort(UiUtils.getString(R.string.tokenVerifyFail));
? ? ? ? ? ??
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case IntegerUtil.ABS_TOKEN_EXPIRE://您的賬號已過期,為確保信息安全,請重新登錄!
? ? ? ? ? ? ? ? FragmentManager mamage = ((AppCompatActivity) mContext).getSupportFragmentManager();
? ? ? ? ? ? ? ? if(comfirmDialog==null)
? ? ? ? ? ? ? ? ? ? comfirmDialog = ConfirmDialog.newInstance("", UiUtils.getString( R.string.tokenVerifyExpire) , "稍后再說", "立即登錄");
? ? ? ? ? ? ? ? if(comfirmDialog.isVisible())
? ? ? ? ? ? ? ? ? ? return;
? ? ? ? ? ? ? ? comfirmDialog.setMargin(60)
? ? ? ? ? ? ? ? ? ? ? ? .setWidth(SystemInfoUtil.getScreenWidth()*2/3)
? ? ? ? ? ? ? ? ? ? ? ? .setOutCancel(false)
? ? ? ? ? ? ? ? ? ? ? ? .show(mamage);
? ? ? ? ? ? ? ? comfirmDialog.setConfirmDialogListener(new ConfirmDialog.ConfirmDialogListener(){
? ? ? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? ? ? public void dialogStatus(int id) {
? ? ? ? ? ? ? ? ? ? ? ? switch (id){
? ? ? ? ? ? ? ? ? ? ? ? ? ? case R.id.cancel:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //取消 到首頁
? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? ? ? ? ? case R.id.ok:
? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case IntegerUtil.ABS_TOKEN_POST_NULL://請求token不能為空? ? ? ? ? ??
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? default:
? ? ? ? ? ? ? ? onResultError(resultException);
? ? ? ? ? ? ? ? break;
? ? ? ? }
? ? }
? ? @Override
? ? public void onNext(T t) {
? ? ? ? onDone(t);
? ? ? ? if(dialog!=null&&dialog.isShowing()){
? ? ? ? ? ? dialog.closeProgress();
? ? ? ? }
? ? }
最后一步,調用實現
? ?HttpService httpService = Http.getHttpService();
? ? ? ? Map<String, Object> map = new HashMap<String, Object>();
? ? ? ? map.put("courseId", courseId);
? ? ? ? httpService.payDirectInfo(RequestBodyUtils.setRequestBody(map))
? ? ? ? ? ? ? ? .subscribeOn(Schedulers.io())
? ? ? ? ? ? ? ? .observeOn(Schedulers.io())
? ? ? ? ? ? ? ? .observeOn(AndroidSchedulers.mainThread())
? ? ? ? ? ? ? ? .subscribe(new AbsAPICallback<PayDirectInfo>(mContext, true) {
? ? ? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? ? ? protected void onDone(PayDirectInfo strTeacher) {
? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? ? ? public void onResultError(ResultException ex) {
? ? ? ? ? ? ? ? ? ? ? ? ToastUtil.showToast(ex.getMessage());
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? });
? ? }
有問題,請隨時留言或加本人QQ:874993467
總結
以上是生活随笔為你收集整理的Retrofit+RxJava+OkHttp项目中的使用的全部內容,希望文章能夠幫你解決所遇到的問題。