在网络上请求图片资源是APP最常见的操作之一,上篇博文已经介绍过ImageRequest,可以实现image的请求显示 重新按照所需尺寸编码decode等等功能。这次我们来介绍ImageLoader。
- ImageRequest—a canned request for getting an image at a given URL and calling back with a decoded bitmap. It also provides convenience features like specifying a size to resize to. Its main benefit is that Volley’s thread scheduling ensures that expensive image operations (decoding, resizing) automatically happen on a worker thread.
- ImageLoader—a helper class that handles loading and caching images from remote URLs. ImageLoader is a an orchestrator for large numbers of ImageRequests, for example when putting multiple thumbnails in a ListView. ImageLoader provides an in-memory cache to sit in front of the normal Volley cache, which is important to prevent flickering. This makes it possible to achieve a cache hit without blocking or deferring off the main thread, which is impossible when using disk I/O. ImageLoader also does response coalescing, without which almost every response handler would set a bitmap on a view and cause a layout pass per image. Coalescing makes it possible to deliver multiple responses simultaneously, which improves performance.
- NetworkImageView—builds on ImageLoader and effectively replaces ImageView for situations where your image is being fetched over the network via URL. NetworkImageView also manages canceling pending requests if the view is detached from the hierarchy.
1.设置list_item.xml
为ListView的每一个项目设置布局。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="90dp"
android:orientation="horizontal" >
<com.android.volley.toolbox.NetworkImageView
android:id="@+id/item_image"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_marginLeft="10dp"
android:src="@drawable/ic_launcher" />
<TextView
android:id="@+id/item_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="神秘北极圈 阿拉斯加的山巅 谁的脸 出线海角的天边" >
TextView>
LinearLayout>
主布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android1="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android1:id="@+id/listView1"
android1:layout_width="match_parent"
android1:layout_height="wrap_content"
android1:layout_alignParentTop="true"
android1:layout_centerHorizontal="true" >
ListView>
RelativeLayout>
2.初始化ListView和设置Adapter
package com.example.volley_list;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.util.Log;
import android.util.LruCache;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.ImageLoader.ImageCache;
import com.android.volley.toolbox.NetworkImageView;
import com.android.volley.toolbox.Volley;
public class MainActivity extends Activity {
private ListView listView;
// 定义自己的Adapter
private ListItemAdapter adapter;
private static final String TAG = "MainActivity";
// 请求队列
static RequestQueue rQueue;
// 圖片URL数组
private String[] paths = {
"http://d.hiphotos.bdimg.com/album/pic/item/34fae6cd7b899e51dca31fbb40a7d933c8950d6b.jpg",
"http://imgsrc.baidu.com/forum/w%3D580/sign=97543e82b6119313c743ffb855380c10/fc0a12f41bd5ad6e19d394aa85cb39dbb6fd3c5d.jpg",
"http://thumbnail2.jiaoyoudns.com/mfs.jiaoyoudns.com/test/sld/91/0391/1_tuku_1_9_1395000391.jpg=-=750_750_0_thumbnails.jpg",
"http://d.hiphotos.bdimg.com/album/pic/item/34fae6cd7b899e51dca31fbb40a7d933c8950d6b.jpg",
"http://img5.duitang.com/uploads/item/201405/02/20140502190021_Bkau2.jpeg",
"http://img4.duitang.com/uploads/item/201405/02/20140502191110_vFfLm.png",
"http://img4.duitang.com/uploads/item/201407/22/20140722133408_BGL2a.png",
"http://1881.img.pp.sohu.com.cn/images/blog/2012/5/4/10/8/e10850818_137d711c6fcg214.png",
"http://img4.imgtn.bdimg.com/it/u=3256617509,2551528905&fm=21&gp=0.jpg",
"http://imgsrc.baidu.com/forum/w%3D580/sign=66743b95d639b6004dce0fbfd9513526/efa669cf3bc79f3d8b66dc46b9a1cd11738b295f.jpg",
"http://images.chinese.kdramastars.com/data/images/full/15686/f-x-krystal.jpg?w=600" };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 实例化成员变量
Log.i(TAG, "onCreate()");
listView = (ListView) findViewById(R.id.listView1);
rQueue = Volley.newRequestQueue(getApplicationContext());
adapter = new ListItemAdapter(this);
listView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
/**
* 编写适配器ListItemAdapter
*
* @author QT
*
*/
public class ListItemAdapter extends BaseAdapter {
// 上下文对象
private Context context;
public ListItemAdapter(Context context) {
super();
this.cOntext= context;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return paths.length;
}
@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
View v;
Log.i(TAG, "getView()" + position);
if (cOnvertView== null) {
// 若为空,则动态加载一个View
v = inflater.inflate(R.layout.list_item, null);
// v.setPadding(8, 8, 8, 8);
} else {
v = convertView;
}
// 初始化ImageLoader,此处其实也应该为单例的
// ImageLoader 需要自己实现缓存
ImageLoader mImageLoader = new ImageLoader(rQueue,
new ImageCache() {
private final LruCache cache = new LruCache(
20);
@Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
@Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
});
NetworkImageView mNetworkImageView = (NetworkImageView) v
.findViewById(R.id.item_image);
String IMAGE_URL = paths[position];
// Set the URL of the image that should be loaded into this view,
// and
// specify the ImageLoader that will be used to make the request.
mNetworkImageView.setImageUrl(IMAGE_URL, mImageLoader);
TextView mTextView = (TextView) v.findViewById(R.id.item_text);
mTextView.append("------>" + position);
return v;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
3.运行结果
每次执行网络请求,实例化一个RequestQueue,很明显是对于资源的浪费,同时在app整个生命周期几乎都有可能发生网络请求,所以设置RequestQueue的上下文对象为ApplicationContext,使用单例模式是最佳实践!
package com.example.volley_list;
import android.content.Context;
import android.graphics.Bitmap;
import android.util.LruCache;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;
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
cache = new LruCache(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) {
// getApplicationContext() is key, it keeps you from leaking the
// Activity or BroadcastReceiver if someone passes one in.
mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
}
return mRequestQueue;
}
public void addToRequestQueue(Request req) {
getRequestQueue().add(req);
}
public ImageLoader getImageLoader() {
return mImageLoader;
}
}
方法调用
// Get a RequestQueue
RequestQueue queue = MySingleton.getInstance(this.getApplicationContext()).
getRequestQueue();
...
// Add a request (in this example, called stringRequest) to your RequestQueue.
MySingleton.getInstance(this).addToRequestQueue(stringRequest);
// Get the ImageLoader through your singleton class.
mImageLoader = MySingleton.getInstance(this).getImageLoader();