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