接上节,上节记录了Bitmap的加载,用上节的方法,我们可以方便地压缩图片,进行加载。
然而,有时候,当出来大量的图片或者是一张大图要加载时,这一过程所花的时间就会显得很长。甚至长到用户可以感觉出来,即UI的卡顿。因此,我们需要一个方法让图片自己加载去吧,不能干扰用户的操作。所以,我们需要用一个新的线程来完成图片加载的操作。其中最简单便捷的方法,就是Use an AsyncTask。
首先创建一个AsyncTask的子类:
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> { private final WeakReference<ImageView> imageViewReference; private int data = 0; private int width , height; public BitmapWorkerTask(ImageView imageView , int width , int height) { // Use a WeakReference to ensure the ImageView can be garbage collected imageViewReference = new WeakReference<ImageView>(imageView); this.width = width; this.height = height; } // Decode image in background. @Override protected Bitmap doInBackground(Integer... params) { data = params[0]; return decodeSampledBitmapFromResource(getResources(), data, width, height); } // Once complete, see if ImageView is still around and set bitmap. @Override protected void onPostExecute(Bitmap bitmap) { if (imageViewReference != null && bitmap != null) { final ImageView imageView = imageViewReference.get(); if (imageView != null) { imageView.setImageBitmap(bitmap); } } } }
其中,第一个参数是需要加载的图片的Id;
PS:WeakReference<ImageView> imageViewReference 为弱引用。
- A
WeakReference
may be cleared and enqueued as soon as is known to be weakly-referenced.
当GC启动时弱引用会自动被回收,这里使用弱引用,防止了内存溢出。
然后,创建这个加载图片类的对象,并在合适的时候执行这个异步任务。
testButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int width = gridLayout.getWidth()/50; int height = gridLayout.getHeight()/50; Toast.makeText(getApplicationContext(),width+","+height,Toast.LENGTH_SHORT).show(); BitmapWorkerTask task = new BitmapWorkerTask(imageView1,width,height); task.execute(R.drawable.ic_launcher_big); } });
以上。
然而,这也是有缺陷的。有时候我们需要加载的不只一张图。为了在存在多张图可能需要加载时,不影响系统的效率。组件回收器会在用户滑动屏幕时进行回收,将不出现在用户视野中的界面回收掉。在上面的方法中,每次加载都需要重开一个AsyncTask。有可能这张图还没有加载完,用户已经把这张图滑走了,我们需要用内存加载下一张图了。怎么处理?下回再写吧。。。