在开发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——



更多相关文章

  1. Android中ListView的使用及优化
  2. Android(安卓)图片资源的异步加载2
  3. Android优秀开发资源
  4. android http中请求访问添加 cookie
  5. 4.1 Android如何访问资源
  6. 如何有效的清除Android中无用的资源(静态代码分析)
  7. API 25 (Android(安卓)7.1.1 API) widget.ProgressBar——属性分
  8. android反射方式访问内部类成员
  9. android hardware 简述(Android系统源码情景分析 笔记)

随机推荐

  1. Android修改system只读权限
  2. RelativeLayout常用布局属性
  3. Android中使用Build获取当前系统SDK版本
  4. 【Android API】Android 4.1 API官方文档
  5. android4.2 webkit 中的jni
  6. Android(安卓)ril移植-6410开发板SIM300
  7. BlueStacks 进入 beta 1 阶段,给 Windows
  8. 安卓中TextView显示长度的控制
  9. Android工程下的文件介绍
  10. Android studio 卡的问题