Retrofit踩坑日记:response.body().string()只能调用一次
总览和相关链接
这个作业属于哪个课程 | 2021春/S班 |
---|---|
这个作业要求在哪里 | 软件工程实践总结&个人技术博客 |
这个作业的目标 | 总结个人技术 |
技术概述
我在开发新闻app的过程中需要请求服务器数据,Retrofit框架在网络请求方面封装的很好,因此我选择学习它,该技术的难点在于它的设计原理十分复杂,它利用了注解和okhttp框架给程序员带来了极大的便利。
技术详述
首先先创建一个接口:
public interface NewsService {
@POST("index") //必须用post请求
@FormUrlEncoded
Call<BaseResponse> post(@Field("type") String type, @Field("key") String key);
@GET("index")
Call<ResponseBody> get(@Query("type") String type, @Query("key") String key);
}
核心方法:先配置Retrofi构造器的addConverterFactory方法,让它可以自动实现json数据转换成实体类,在baseurl函数的参数里填上要访问的网络地址,利用Retrofit框架对NewsService进行实现,然后调用NewsService的post方法,然后在子线程中进行网络请求,主线程等待子线程处理完毕,将得到的数据返回。
public List<News> getData(String type) throws InterruptedException {
List<News>[] newsList = new List[]{new ArrayList<>()};
Retrofit retrofit = new Retrofit.Builder().baseUrl("https://v.juhe.cn/toutiao/")
.addConverterFactory(GsonConverterFactory.create()) //添加转换器build();
.build();
NewsService newsService = retrofit.create(NewsService.class); //Retrofit将这个接口进行实现
Call<BaseResponse> call = newsService.post(type, "4b3b9c355a55f676605532d37cf0d66c");
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
Response<BaseResponse> response = call.execute();
BaseResponse baseResponse = response.body();
newsList[0] = baseResponse.getResult().getData();
} catch (IOException e) {
e.printStackTrace();
}
}
};
Thread thread = new Thread(runnable);
thread.start();
thread.join();
Log.d("lifecycle", String.valueOf(newsList[0].size())); //0?
return newsList[0];
}
流程图:
技术使用中遇到的问题和解决过程。
问题:我打算将服务器返回的json数据进行解析,解析出来的对象一直是空,我还以为我导入的GSON库有问题,浪费了很多时间。
贴上错误代码
public void onResponse(retrofit2.Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
try {
Log.d("RetrofitActivity", response.body().string());
//String result = response.body().string();
BaseResponse baseResponse = new Gson().fromJson(response.body().string(), BaseResponse.class);
System.out.println(baseResponse);
} catch (IOException e) {
e.printStackTrace();
}
}
注意看我调用了两次response.body().string(),原来response.body().string()只能调用一次,第二次为空。因为response.body().string()所包含的资源往往很大 ,当客户端接收到数据之后,okhttp的缓冲区就会自动释放资源!!
解决方案:
public void onResponse(retrofit2.Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
try {
//Log.d("RetrofitActivity", response.body().string());
String result = response.body().string();
BaseResponse baseResponse = new Gson().fromJson(result, BaseResponse.class);
System.out.println(baseResponse);
} catch (IOException e) {
e.printStackTrace();
}
}
总结
当调用response.body().string()获取数据时,response.body().string()只能调用一次,因此我们可以新建变量将数据存储下来再进行后面的处理。犯这种错误的原因主要还是因为对网络框架的原理不够了解。
参考文献
OkHttp踩坑记:为何 response.body().string() 只能调用一次? 作者:ruicbAndroid