这个章节我们来讲下Volley在实际开发中如何正确地运用它。废话不说,进入正题。
集成 Volley
如果使用Android Studio开发的读者可以直接添加远程依赖:
compile ‘com.mcxiaoke.volley:library:1.0.19‘
如果使用Ecplise开发的读者可以在lib中加入jar,可以自己通过源码进行打包成jar,我这里就直接给出Volley.jar资源了。点此下载Volley.jar
Volley的Requst
final TextView mTextView = (TextView) findViewById(R.id.text);
...
// Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(this);
String url ="https://www.baidu.com/";
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
mTextView.setText("Response is: "+ response.substring(0,500));
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
mTextView.setText("That didn‘t work!");
}
});
queue.add(stringRequest);
这是Volley的常规用法:
- 创建一个RequestQueue对象
- 创建一个继承自Request抽象类的子类请求对象
- 将请求对象加入到RequestQueue中
我们在StringRequest中传了四个参数,分别是:请求方法、url的字符串、请求成功的回调以及请求失败的回调。我们可以在回调中实现我们想要的具体逻辑。无论是StringRequest还是JsonRequest以及其他继承了Request类的对象,都是如此使用。
在开发过程中,比如在一个Activity有多个需要加载网络图片的ImageView,我们将多个Request加入到RequestQueue中,此时图片还没全部显示出来,我们点了后退键。此时,这个Acitivity销毁了,此时我们请求还在队列中,视图却已经销毁了,这样子就很容易造成效率的影响。所以我们可以在Activity中写如下代码:
public static final String TAG = MainActivity.class.getSimpleName();
StringRequest stringRequest; // Assume this exists.
RequestQueue mRequestQueue; // Assume this exists.
// Set the tag on the request.
stringRequest.setTag(TAG);
// Add the request to the RequestQueue.
mRequestQueue.add(stringRequest);
这里我们为每个Request设置了标签,并且标签最好以类名定义,这样子方便管理。然后我们在Activity的Stop方法中可以这么写:
@Override
protected void onStop () {
super.onStop();
if (mRequestQueue != null) {
mRequestQueue.cancelAll(TAG);
}
}
可以看到,我们取消掉了在RequestQueue中所有有此标签的Request。
Volley的RequestQueue:
在开发中,我们最好设计一个全局的RequestQueue对象,此时,你可能很容易想到在继承于Application中的Oncreate方法初始化它,但是这样子是不推荐的,会引起很多不必要的麻烦。现在我们通过单例模式来创建它:
public class MySingleton {
private static MySingleton mInstance;
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
private static Context mCtx;
private MySingleton(Context context) {
mCtx = context;
mRequestQueue = getRequestQueue();
mImageLoader = new ImageLoader(mRequestQueue,
new ImageLoader.ImageCache() {
private final LruCache<String, Bitmap>
cache = new LruCache<String, Bitmap>(20);
@Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
});
}
public static synchronized MySingleton getInstance(Context context) {
if (mInstance == null) {
mInstance = new MySingleton(context);
}
return mInstance;
}
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
}
return mRequestQueue;
}
public <T> void addToRequestQueue(Request<T> req) {
getRequestQueue().add(req);
}
public ImageLoader getImageLoader() {
return mImageLoader;
}
}
这里我们Volley.newRequestQueue(mCtx.getApplicationContext());
传入了了ApplicationContext对象,这是一个全局对象,如果我们传入了Activity或者Service的Context,就会引起内存泄漏。在这里初始化了RequestQueue对象以及一个ImageLoader。关于ImageLoader我们接下去再说,现在我们可以这样使用RequestQueue:
RequestQueue queue = MySingleton.getInstance(this.getApplicationContext()).
getRequestQueue();
MySingleton.getInstance(this).addToRequestQueue(stringRequest);
这样子就全局管理了RequestQueue。
Volley的NetworkImageView
Volley封装了一个继承自ImageView的NetworkImageView,还记得我们在RequestQueue单例中还初始化了一个ImageLoader吗,它能简单快捷地与NetworkImageView联合使用。我们可以在ListView的Item布局中使用NetworkImageView,然后用ImageLoader加载图片。
在Xml布局中定义很简单:
<com.android.volley.toolbox.NetworkImageView
android:id="@+id/networkImageView"
android:layout_width="150dp"
android:layout_height="170dp"
android:layout_centerHorizontal="true" />
然后在视图中代码可以这么写:
ImageLoader mImageLoader;
NetworkImageView mNetworkImageView;
private static final String IMAGE_URL =
"https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png";
mNetworkImageView = (NetworkImageView)
findViewById(R.id.networkImageView);
mImageLoader = MySingleton.getInstance(this).getImageLoader();
mNetworkImageView.setImageUrl(IMAGE_URL, mImageLoader);
可以看到我们在这里mNetworkImageView.setImageUrl(IMAGE_URL, mImageLoader);
方法中只传入了一个url以及一个加载器就可以。
我们比较一下ImageView配合ImageLoader的代码:
ImageLoader mImageLoader;
ImageView mImageView;
private static final String IMAGE_URL =
"https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png";
mImageView = (ImageView) findViewById(R.id.regularImageView);
mImageLoader = MySingleton.getInstance(this).getImageLoader();
mImageLoader.get(IMAGE_URL, ImageLoader.getImageListener(mImageView,
R.drawable.def_image, R.drawable.err_image));
很明显看到,代码不如用NetworkImageView与Imageloader配合来的简洁。