代码下载 点击链接,免积分下载。。。
今天来写一个关于图片请求的小例子,我们用NetworkImageView这个类来实现,这个类可以直接用在xml控件中,当作imageview,而且内部原理也是使用的ImageLoader,所以综合性还是不错的
效果图如下:
本例就没有再去进行封装代码了,封装代码在前几篇中有写到,下面2张图是
http://www.imooc.com/api/teacher?type=4&num=30返回的json格式的数据,本例也就从中获取picSmall、name即可
下面就是onResponse返回的一串字符串(只不过这个字符串的格式是Json类型)
StringRequest request = new StringRequest(Method.GET, url,
new Listener() {
@Override
public void onResponse(String sb) {
Log.e("Safly", "onResponse-->>" + sb);
parseJsonFromServer(sb);
setAdapter();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError arg0) {
}
});
然后就开始解析,用JsonObject(当然也可以用JsonObject的另外写法比如jsonObject.optInt的写法,还可以用JsonReader等等)
private void parseJsonFromServer(String sb) {
datas = new ArrayList();
JSONObject jsonObject;
try {
jsonObject = new JSONObject(sb.toString());
JSONArray jsonArray = jsonObject
.getJSONArray("data");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonData = jsonArray
.getJSONObject(i);
DataBean newsBean = new DataBean();
newsBean.setImageUrl(jsonData
.getString("picSmall"));
newsBean.setTitle(jsonData.getString("name"));
// 添加对象,组建集合
datas.add(newsBean);
}
Log.i("Safly", "datas.size-->>"+datas.size());
} catch (JSONException e) {
e.printStackTrace();
}
}
最后就看adapter中的内容即可
我们在稍微看下NetworkImageView源码类
它里面有2个方法是进行设置控件的默认图片,以及下载失败的提示图片,结果这2个方法在Volley中都没有内部调用,所以说我们可以在adapter中,进行预设置,我们之前看源码得知,下载完毕图片后,还会进行更新操作,下载失败后,就会volley内部去进行操作
/**
* 接下来就是跟imageloader里面的请求代码思路一样了
*/
ImageContainer newContainer = mImageLoader.get(mUrl,
new ImageListener() {
@Override
public void onErrorResponse(VolleyError error) {
if (mErrorImageId != 0) {
setImageResource(mErrorImageId);
}
}
然后我们就可以利用如下的源码进行设置了一些参数了,下边是volley的代码
public void setImageUrl(String url, ImageLoader imageLoader) {
mUrl = url;
mImageLoader = imageLoader;
// The URL has potentially changed. See if we need to load it.
loadImageIfNecessary(false);
}
对应我们代码中的部分
viewHolder.imageview_item.setImageUrl(url, VolleyTool.getInstance(context).getImageLoader());
//私有构造方法
private VolleyTool(Context context) {
//创建请求队列
queue = Volley.newRequestQueue(context);
//创建图片加载器
imageLoader = new ImageLoader(queue, new LruImageCache());
}
//公共、静态的方法
public static VolleyTool getInstance(Context context) {
if (instance == null) {
instance = new VolleyTool(context);
}
return instance;
}
看看构造器中进行了哪些操作?初始化queue、ImageLoader
我们在看看对应volley中的ImageLoader的构造器部分如下:
public interface ImageCache {
public Bitmap getBitmap(String url);
public void putBitmap(String url, Bitmap bitmap);
}
/**
* Constructs a new ImageLoader.
* @param queue The RequestQueue to use for making image requests.
* @param imageCache The cache to use as an L1 cache.
*/
public ImageLoader(RequestQueue queue, ImageCache imageCache) {
mRequestQueue = queue;
mCache = imageCache;
}
很明显源码中ImageCache,只有getBitmap、putBitmap方法,而我们呢?用到了LruCache强缓存处理,以完善内存缓存的控制管理
那我们就来看看这个LruChche的源码把如下:
首先看看构造器部分:
/**
* @param maxSize for caches that do not override {@link #sizeOf}, this is
* the maximum number of entries in the cache. For all other caches,
* this is the maximum sum of the sizes of the entries in this cache.
*/
public LruCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
this.map = new LinkedHashMap(0, 0.75f, true);
}
如果maxSize<=0 就会跑异常,那么这个参数是什么意思呢?
我们看看百度的翻译:这是高速缓存中的条目的最大数目。对于所有其他高速缓存,这是该缓存中的项的大小的最大和。
意思就是此缓存能缓存的最大值是多少
缓存肯定需要放东西把,我们看看put做了什么相关处理的操作?
public final V put(K key, V value) {
if (key == null || value == null) {
throw new NullPointerException("key == null || value == null");
}
V previous;
synchronized (this) {
putCount++;
size += safeSizeOf(key, value);
previous = map.put(key, value);
if (previous != null) {
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
entryRemoved(false, key, previous, value);
}
trimToSize(maxSize);
return previous;
}
大概意思就是:放进来一个就putCount++就累加进来数量,参数一看就知道啥意思了,那么safeSizeOf这个是啥意思呢?我们去看看
private int safeSizeOf(K key, V value) {
int result = sizeOf(key, value);
if (result < 0) {
throw new IllegalStateException("Negative size: " + key + "=" + value);
}
return result;
}
protected int sizeOf(K key, V value) {
return 1;
}
针对到本例子就是请求的一个图片的内存大小,请求一个就累加size += safeSizeOf(key, value);我们该问了,它对存在的还会累加么?我们在回到put方法中,
if (previous != null) {
size -= safeSizeOf(key, previous);
}
这个意思是如果之前有缓存的话,就不再添加了,就在剪掉即可
最后看下put方法中的代码
trimToSize(maxSize);
他的意思就是删除最大的条目,直到剩余的条目总数或低于所请求的大小。百度翻译的意思就是,容量超过就会删除访问少的条目
get方法也就相对简单了,就是取出来就可。
所以我们的代码在看的话,就不是那么复杂了:
/**
* 使用LRU回收算法的缓存类
*/
class LruImageCache implements ImageCache {
// 缓存容器
private LruCache cache;
public LruImageCache() {
// 计算缓存的最值
int maxSize = (int) (Runtime.getRuntime().maxMemory() / 8);
//创建缓存对象实例
cache = new LruCache(maxSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
// 返回bitmap占用的内存大小
return value.getRowBytes() * value.getHeight();
}
};
}
// 从缓存中取图片对象
@Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
// 将图片对象保存到缓存容器中
@Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
}
另外注意一点就是在item布局中
<com.android.volley.toolbox.NetworkImageView
android:scaleType="fitXY"
android:background="@drawable/ic_launcher"
android:id="@+id/imageview_item"
android:layout_width="60dp"
android:layout_height="60dp"/>
需要android:scaleType=”fitXY”
我这个demo没有出现图片错乱的现象,有的朋友说会有错乱的现象,我做了一个实验,初始化有网络,然后就关掉网络,进行滑动依然是没有问题的如下:
以下就是代码区别############################
"http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.saflyimage.MainActivity" >
"@+id/mListView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
"1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="#FFFFF0"
android:layout_height="wrap_content" >
"fitXY"
android:background="@drawable/ic_launcher"
android:id="@+id/imageview_item"
android:layout_width="60dp"
android:layout_height="60dp"/>
"tv"
android:layout_marginRight="20dp"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:id="@+id/textview_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
SaflyApplication
package com.example.saflyimage;
import android.app.Application;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;
public class SaflyApplication extends Application {
public static RequestQueue requestQueue;
@Override
public void onCreate() {
super.onCreate();
requestQueue = Volley.newRequestQueue(getApplicationContext());
}
public static RequestQueue getRequestQueue() {
return requestQueue;
}
}
DataBean
package com.example.saflyimage;
public class DataBean {
private String imageUrl;
private String title;
public DataBean(String imageUrl, String title) {
super();
this.imageUrl = imageUrl;
this.title = title;
}
public DataBean() {
super();
// TODO Auto-generated constructor stub
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
MainActivity
package com.example.saflyimage;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ListView;
import com.android.volley.Request.Method;
import com.android.volley.Response;
import com.android.volley.Response.Listener;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
public class MainActivity extends Activity {
private List datas;
private ListView mListView;
private SaflyAdapter saflyAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) findViewById(R.id.mListView);
String url = "http://www.imooc.com/api/teacher?type=4&num=30";
StringRequest request = new StringRequest(Method.GET, url,
new Listener() {
@Override
public void onResponse(String sb) {
Log.e("Safly", "onResponse-->>" + sb);
parseJsonFromServer(sb);
setAdapter();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError arg0) {
}
});
// 设置标签
request.setTag("abcGet");
SaflyApplication.getRequestQueue().add(request);
SaflyApplication.getRequestQueue().start();
}
/**
* 设置适配器
*/
private void setAdapter() {
saflyAdapter = new SaflyAdapter(MainActivity.this,datas);
mListView.setAdapter(saflyAdapter);
}
/**
* 解析json数据
* @param sb
*/
private void parseJsonFromServer(String sb) {
datas = new ArrayList();
JSONObject jsonObject;
try {
jsonObject = new JSONObject(sb.toString());
JSONArray jsonArray = jsonObject
.getJSONArray("data");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonData = jsonArray
.getJSONObject(i);
DataBean newsBean = new DataBean();
newsBean.setImageUrl(jsonData
.getString("picSmall"));
newsBean.setTitle(jsonData.getString("name"));
// 添加对象,组建集合
datas.add(newsBean);
}
Log.i("Safly", "datas.size-->>"+datas.size());
} catch (JSONException e) {
e.printStackTrace();
}
}
}
SaflyAdapter
package com.example.saflyimage;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import com.android.volley.toolbox.NetworkImageView;
public class SaflyAdapter extends BaseAdapter {
private ArrayList dataBeans;
private Context context;
private LayoutInflater inflater;
public SaflyAdapter(Context context, List datas) {
super();
this.dataBeans = (ArrayList) datas;
this.context = context;
this.inflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return dataBeans.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return dataBeans.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.listview_item, parent,
false);
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
DataBean dataBean = dataBeans.get(position);
viewHolder.textview_item.setText(dataBean.getTitle());
// 设置未加载默认图片
viewHolder.imageview_item.setDefaultImageResId(R.drawable.ic_launcher);
// 设置加载异常的图片
viewHolder.imageview_item.setErrorImageResId(R.drawable.anzhuanghsibai);
String url = dataBean.getImageUrl();
viewHolder.imageview_item.setImageUrl(url,
VolleyTool.getInstance(context).getImageLoader());
return convertView;
}
class ViewHolder {
NetworkImageView imageview_item;
TextView textview_item;
public ViewHolder(View view) {
super();
this.imageview_item = (NetworkImageView) view
.findViewById(R.id.imageview_item);
this.textview_item = (TextView) view
.findViewById(R.id.textview_item);
}
}
}
VolleyTool
package com.example.saflyimage;
import android.content.Context;
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.ImageLoader.ImageCache;
import com.android.volley.toolbox.Volley;
public class VolleyTool {
//初始化请求队列、图片加载器
private RequestQueue queue;
private ImageLoader imageLoader;
//私有静态实例
private static VolleyTool instance;
//私有构造方法
private VolleyTool(Context context) {
//创建请求队列
queue = Volley.newRequestQueue(context);
//创建图片加载器
imageLoader = new ImageLoader(queue, new LruImageCache());
}
//公共、静态的方法
public static VolleyTool getInstance(Context context) {
if (instance == null) {
instance = new VolleyTool(context);
}
return instance;
}
//得到请求队列
public RequestQueue getQueue() {
return queue;
}
//得到图片加载器
public ImageLoader getImageLoader() {
return imageLoader;
}
/**
* 使用LRU回收算法的缓存类
*/
class LruImageCache implements ImageCache {
// 缓存容器
private LruCache cache;
public LruImageCache() {
// 计算缓存的最值
int maxSize = (int) (Runtime.getRuntime().maxMemory() / 8);
//创建缓存对象实例
cache = new LruCache(maxSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
// 返回bitmap占用的内存大小
return value.getRowBytes() * value.getHeight();
}
};
}
// 从缓存中取图片对象
@Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
// 将图片对象保存到缓存容器中
@Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
}
}