联网的框架有很多,我试着分别用了两个,一个是Volley,一个是Okhttp。在使用过程中,有大大小小的坑,把我这两天的时间都浪费光了,不过解决这些问题后我确实又明白了很多知识,虽然这些知识在之前看书的时候都学过,但是理解不够,用的时候自然无从下手,现在明白一些了,就把这些都记录一下。
首先说一下使用过程中的坑吧,第一个坑,我在用volley去请求网络后,然后在volley请求成功的回调方法里面打印了请求数据,结果一直请求失败,因为我请求了十三个地址,然后把所有请求队列放在一个循环里,这样去请求,结果自然不行,后来我查询资料,发现原来Volley是要把多个请求放在一个队列,而不是创建多个只包含一个请求的队列。然后我就把请求放在一个队列中
public void getDateByVolley(){
RequestQueue queue = Volley.newRequestQueue(context);
for (int i = 0 ; i < Constants.all_urls.length; i++){
queue.add(getDataFromNetByVolley(Constants.all_urls[i]));
}
}
结果发现还是没有网络,坑爹了。。。。又通过查资料,发现volley可以设置请求网络失败时重新请求,只要
request.setRetryPolicy(new DefaultRetryPolicy(10 * 1000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES,//默认最大尝试次数
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT )); //设置请求失败的时候重试
然后请求网络得到数据了:
结果坑爹的又来了,我在volley请求网络成功回调的onResponse方法里面获取的数据居然不能在这个方法之外使用,而且因为请求是耗时的,你无法在onResponse方法外面去正确的判断数据的状态。
比如上图中,volley每请求成功一次,我就把获取的数据添加到一个集合中,然后打印这个集合list的长度,它是递增的,结果我在onResponse方法之外去打印list的长度(list是全局变量),不管在哪里打印,不管我怎么使用if,when,结果都为0,list也为null。
后来我思考了很久很久,终于想明白了,由于网络请求是一个耗时操作,这里请求十几个地址全部完成大概要十几秒,所以我在onResponse方法外去判断是没有效果的,因为时间不同步,我连请求都没完成,判断就结束了,必须要在网络请求完成后发送一个通知才行。
这时候我想到了AsyncTask,结果不行,在网上查资料发现,volley已经封装了异步请求网络,也就是说它的网络请求是
然后我又思考了很久很久,终于想到了两个方法,第一个是使用Handler,第二个是通过构造函数的方法。
Handler就不谈了,我最开心的是想到了构造函数的方法,比如说我想用这些数据设置ListView的适配器,只需要创建一个ListView的适配器,然后在适配器里添加一个构造函数,这个构造函数的构造参数有我想要的数据就行,这样就可以把数据传递给适配器了。
然后使用okhttp需要注意的一点是,在okhttp请求成功的回调方法中,不是在主线程里,而volley请求成功的回调方法是在主线程里的,所以前者需要开启主线程才能更新UI,后者则可以直接在volley中更新UI。接下来就是大致的代码了:
public class MainActivity extends AppCompatActivity {
private ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listview);
try {
initData();
} catch (JSONException e) {
e.printStackTrace();
}
}
public void initData() throws JSONException {
LogUtil.e("页面数据被初始化——");
String saveJson = CacheUtils.getString(MainActivity.this, Constants.all_urls[0]);
if (!TextUtils.isEmpty(saveJson)){
processData(saveJson);
}
// getDateByVolley();
getDataByOkhttp(Constants.all_urls[0]);
}
public void getDateByVolley(){
RequestQueue queue = Volley.newRequestQueue(this);
queue.add(getDataFromNetByVolley(Constants.all_urls[0]));
}
private StringRequest getDataFromNetByVolley(final String url){
final StringRequest request = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
LogUtil.e("使用Volley联网请求数据成功——" + response);
//缓存数据
CacheUtils.putString(MainActivity.this, url, response);
NewsTopBeanAuto bean = HttpUtil.parsedJsonWithGson(response);
String title = bean.getResult().getResult().getChannel();
processData(response);
LogUtil.e("数据解析成功,标题是——" + title );
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
LogUtil.e("使用Volley联网请求数据失败——" + error.getMessage());
}
}){
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
try {
String parsed = new String(response.data, "UTF-8");
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return super.parseNetworkResponse(response);
}
};
request.setRetryPolicy(new DefaultRetryPolicy(10 * 1000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES,//默认最大尝试次数
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT )); //设置请求失败的时候重试
return request;
}
private void processData(String json) {
final NewsTopBeanAuto bean = HttpUtil.parsedJsonWithGson(json);
String title = bean.getResult().getResult().getChannel();
List<NewsTopBeanAuto.ResultBeanX.ResultBean.ListBean> listBeen = bean.getResult().getResult().getList();
LogUtil.e("解析Json数据成功----title----:" + title);
if (listBeen != null){
listView.setAdapter(new MyListViewAdapter(listBeen));
}
}
private void getDataByOkhttp(String url){
HttpUtil.sendOkHttpRequest(url, new Callback() {
@Override
public void onFailure(Call call, IOException e) {
LogUtil.e("使用okhttp失败~~~");
}
@Override
public void onResponse(Call call, okhttp3.Response response) throws IOException {
LogUtil.e("使用okhttp成功~~~当前线程是——" + Thread.currentThread().getName());
final String data = response.body().string();
NewsTopBeanAuto bean = HttpUtil.parsedJsonWithGson(data);
String title = bean.getResult().getResult().getChannel();
runOnUiThread(new Runnable() {
@Override
public void run() {
processData(data);
}
});
LogUtil.e("数据解析成功,标题是——" + title );
}
});
}
private class MyListViewAdapter extends BaseAdapter {
List<NewsTopBeanAuto.ResultBeanX.ResultBean.ListBean> listBeen;
public MyListViewAdapter(List<NewsTopBeanAuto.ResultBeanX.ResultBean.ListBean> listBeen) {
this.listBeen = listBeen;
}
@Override
public int getCount() {
return listBeen.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null){
convertView = View.inflate(MainActivity.this, R.layout.listview_detail, null);
viewHolder = new ViewHolder();
viewHolder.tv_title = (TextView) convertView.findViewById(R.id.tv_title);
viewHolder.tv_time = (TextView) convertView.findViewById(R.id.tv_time);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
String data1 = listBeen.get(position).getTitle();
String data2 = listBeen.get(position).getTime();
viewHolder.tv_title.setText(data1);
viewHolder.tv_time.setText(data2);
LogUtil.e("内容是——" + data1 + data2);
return convertView;
}
}
private class ViewHolder {
TextView tv_title;
TextView tv_time;
}
}
粗略效果大概是这样: