Android加载网络图片资源方式和加载字符串资源类式,也是通过Http连接解析返回的字节流InputStream实现
//构造URL类
URL url = new URL(httpUrl);
//从url中得到图片输入流
InputStream in = url.openStream();
//使用BitmapFactory类解析流得到Bitmap对象
Bitmap bitmap = BitmapFactory.decodeStream(in);
注:InputStream in = url.openStream()
等价于
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
InputStream is = conn.getInputStream();
openStream()方法其实是对上面两行代码的封装
/**
* Equivalent to {@code openConnection().getInputStream(types)}.
*/
public final InputStream openStream() throws IOException {
return openConnection().getInputStream();
}
接着我们来实现一个网络加载单张图片实例
首先定义一个方法根据图片地址获取图片
public Bitmap downLoadBitmap(String httpUrl) {
InputStream in = null;
try {
URL url = new URL(httpUrl);
in = url.openStream();
Bitmap bitmap = BitmapFactory.decodeStream(in);
return bitmap;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
加载网络图片是耗时操作我们需要在异步任务中调用
String httpUrl = "http://d.hiphotos.baidu.com/image/h%3D360/sign=
ba3bf5f839c79f3d90e1e2368aa1cdbc/f636afc379310a55c01f6ef3b54543a9822610f9.jpg";
new AsyncTask<String, Void, Bitmap>() {
protected void onPreExecute() {
mProgressBar.setVisibility(View.VISIBLE);
}
@Override
protected Bitmap doInBackground(String... params) {
String httpUrl = params[0];
Bitmap bitmap = downLoadBitmap(httpUrl);
return bitmap;
}
@Override
protected void onPostExecute(Bitmap result) {
mProgressBar.setVisibility(View.GONE);
if (result != null)
mShowImg.setImageBitmap(result);
}
}.execute(httpUrl);
界面部份使用imageView控件,ProgressBar显示加载中效果如下
接着我们在来看下实现多图加载操作
获取图片资源方式和单张图片一样,显示控件我们换用GridView.
主要代码如下
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ImageView loaderImageView;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item_my_gridview_layout, null);
loaderImageView = (ImageView) convertView.findViewById(R.id.my_gridview_img);
convertView.setTag(loaderImageView);
} else {
loaderImageView = (ImageView) convertView.getTag();
}
String itemUrl = (String) getItem(position);
new AsyncTask<String, Void, Bitmap>() {
@Override
protected Bitmap doInBackground(String... params) {
String httpUrl = params[0];
//根据httpUrl地址加载网络图片
Bitmap bitmap = downLoadBitmap(httpUrl);
return bitmap;
}
@Override
protected void onPostExecute(Bitmap result) {
if (result != null)
loaderImageView.setImageBitmap(result);
}
}.execute(itemUrl);
return convertView;
}
}
将AsyncTask放到适配器getView方法获取图片一屏的时候感觉不到问题,当我们图片很多时,上下滚动,这时会发现图片错位现象.
这是因为上下滚动时会不但重复调用getView方法启动AsyncTask.为了解决这个问题我们可以将AsyncTask进行保存,根据Url来控制是否启动AsyncTask,具体代码如下:
public void loadBitmap(Resources res,String imageUrl, ImageView imageView, int resId) {
if (cancelPotentialWork(imageUrl, imageView)) {
BitmapWorkerTask task = new BitmapWorkerTask(imageView);
AsyncDrawable asyncDrawable = new AsyncDrawable(res,
BitmapFactory.decodeResource(res, resId), task);
imageView.setImageDrawable(asyncDrawable);
task.execute(imageUrl);
}
}
public static boolean cancelPotentialWork(String imageUrl,
ImageView imageView) {
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
if (bitmapWorkerTask != null) {
final String bitmapData = bitmapWorkerTask.imageUrl;
if (!bitmapData.equals(imageUrl)) {
// Cancel previous task
bitmapWorkerTask.cancel(true);
} else {
// The same work is already in progress
return false;
}
}
// No task associated with the ImageView, or an existing task was
// cancelled
return true;
}
private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
if (imageView != null) {
final Drawable drawable = imageView.getDrawable();
if (drawable instanceof AsyncDrawable) {
final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
return asyncDrawable.getBitmapWorkerTask();
}
}
return null;
}
/**
* 创建一个专用的Drawable的子类来储存返回工作任务的引用。在这种情况下,当任务完成时BitmapDrawable会被使用
*
*/
static class AsyncDrawable extends BitmapDrawable {
private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
public AsyncDrawable(Resources res, Bitmap bitmap,
BitmapWorkerTask bitmapWorkerTask) {
super(res, bitmap);
bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>(
bitmapWorkerTask);
}
public BitmapWorkerTask getBitmapWorkerTask() {
return (BitmapWorkerTask) bitmapWorkerTaskReference.get();
}
}
class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private String imageUrl = "";
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage
// collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
// Decode image in background.
@Override
protected Bitmap doInBackground(String... params) {
imageUrl = params[0];
return downLoadBitmap(imageUrl);
}
// Once complete, see if ImageView is still around and set bitmap.
@Override
protected void onPostExecute(Bitmap bitmap) {
if (isCancelled()) {
bitmap = null;
}
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = (ImageView) imageViewReference
.get();
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
if (this == bitmapWorkerTask && imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}