1. Bitmap位图解码
 Android设备系统资源是有限的,会给单独的应用分配大概16MB的内存。如果Bitmap资源太大,会造成内存溢出。
示例:让一个很大的图片,以一个比例缩小后显示在一个ImageView中。
1. 在Activity中,点击按钮显示图片 
button.setOnClickListener(new View.OnClickListener() {public void onClick(View v) {Bitmap bm = BitmapTools.decodeBitmap(getResources(),R.drawable.a, 50, 50);imageView.setImageBitmap(bm);}});
2. 定义一个Bitmap工具类
public class BitmapTools {public BitmapTools() {}/**@param resources        资源文件 * @param resId            解码位图的id * @param reqWith          指定输出位图的宽度 * @param reqHeight        指定输出位图的高度 */public static Bitmap decodeBitmap(Resources resources, int resId,int reqWith, int reqHeight) {// 对位图进行解码的参数设置BitmapFactory.Options options = new BitmapFactory.Options();// 在对位图进行解码的过程中,避免申请内存空间options.inJustDecodeBounds = true;BitmapFactory.decodeResource(resources, resId, options);// 对图片进行一定比例的压缩处理options.inSampleSize = calculateInSimpleSize(options, reqWith,reqHeight);options.inJustDecodeBounds = false;// 真正输出位图return BitmapFactory.decodeResource(resources, resId, options);}public static int calculateInSimpleSize(BitmapFactory.Options options,int reqWith, int reqHeight) {// 获得图片的原始宽高int imageHeight = options.outHeight;int imageWidth = options.outWidth;int inSimpleSize = 1;// 压缩比例if (imageHeight > reqHeight || imageWidth > reqWith) {final int heightRatio = Math.round((float) imageHeight/(float) reqHeight);final int widthRatio = Math.round((float)imageWidth/(float)reqWith);inSimpleSize = heightRatio < widthRatio ? heightRatio : widthRatio;}return inSimpleSize;}}
假如要用到一张1024*768像素的图片,它最终是以128*96像素显示在一个ImageView当中的。
这就要decoder对图片做二次抽样,导入一张小版本的图片到内存中,并设置BitmapFactory.Options的 inSampleSize为true.这个值表示压缩的比较,如为3,就为原来的1/3。

2. Bitmap UI加载大位图处理
加载位图的时间是不确定的,一旦这些任务阻塞了UI线程,那么Ui就无反应了。可以用异步任务来完成。
这个例子要实现的效果:定义一个数组保存了大量大像素的网络图片的地址,通过异步任务把它们下载下来,并进行解码。在Activity中显示上下划动时,看不见的就释放掉,重新加载图片。
1) 图片下载工具类
public class HttpUtils {public HttpUtils() {}public static byte[] sendPost(String path) {HttpClient httpClient = new DefaultHttpClient();HttpPost httpPost = new HttpPost(path);HttpResponse response = null;try {response = httpClient.execute(httpPost);if (response.getStatusLine().getStatusCode() == 200) {return EntityUtils.toByteArray(response.getEntity());}} catch (Exception e) {e.printStackTrace();} finally {httpClient.getConnectionManager().shutdown();}return null;}}
2)图片解码类与上面的一样,但是图片来源不同,有些小修改
public static Bitmap decodeBitmap(byte[] data, int reqWith, int reqHeight) {// 对位图进行解码的参数设置BitmapFactory.Options options = new BitmapFactory.Options();// 在对位图进行解码的过程中,避免申请内存空间options.inJustDecodeBounds = true;BitmapFactory.decodeByteArray(data, 0, data.length, options);// 对图片进行一定比例的压缩处理options.inSampleSize = calculateInSimpleSize(options, reqWith,reqHeight);options.inJustDecodeBounds = false;// 真正输出位图return BitmapFactory.decodeByteArray(data, 0, data.length, options);}
3)Activity
public class MainActivity extends Activity {private ListView listView;// 图片的链接private String[] imageUrls = Images.imageUrls;private ImageAdapter adapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);listView = (ListView) this.findViewById(R.id.listView1);adapter = new ImageAdapter();listView.setAdapter(adapter);adapter.notifyDataSetChanged();}public class ImageAdapter extends BaseAdapter {@Overridepublic int getCount() {return imageUrls.length;}@Overridepublic Object getItem(int position) {return imageUrls[position];}public long getItemId(int position) {return position;}public View getView(int position, View convertView, ViewGroup parent) {View view = null;if (convertView == null) {view = LayoutInflater.from(MainActivity.this).inflate(R.layout.item, null);} else {view = convertView;}ImageView imageView = (ImageView) view.findViewById(R.id.imageView1);// 从网络中获取数据,填充到imageview中// 可能会造成图片的错位:loadBitmap(imageUrls[position], imageView);return view;}}/** * 在滑动这些ListView的时候,会对就的布局进行资源回收,如果ListView结合异步任务操作的时候,不能确保重用的布局被及时回收 */static class AsyncDrawable extends BitmapDrawable {private final SoftReference softReference;public AsyncDrawable(Resources resources, Bitmap bitmap,BitmapWorkerTask bitmapWorkerTask) {super(resources, bitmap);softReference = new SoftReference(bitmapWorkerTask);}public BitmapWorkerTask getBitmapWorkerTask() {return softReference.get();}}/** 异步任务 */class BitmapWorkerTask extends AsyncTask {private SoftReference imageSoftReference;private String data = "";public BitmapWorkerTask(ImageView imageView) {imageSoftReference = new SoftReference(imageView);}protected Bitmap doInBackground(String... params) {data = params[0];byte[] result = HttpUtils.sendPost(data);// 解码过程return BitmapTools.decodeBitmap(result, 100, 100);}protected void onPostExecute(Bitmap bitmap) {super.onPostExecute(bitmap);if (isCancelled()) {bitmap = null;}if (imageSoftReference != null && bitmap != null) {final ImageView imageView = imageSoftReference.get();final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);if (this == bitmapWorkerTask && imageView != null) {imageView.setImageBitmap(bitmap);}}}}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;}public static boolean cancelPotntialWork(String data, ImageView imageView) {final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);if (bitmapWorkerTask != null) {final String bitmapData = bitmapWorkerTask.data;if (bitmapData != data) {bitmapWorkerTask.cancel(true);} else {return false;}}return true;}/** * 加载图片 */public void loadBitmap(String data, ImageView imageView) {Bitmap placeBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.empty_photo);if (cancelPotntialWork(data, imageView)) {final BitmapWorkerTask task = new BitmapWorkerTask(imageView);final AsyncDrawable asyncDrawable = new AsyncDrawable(getResources(), placeBitmap, task);imageView.setImageDrawable(asyncDrawable);task.execute(data);}}}

getView()中convertView被不断的重复使用,可能会导致旧的引用不会被及时释放,从而造成图片错位的问题。
并发的问题:
普通的View,如ListView 和GridView在联合异步任务加载资源的时候,可能会导致图片错位和占用内存过大的问题。
在view划动的过程中,系统会对view资源进行回收。要被回收的view,使用到异步任务加载的时候,就不能确保它会被及时回收。因为异步任务和view是分别在两个不同的线程中的。所以这里的话使用了SoftReference来保证资源能够被回收。

更多相关文章

  1. Android 绘制一个Loading动画__向图片中缓慢填充颜色,从而形成动
  2. 如何在Android当中显示网络图片
  3. Android 使用javaMail jar包发送邮件到指定邮箱,并可以发送图片附
  4. Android 使用ArrayAdapter 加载Bean数据
  5. 从零开始搞懂Android网络请求——异步加载ListView
  6. Android:ImageView图片缩放、居中
  7. Android调用摄像头识别图片的形状和颜色怎么做
  8. [Android1.5]标签TabHost图片文字覆盖的问题

随机推荐

  1. 学 Win32 汇编[34] - 宏汇编(1)
  2. 学 Win32 汇编[23] - 位测试与位扫描指令
  3. 学用 ASP.Net 之 "字符串" (1): 基础
  4. 学 Win32 汇编[15]: LOOP 与标号
  5. 学 Win32 汇编[24] - 移位: SHL、SHR、SA
  6. 学用 ASP.Net 之 "字符串" (2): string.F
  7. 学 Win32 汇编[16]: 常用寄存器的常规功
  8. 学 Win32 汇编[25] - 符号扩展指令: CBW
  9. 学用 ASP.Net 之 "字符串" (3): string
  10. 学 Win32 汇编[17]: 关于压栈(PUSH)与出