天天看點

Rxjava+retrofit2+OKHttp+GSON實踐

Rxjava+retrofit2+OKHttp+GSON實踐(新浪微網誌API調用執行個體)

網絡請求

建議學習了以下知識才看這篇文章:

OKHTTP3請參考:http://blog.csdn.net/weixin_37577039/article/details/78546444

retrofit2 請參考:http://blog.csdn.net/weixin_37577039/article/details/78546591

JSON解析:http://blog.csdn.net/weixin_37577039/article/details/78546482

新浪微網誌JSON解析實踐:http://blog.csdn.net/weixin_37577039/article/details/78619940

Rxjava2請參考:http://blog.csdn.net/weixin_37577039/article/details/78555208

1 添加配置檔案,添權重限

包一定要導對,這裡是個坑

//retrofit2
    compile 'com.squareup.retrofit2:retrofit:2.3.0'
    //Gson converter
    compile 'com.squareup.retrofit2:converter-gson:2.3.0'
    //RxJava2 Adapter
    compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
    //rxjava2
    compile 'io.reactivex.rxjava2:rxjava:2.1.5'
    //rxandroid2
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
    //okhttp
    compile 'com.squareup.okhttp3:okhttp:3.9.0'
    compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
    // 新浪微網誌SDK
    compile 'com.sina.weibo.sdk:core:4.1.0:[email protected]'
           

有時候某個Sync不通過就try again試下

AndroidManifest.xml中

當獲得了AccessToken後,去調用API接口了 這裡就要用Rxjava進行異步操作,上遊執行網絡請求,下遊進行資料處理,UI更新

這裡将Observable為< ResponseBody>參數的

其他參數為BEAN類的其實也一樣

将ResponseBody部分改為BEAN類即可

@Override
public void onNext(XXBean xxBean) {
// 替換了那個call.enqueue方法 直接在這裡進行擷取
Log.i("myAccessToken", xxBean.getXXX() );// 即可以得到BEAN類中對應的資料
}
           
//call對象聲明
private io.reactivex.Observable<AccessTokenBean> call_1;

           

2 定義接口

(retrofit2 負責部分,原retrofit2改call為Observable)

public interface HttpService {
//調用API
@GET("2/statuses/home_timeline.json?")
Observable<ResponseBody> getAPI(@Query("access_token") String accessToken, @Query("count") int count);

}
           

3 接着建立一個Retrofit用戶端

(retrofit2和okhttp3 原retrofit2增加了.addCallAdapterFactory)

private Context mContext;
 public void createRetrofit(String accessToken,Context context){
        mContext=context;
        //OKHttp進行逾時設定,攔截器等設定
        OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
        builder.readTimeout(, TimeUnit.SECONDS);
        builder.connectTimeout(, TimeUnit.SECONDS);
        if (BuildConfig.DEBUG) {
            HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
            interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
            builder.addInterceptor(interceptor);
        }
 // 建立gson執行個體
    Gson gson = new GsonBuilder()
    //配置你的Gson
    .setDateFormat("yyyy-MM-dd hh:mm:ss")
    .create();
//建立Retrofit執行個體
    Retrofit retrofit = new Retrofit.Builder()
    .baseUrl(baseUrl)
    .client(builder.build())
    .addConverterFactory(GsonConverterFactory.create(gson))
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .build();

           

4 發送請求

//先聲明
private Observable<ResponseBody> call_1;

//用retrofit建立HttpService對象
        final HttpService httpService = retrofit.create(HttpService.class);
         // 接口調用
        call_1= httpService.getAPI(accessToken,COUNT);
        //!!!這裡是一個坑!!!
        //這裡可能會報錯 說retrofit.call不能轉化為io.reactivex.observable類型 按ALT+ENTER去選擇最後一個,return httpService為io.reactivex.observable格式的(大概這個意思)就OK了

        // RXJAVA實作
        call_1.subscribeOn(Schedulers.io()) //在IO線程進行網絡請求
                .observeOn(AndroidSchedulers.mainThread())  //回到主線程去處理請求結果
                .subscribe(new Observer<ResponseBody>() {
                    @Override
// 連接配接成功了就會執行
  public void onSubscribe(Disposable d) {
      Log.i("subscribe is ok","subscribe is ok" );
  }
  @Override
  public void onNext(ResponseBody responseBody) {
      Toast.makeText(mContext, "調用API成功", Toast.LENGTH_SHORT).show();
      try {
          str=responseBody.string();
      } catch (IOException e) {
          e.printStackTrace();
      }
      Log.i("str",str);
      //開始解析
      try {
          // 将傳回的JSONString格式賦予JSONObject
          JSONObject jsonObject = new JSONObject(str);
          // 第一層為statuses 并且statuses為數組形式 是以将其設定為JSONArray形式
          JSONArray statusesArr = jsonObject.getJSONArray("statuses");
          // 循環地去獲得多條微網誌
          // 這裡的index+1代表的是第n條status(微網誌),是以index=0 為第一條 以此類推
          for (int i = ; i < COUNT; i++) {
              // 第一條 下标從0開始
              JSONObject statusesObj = statusesArr.getJSONObject(i);
              // statuses中的第一層,即總的第二層
              // 該條微網誌的建立時間
              created_at[i] = statusesObj.getString("created_at");
              Log.i("created_at", created_at[i]);
              //該條微網誌的來源
              source[i] = statusesObj.getString("source");
              Log.i("source", source[i]);
              //該條微網誌的轉發數
              reposts_count[i] = statusesObj.getString("reposts_count");
              Log.i("reposts_count", reposts_count[i]);
              //該條微網誌的評論數
              comments_count[i] = statusesObj.getString("comments_count");
              Log.i("comments_count", comments_count[i]);
              //該條微網誌的點贊數
              attitudes_count[i] = statusesObj.getString("attitudes_count");
              Log.i("attitudes_count", attitudes_count[i]);
              //該條微網誌的微網誌text内容
              text[i] = statusesObj.getString("text");
              Log.i("text", text[i]);
              // 總的第三層
              // 擷取user的值
              String user = statusesObj.getString("user");
              //user轉化為JSONObject
              JSONObject userObj = new JSONObject(user); // 将其轉化為JSONObject
              //微部落客名
              screen_name[i] = userObj.getString("screen_name"); // 使用getXX方法擷取資料
              Log.i("screen_name", screen_name[i]);
              //微部落客照片的位址
              profile_image_url[i] = userObj.getString("profile_image_url"); // 使用getXX方法擷取資料
              Log.i("profile_image_url", profile_image_url[i]);
          }
          // 若成功傳入最後一個微網誌 指定一個變量 而不是隻是一個數值 因為網絡請求要花時間
          if(profile_image_url[COUNT-]!=null){
              //若有值
              canIntent=true;
              // 非Activity中跳轉 滿足MVVM嗎  不滿足要改~~~~~~
              Intent intent = new Intent(mContext, MainActivity.class);
              mContext.startActivity(intent);
          }else{
              canIntent=false;
          }
      } catch(JSONException e){
          e.printStackTrace();
      }
  }
  @Override
  public void onError(Throwable e) {
      Log.i("API調用失敗","API調用失敗");
      Toast.makeText(mContext, "API調用失敗", Toast.LENGTH_SHORT).show();
  }
  //上遊不寫complete  成功傳回也會自動執行
  @Override
  public void onComplete() {
      Log.i("API調用成功","API調用成功");
      Toast.makeText(mContext, "API調用成功", Toast.LENGTH_SHORT).show();
  }
});
           

思考:

當方法A先執行,但是方法A要去調用監聽,他的回調資料還沒回調,這時會執行下面的B方法,但是B方法又需要A的回調資料,此時涉及到方法的異步調用問題

可以用RXJava解決這個問題

原理:在回調方法中,用RXJAVA去進行上下遊的異步操作

如新浪微網誌通過OAuth授權方式擷取accessToken,回調這個accessToken需要時間,則可以在回調的方法中,Rxjava上遊去接受回調,處理回調資料,然後處理完了,再去發送資料給下遊,下遊有了資料再去利用該資料調用新的請求

(不夠好?用FlatMap?見Rxjava(三)系列)

代碼示例見Github的SinaWeiBoDemo的LoginActivity中:

很多業務中,需要上一個請求成功了,得到資料并處理了,才進行下一個請求,這裡涉及了請求先後順序的問題

請參考下一篇部落格:

Rxjava2(三):http://blog.csdn.net/weixin_37577039/article/details/78622443

但是當請求未完成或剛完成,Activity銷毀了,則不應該更新主線程UI了,是以在Activity中将這個Disposable 儲存起來, 當Activity退出時, 切斷它即可

果有多個Disposable

RxJava中已經内置了一個容器CompositeDisposable, 每當我們得到一個Disposable時就調用CompositeDisposable.add()将它添加到容器中, 在退出的時候, 調用CompositeDisposable.clear() 即可切斷所有的水管

Disposable使用參考 RXjava(一):

http://blog.csdn.net/weixin_37577039/article/details/78555208

參考連結:http://www.jianshu.com/p/8818b98c44e2