Android加载网络图片

    |     2015年8月14日   |   网络通讯   |     0 条评论   |    2614

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显示加载中效果如下
imageloader1

接着我们在来看下实现多图加载操作
获取图片资源方式和单张图片一样,显示控件我们换用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;
	}

}

效果如下:
imageloader2

将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);
			}
		}
	}
}
转载请注明来源:Android加载网络图片

上一篇:

下一篇:

回复 取消