Android换肤功能设计与实现(5)——网络加载及图片内存管理

    在开发Android客户端应用时,经常要与Server端进行通信,最常用的也是最麻烦的就是 通过网络加载各种图片资源。由于与PC相比,手机的内存实在少的可怜。同时,为了提手机内同时运行的任务数,Android在系统 内对虚拟机是有最高内存限制的,默认在4.0上APP最高内存占用为48MB,在3.0以前最高位32MB。以上就是在开发Android客户端经常要面对的两个最主要的问题,下面一一进行解决。

    一、网络加载技术

    想要快速的实现网络加载,可以从2各方面入手,一个是与Server端的通讯协议;第二个就是提高自身加载速度。

    首先,与Server端的通讯协议,可以采用分段加载的方式,就是在加载过程中,分为两个阶段,一个是加载整体数据的阶段,另一个是加载具体资源阶段。我们在浏览网页时经常就是通过这种方式提高访问速度,提升访问体验的。具体 就是首先获取整个页面的文字内容,获取各个图片资源的大小信息,进行页面的布局排版。之后根据具体浏览的位置,再单独发送请求,获取具体的图片资源,从而实现页面的快速显示,同时节省网络流量。为了实现这种访问方式,在客户端通过Bitmap加载网络图片时,可以通过2段访问的方式,及先获取Bitmap大小,需要时再去获取真正资源,从而大大提升页面加载速度。

 private BitmapFactory.Options mOption; 
 mOption = new BitmapFactory.Options();
mOption.inSampleSize = 1;  
 //只进行大小判断   
mOption.inJustDecodeBounds = true;  
 BitmapFactory.decodeStream(new URL(imageUrl).openStream(),null,mOption);
  if(mOption.outHeight > 210){
         mOption.inSampleSize = 4;
                    }
  mOption.inJustDecodeBounds = false;                                      
 Bitmap drawable = BitmapFactory.decodeStream(new URL(imageUrl)
                            .openStream(),null,mOption);

    其次,就是客户端在访问Server端时,采用多线程访问的技术,同步发起资源请求,可以大大提高资源访问及申请的速度。这里比较常用的手段是采用线程池来管理资源的请求与管理。线程池拥有自己的执行队列,自动将执行请求进行队列缓存,按顺序执行请求。线程池可以有效避免手动创建线程的线程开销,线程池自动维护执行线程,在有执行请求时,不会销毁执行线程。

    private ExecutorService executorService;
        executorService = new ThreadPoolExecutor(CORE_THREAD_SIZE, MAX_THREAD_SIZE, 120, TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(),
                Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());
executorService.submit(new Runnable() {public void run() {}
        }

    二、网络图片资源加载及内存管理

    在进行客户端开发时,经常要面对的就是网络加载大量的图片,而每一张图片又是即时加载,需要手动释放资源,否则在加载新图片时经常出现OOM(Out of Memory)问题。同时为了界面显示浏览的流畅性,又需要在一定程度上、内存允许范围内的缓存请求。如何在平衡这两方面的问题,避免出现OOM,提高APP的稳定性那。这里提两个简单有效、实用的方式。

    首先,根据具体的资源大小分别进行管理,这是在缓存、加载中需要处理的第一个问题,需要根据具体的需求,哪些资源对缓存的需求更强烈,那些资源对释放更迫切。使用不同的资源访问、管理方式。

    接下来就根据资源的简单分类分别进行访问、管理;对于释放要求更迫切的资源来说,我们可以采用二级缓存、同步释放的方式。简单来说就是在访问网络资源获取后,复制到内部固定缓存空间,同步释放网络加载资源。

private static Bitmap mBigBitmap[] = new Bitmap[HorizontalViewer.MAX_PREVIEW_PICS];
    static{
        for(int i=0;i<HorizontalViewer.MAX_PREVIEW_PICS;i++){
//            mDrawBitmap[i] = Bitmap.createBitmap(IMAGE_WIDTH, IMAGE_HEIGHT, Config.ARGB_8888);
            mBigBitmap[i] = Bitmap.createBitmap(BIG_IMAGE_WIDTH, BIG_IMAGE_HEIGHT, Config.ARGB_8888);
        }
    }
Bitmap drawable = BitmapFactory.decodeStream(new URL(imageUrl)
                     .openStream(),null,mOption);

        mCanvas = new Canvas(mBigBitmap[inx]);
        mCanvas.drawBitmapdrawable new Rect(0,0,imageDrawable.getWidth(),imageDrawable.getHeight()), 
                new Rect(0,0,BIG_IMAGE_WIDTH,BIG_IMAGE_HEIGHT), null);
if (!drawable.isRecycled()) {
     drawable.recycle();
  }


通过Canvas实现对图片资源的快速复制,由于在复制过程中,Bitmap底层直接采用内存拷贝的方式进行,在效率上非常高,通过固定使用static的Bitmap缓冲池,使资源占用在一个定值内,网络异步加载的资源,在拷贝完后,迅速释放,避免内存的过高占用。

    而对于缓存需求更强烈的资源来说,在访问过程中,可以采用弱引用的方式,进行加载与管理,在系统资源满足要求的情况下,系统不会释放弱引用所指向的资源,在资源紧张下,自动回收若引用资源。这样刚好满足我们对资源缓存的要求。

    public Map<String, WeakReference<Bitmap>> imageCache = new HashMap<String, WeakReference<Bitmap>>();
    public Bitmap loadSmallDrawable(final String imageUrl, final ImageCallback callback) {
        /* 方案 :小图片的缓冲比较多 */

        if (imageCache.containsKey(imageUrl)) {
            WeakReference<Bitmap> softReference = imageCache.get(imageUrl);
            
            if (softReference.get() != null) {
                if (callback != null) {
                    callback.imageLoaded(softReference.get());
                }
                return softReference.get();
            }
        }
        if (callback == null)
            return null;
        // 缓存中没有图像,则从网络上取出数据,并将取出的数据缓存到内存中
        executorService.submit(new Runnable() {
            public void run() {
                try {

                    Bitmap drawable = BitmapFactory.decodeStream(new URL(imageUrl)
                            .openStream(),null,mOption);

                    drawable = Bitmap.createScaledBitmap(drawable, 120, 200, true);
//                    drawable.recycle();

                    imageCache.put(imageUrl, new
                    WeakReference<Bitmap>(drawable));
                    Log.e(TAG, "get a drawable");

    
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });
        return null;
    }

    通过以上技术基本可以满足Android客户端访问网络加载资源的需求,最后一点需要注意的就是对资源的访问,尽量做到提前预知资源大小,尽量避免对图片的资源的二次加工。简单来说就是对网络加载的资源,尽量减少在内部的缩放、Alpha等的重新改变,主要由于对Bitmap的各种改变,系统都是重新创建资源,这样就导致内存空间的浪费,及比较高的时间代价。在访问资源时,通过改变采样率等方式,有效避免这种情况的发生。

    private BitmapFactory.Options mOption;
    mOption = new BitmapFactory.Options();
    mOption.inSampleSize = 1;  
    //只进行大小判断   
    mOption.inJustDecodeBounds = true;   
    BitmapFactory.decodeStream(new URL(imageUrl)
          .openStream(),null,mOption);
    if(mOption.outHeight > 210){
            mOption.inSampleSize = 4;
          }
     mOption.inJustDecodeBounds = false;                     

     Bitmap drawable = BitmapFactory.decodeStream(new URL(imageUrl)
               .openStream(),null,mOption);

            

                     ——欢迎转载,请注明出处http://blog.csdn.net/zyplus——



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值