Bitmap的三级缓存----封装BitmapLoader

public class BitmapLoader {
    MainActivity context;
    
    LruCache<String, Bitmap> lruCache;

    private File cacheDir ;
    public static final Executor THEAD_POOL_EXECUTOR= Executors.newFixedThreadPool(3);



    public BitmapLoader(MainActivity context) {
          this.context=context;
          cacheDir = context.getCacheDir();            //!!!本地文件路径获取!!
          int maxSize = (int) (Runtime.getRuntime().freeMemory() /2);
          lruCache = new LruCache<String, Bitmap>(maxSize) {

            @Override
            protected int sizeOf(String key, Bitmap value) {
                // TODO Auto-generated method stub
                return value.getRowBytes() * value.getHeight();
            }

        };


        //存储缓存

    }


//
    private Bitmap loadBitmap(String url) {
        //从内存获取
         Bitmap bitmap =loadFromMemCache(url);
       
        if(bitmap!=null){
            Log.d("加载","从内存中获取");
            return bitmap;
        }

        //从存储内存中获取
        bitmap=loadFromFileCache(url);

        if(bitmap!=null){
            Log.d("加载","从文件中获取");
            return bitmap;
        }
          else {
            //从网络获取
            bitmap=downLoadFromNet(url);
            Log.d("加载","从网络中获取");
            return  bitmap;
        }


    }

    //显示 开启一个线程池 先得到图片,然后在主线程,将图片绑定
    public void  displayBitmap(final String url, final ImageView imageView){

        Runnable loadBitmapTask=new Runnable() {
            @Override
            public void run() {
              final   Bitmap bitmap=loadBitmap(url);
                if(bitmap!=null){
                    //获取到主线程 重新在主线程中调用该方法!!这里是这样处理线程不能改变界面的问题的!
                    context.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            imageView.setImageBitmap(bitmap);
                        }
                    });
                }
            }

        };
        //在线程池中加载图片
        THEAD_POOL_EXECUTOR.execute(loadBitmapTask);


    }
    //加密
    public  void   putToMemCache(String url,Bitmap bitmap){
        //把Url做Md5加密处理
        lruCache.put(url,bitmap);
    }


    //不带算法的文件存储方式
    public void saveBitmapToCacheFile(Bitmap bitmap,String ivUrl) {
        File file = new File(cacheDir,Md5Utils.md5(ivUrl));
        try {
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(file));
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


    /***
     * 从内存中获取
     * @param key
     * @return
     */
    public Bitmap loadFromMemCache(String  key){
        //将url进行解密处理,然后获取
        Bitmap bitmap = lruCache.get(key);
        if(bitmap!=null){
            Log.d("获取非数据","11");
        }
            Log.d("获取空数据","11"+key);

        return bitmap;

    }

     * @param ivUrl
     *     当做缓存图片的名字
     * @return
     * 从文件中获取
     */
    public Bitmap loadFromFileCache(String ivUrl){
        //把ivUrl转换MD5值,再把md5 做文件名
        File file = new File(cacheDir,Md5Utils.md5(ivUrl));
        if (file != null  && file.exists()) {
            //文件存在
            //把文件转换成bitmap
            Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());

            if(bitmap!=null){
                Log.d("写入","写入成功"+ivUrl);
                putToMemCache(ivUrl, bitmap);
            }else{
                Log.d("写入","写入空数据");
            }
            //再往内存写


            return bitmap;
        } else {
            return null;
        }

    }

    /**
     *
     * @param bPurl
     * @return
     * 从网络中获取
     */
    public  Bitmap downLoadFromNet(final String bPurl) {
        //开启线程! 获取Bitmap
        //这里可以用线程池处理?
        Bitmap bitmap=null;
        HttpURLConnection connection = null;
        try {

            URL url1 = new URL(bPurl);
            connection = (HttpURLConnection) url1.openConnection();
            connection.setReadTimeout(8000);
            connection.setRequestMethod("GET");
            InputStream inputStrearms = connection.getInputStream();

            bitmap = BitmapFactory.decodeStream(inputStrearms);
            //本地存储
            saveBitmapToCacheFile(bitmap,bPurl);

            putToMemCache(bPurl,bitmap);

        } catch (ProtocolException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally {
            if(connection!=null){
                connection.disconnect();
            }
        }


        return bitmap;

    }



}


缓存思想:

先内存,没有本地,内有网络

并在获取后向下添加数据,以求减少流量损耗!

而缓存的思想是当 所用容器满时 则自动删除旧的数据,存入新的数据从而达到缓存的目的

LruCache 就是 这种算法的容器。支持泛型什么的。。。。。。


1.线程问题的注意: 线程池 加handler 或主线程RunOnuiTHeard!!
如何异步处理时通过子线程更新UI的?

2.通过线程池 和Handler进行处理!(需要判断当前运行该方法的线程是否为主线程如果是则不可以)

  这里进行了简化处理直接获取到主Activity 并runOnUIThread();


3.为什么采用线程池处理而不采用线程?: 因为在列表下滑是可能产生大量的线程!!
AsyncTask 为什么不适用? 因为无法实现并发效果!


线程池的使用方式:

如上方式


4.复用错位问题处理?
由于多线程 和 复用问题 所以可能会出现由于 线程过慢加载引发的图片错位问题

解决方式:保存URL并判断是否为最新的URL

采用HashMap作为存储容器,当KEY相同值不同时 再次赋值,此时的Value将会被覆盖。

//保留最后一次访问url的信息
	private Map<ImageView,String> urlImageViewDatas = new HashMap<ImageView, String>();
	


从网络获取后,将URL保留。

// 3. 从网络取
		urlImageViewDatas.put(iv, ivUrl);//保留最后一次访问的url
当缓存的内容线程加载过慢而,本该显示新的URL内容的view给覆盖了,因这个被复用的view本应该显示新的URL的内容。‘

所以当缓存的view加载图片是要先判断,URL是否发生了改变,如果发生改变 ,就该设置最新的URL的内容。


在设置前判断是否是最新的URL

							// 显示图片
							// 判断url是不是最新的
							//是最新的 自己的数据
							if (ivUrl.equals(urlImageViewDatas.get(iv))) {
								//自己的数据
								iv.setImageBitmap(bitmap);
							}


解决图片错位的整体代码:

public void  displayBitmap(final String url, final ImageView imageView){

        Runnable loadBitmapTask=new Runnable() {
            @Override
            public void run() {
                final   Bitmap bitmap=loadBitmap(url);

                   //在此处将URL记录下来
                // 3. 从网络取
                urlImageViewDatas.put(bitmap,url);//保留最后一次访问的url

                if(bitmap!=null){
                    //获取到主线程 重新在主线程中调用该方法!!这里是这样处理线程不能改变界面的问题的!
                    context.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            //在这之前监测URL是否发生了改变?
                            if (url.equals(urlImageViewDatas.get(url))) {
                                //自己的数据
                                imageView.setImageBitmap(bitmap);
                            }

                        }
                    });
                }
            }

        };


5.没有采用存储缓存 因为不是SDK里的内容 且 更加复杂,用editer 的方法进行写入和读出, 同样是用LRU算法

6.在添加缓存前可对图片进行压缩,听过Options参数 进行采样缩放 !通过裁剪 减少出现内存溢出的问题!

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

上面的一切没看懂不要紧。

框架开始了!!!

Universal Image Loader 框架! jar包 gihub上有

1.apllacation 配置:

 ImageLoaderConfiguration configuration = ImageLoaderConfiguration
                .createDefault(this);

        //Initialize ImageLoader with configuration.
        ImageLoader.getInstance().init(configuration);


2.缓存的参数配置:

   DisplayImageOptions options = new DisplayImageOptions.Builder()
                      .resetViewBeforeLoading(false)  // default
                       .delayBeforeLoading(1000)
                       .cacheInMemory(false) // default
                       .cacheOnDisk(false) // default
                       .considerExifParams(false) // default
                       .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default
                       .bitmapConfig(Bitmap.Config.ARGB_8888) // default
                       .displayer(new SimpleBitmapDisplayer()) // default
                       .handler(new Handler()) // default
                       .build();
               ImageSize mImageSize = new ImageSize(100, 100);
               //显示图片的配置
               DisplayImageOptions optionss = new DisplayImageOptions.Builder()
                       .cacheInMemory(true)
                       .cacheOnDisk(true)
                       .bitmapConfig(Bitmap.Config.RGB_565)
                       .build();


3.绑定并完成简单的监听过程,包括图片加前后的默认图片等等:

   ImageLoader.getInstance().loadImage(newsListData.get(position).getListimage(),mImageSize, optionss,  new SimpleImageLoadingListener(){

                   @Override
                   public void onLoadingComplete(String imageUri, View view,
                                                 Bitmap loadedImage) {
                       super.onLoadingComplete(imageUri, view, loadedImage);
                       finalHolder.iv_newspic.setImageBitmap(loadedImage);
                   }

               });
               return convertView;
           }

用这个框架的好处是,避免了OOM和,并处理了缓存,同时,可以进行大小缩放 图片旋转的各种功能!!!!!

同类框架:picasso!!



----------------------------------------

Bitmap  转换时 可以通过BitmapFactory 进行缩放和设定(减少图片所占的内存)

Android中BitmapFactory.Options

(1 / inSampleSize) 2的幂函数 等其他

详细参数配置地址:

http://blog.csdn.net/haozipi/article/details/47183543?ref=myread




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值