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