Android相册功能技术实现细节

最近的一个demo是模拟手Q中发送图片界面,它实际上是一个由缩略图组成的预览界面,在开发过程中,遇到两个问题:

  1. 因为该界面是由缩略图组成,如果直接将原始图片加载到内存中来处理,有可能导致OOM(一张图片是很大的,况且有很多张图片),如何有效的获取原始图片的缩略图呢?

  2. 在demo的第一版中,图片能正确加载到界面,可是当我去滑动gridView时,会非常卡,这是什么原因导致,又该如何处理呢?

又是各种度娘,google,问题最终还是解决了,这里总结一下解决方案。

问题一:图片缩放


一般来说,取缩略图的方法是是使用BitmapFactory的decodeFile方法,通过BitmapFactory.Options的inSampleSize属性来控制缩放比例。属性值inSampleSize表示缩略图大小为原始的N分之几。然而,我们不可能将所有图片都加载到内存中来进行缩放操作,因为有些图片很大,而手机中内存又是很宝贵的,该怎么办呢?经研究发现,BitmapFactory.Options中有个inJustDecodeBounds属性,如果该值设置为true,,那么将不返回实际的bitmap,不给其分配实际的内存空间,而仅仅是一些图片大小信息。

有了这个属性,相应的方法就很简单了,可以先设置Options中有个inJustDecodeBounds为true,使用decodeFile获取图片的大小信息,计算出一个缩放比例(inSampleSize)后,再设置inJustDecodeBounds为false,将缩放后的图片加载到内存中。 具体代码如下:

private Bitmap getBitmapFromUrl(String path){
    Bitmap bitmap = null;
    //先从缓存中读取
    bitmap = gridviewBitmapCaches.get(path);
    if (bitmap != null) {
        return bitmap;
    }
    BitmapFactory.Options options = new BitmapFactory.Options();

    //设置inJustDecodeBounds为ture,来加载图片的边界信息
    ptions.inJustDecodeBounds = true;
    bitmap = BitmapFactory.decodeFile(path, options);

    //计算出实际的缩放比例
    int be = Math.min((int)(options.outHeight/(float)mImageHeight), (int)(options.outWidth/(float)mImageWidth));
    if (be <= 0) {
        be = 1;
    }
    options.inSampleSize = be;

    //现在讲inJustDecodeBounds重新设置为false,获取实际的缩放后的图片
    ptions.inJustDecodeBounds = false;
    bitmap=BitmapFactory.decodeFile(path,options);

    return bitmap;
}

问题二:GridView滑动的时候卡


在demo刚成型的时候,发现在滑动GridView的时候是很卡的,仔细想了想,终于发现问题所在,因为我是在主线程来加载图片,并更新UI,这样,IO本身就是一个耗时的操作,若将图片加载放到主线程来执行,必然会阻塞IO。知道了问题所在,解决问题的方法也就有了,即异步来加载图片。 Android规定只有主线程能更新UI,并提供了一些在新线程中来更新UI的方式,其中最简单,最轻量的莫过于使用AsyncTask了,AsyncTask的具体用法可以查阅相关的文档,这里给出具体的实现代码:

//这个是在GridViewAdapter中
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View view = converView;
    if (view == null) {
        view = getLayoutInflater().inflate(R.layout.qq_photo_select_item, null);
    }
    view.setLayoutParams(new GridView.LayoutParams(mImageWidth,
            mImageHeight));
    PhotoInfo imageInfo = getItem(position);
    ImageView imageView = (ImageView) view
            .findViewById(R.id.photo_select_item_photo_iv);
    imageView.setAdjustViewBounds(false);
    String path = imageInfo.getPath();
    AsyncLoadImageTask task = new AsyncLoadImageTask(imageView);
    task.execute(path);
}

//这里就是异步任务
private class AsyncLoadImageTask extends AsyncTask<String, Void, Bitmap> {
    private String url = null;
    private final WeakReference<ImageView> imageViewReference;
    public AsyncLoadImageTask(ImageView imageview) {
        super();
        // TODO Auto-generated constructor stub
        imageViewReference = new WeakReference<ImageView>(imageview);
    }


    @Override
    protected Bitmap doInBackground(String... params) {
        Bitmap bitmap = null;
        this.url = params[0];
        bitmap = getBitmapFromUrl(url);
        MainActivity.gridviewBitmapCaches.put(url, bitmap);
        return bitmap;

    }

    @Override
    protected void onPostExecute(Bitmap resultBitmap) {
        if (imageViewReference != null) {
            ImageView imageview = imageViewReference.get();
            imageview.setImageBitmap(resultBitmap);
        }
    }
}   

问题解决,当然,这里还有很多优化的时候,比如在滑动GridView的时候,在它的滑动事件里,去recycle(对于那些不可见的convertView)相应的bitmap。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值