LrcCache和DiskLruCache相结合打造图片加载框架

LrcCache和DiskLruCache相结合打造图片加载框架

1概述

这几在研究图片加载的方面的知识,在网上看了一下前辈们写的文章,受到了一些启发,于是综合多方面的知识,将这些整合起来,自己边写了一个图片加载框架。说到图片加载最容易出问题的就是OOM就是内存溢出,所以一定要限制加载图片时使用的内存,这就使用到Android提供的缓存类LruCache,关于LruCache的知识这里不再赘述,大家自行学习。但是如果图片非常的多而且频繁操作的话,加上LruCache的缓存空间有限,缓存就不得不经常更新,效果会大打折扣,于是就想到使用LruCache和DiskLruCache结合起来,做一个二级缓存。DiskLruCache使用的手机的SD卡或者手机存储作为缓存,不占用手机App运行时占用的内存。

2缓存

主要思路,得到的图片Bitmap存入LruCache中,如果LruCache如果空间不够使用会按照最近最少使用的原则去把最近最少使用的Bitmap删除。将LruCache删除的Bitmap存入DiskLruCache缓存中,实现二级缓存。

2.1 改造LruCache

由于Android提供LruCache 在删除最近最少使用的对象时是直接删除对象,但是我要的是将删除的对象返回,并存入到DiskLruCache中,所有要对LruCache进行改造。由于LruCache的缓存方法public final V put(K key, V value)如下,不能重写,所有只能重新写一个与LruCache一样的类,复制LruCache的所有方法过来,但是单独改写public final V put(K key, V value)以及相关的private void trimToSize(int maxSize)。
 

public final Vput(K
key, V value) {

if (key == null|| value ==
null) {

throw new NullPointerException("key == null || value == null");

}

V previous;

synchronized (this) {

putCount++;

size += safeSizeOf(key, value);

previous = map.put(key, value);

if (previous !=
null
) {

size -= safeSizeOf(key, previous);

}

}

if (previous != null) {

entryRemoved(false, key, previous, value);

}

trimToSize(maxSize);

return previous;

}

重新建立类BitmapLruCache,重新写public finalV
put(Kkey, V
value)和private voidtrimToSize(int
maxSize)方法。

/**
 * 将对象加入缓存,如果缓存已经满,则删除最近最少使用的对象,并返回被删除的对象列表
 * @param key
 * @param value
 * @return
 */
public final LinkedHashMap<K, V> put(K key, V value) {
    if (key == null || value == null) {
        throw new NullPointerException("key == null || value == null");
    }

    V previous;
    synchronized (this) {
        putCount++;
        size += safeSizeOf(key, value);
        previous = map.put(key, value);
        if (previous != null) {
            size -= safeSizeOf(key, previous);
        }
    }

    if (previous != null) {
        entryRemoved(false, key, previous, value);
    }
   
    return trimToSize(maxSize);
}
/**
 * 删除最近最少使用对象,并返回被删除的对象列表
 * @param maxSize
 * @return
 */
public LinkedHashMap<K, V> trimToSize(int maxSize) {
   LinkedHashMap<K, V> trimMap =  new LinkedHashMap<K, V>(0, 0.75f, true); //被删除的对象列表
    while (true) {
        K key;
        V value;
        synchronized (this) {
            if (size < 0 || (map.isEmpty() && size != 0)) {
                throw new IllegalStateException(getClass().getName()
                        + ".sizeOf() is reporting inconsistent results!");
            }

            if (size <= maxSize || map.isEmpty()) {
                break;
            }

            Map.Entry<K, V> toEvict = map.entrySet().iterator().next();
            key = toEvict.getKey();
            value = toEvict.getValue();
            trimMap.put(key, value);     //添加被删除的对象
            map.remove(key);
            size -= safeSizeOf(key, value);
            evictionCount++;
        }

        entryRemoved(true, key, value, null);
    }
   
    return trimMap;
}
 

2.2 DiskLruCache

对应DiskLruCache大家可以学习这篇文章http://blog.csdn.net/guolin_blog/article/details/28863651,说的非常好,我就不赘述了。

2.3 LruCache和DiskLruCache相结合

建立BitmapCacheL2类,结合LrcCache和DiskLruCache,写缓存方法。
在构造方法初始化LrcCache和DiskLruCache
 
public BitmapCacheL2(Context context){
   mLrcCache = new BitmapLruCache<String, Bitmap>(mCacheSize){
      @Override
      protected int sizeOf(String key, Bitmap value) {
         // TODO Auto-generated method stub
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
            return value.getByteCount();
         } else {
            return value.getRowBytes() * value.getHeight();
         }
         // Pre HC-MR1

      }
   };

   //start 初始化手机SD存储缓存
   File cacheDir = getDiskCacheDir(context, "thumb");
   if (!cacheDir.exists()) {
      cacheDir.mkdirs();
   }
   // 创建DiskLruCache实例,初始化缓存数据
   try {
      mDiskLruCache = DiskLruCache
            .open(cacheDir, getAppVersion(context), 1, MAX_FILE_SIZE);
   } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
   }
   //end 初始化手机SD存储缓存
}
 

BitmapCacheL2  最主要的的两个方法分别是添加缓存和取出缓存的方法如下

/**
 * 保存bitmap到缓存
 * @param url
 * @param bitmap
 */
public void putBitmap(String url, Bitmap bitmap) {
   Log.i(tag, "putBitmap *** ");
   //start 将bitmap存入内存缓存,如果已经存满,则删除最近最少使用的bitmap,并返回被删除的bitmap对象列表
   LinkedHashMap<String, Bitmap> trimMap;
   trimMap = mLrcCache.put(url, bitmap);
   putBitmap2DiskLruCache(url,bitmap);
   //end 将bitmap存入内存缓存,如果已经存满,则删除最近最少使用的bitmap,并返回被删除的bitmap对象列表

   //start 将被LrucCache删除的bitmap存入DiskLruCache
   if(null!=trimMap && !trimMap.isEmpty()){
      Log.i(tag, " LruCache--->DiskCache");
      Iterator<?> it = trimMap.entrySet().iterator();
      while(it.hasNext()){
         Entry<String, Bitmap> entry = (Entry<String, Bitmap>) it.next();
         putBitmap2DiskLruCache(entry.getKey(), entry.getValue());//向DiskLruCache添加缓存
      }
   }
   ///end 将被LrucCache删除的bitmap存入DiskLruCache

}
/**
 * 从缓存获取bitmap
 */
public Bitmap getBitmap(String url) {
   // TODO Auto-generated method stub
   Log.i(tag, "getBitmap ***");
   //首先从手机内存缓存中获取
   Bitmap map = mLrcCache.get(url);

   //手机内存缓存没有,再从手机SD存储缓存中获取
   if(null==map){
      map = getBitmapFromDiskLruCache(url);
   }

   return map;
}

3图片加载类SDImageLoader

图片加载类的主要工作过程:首先查找缓存,找到相应Bitmap则返回Bitmap,如果没有则根据路径从本地加载或者从网络下载;将从本地加载或者从网络下载Bitmap加入到缓存中,并刷新UI。当然加载图片Bitmap的操作都是在线程中进行的,为了管理这些线程,我建立了线程池,和用于管理线程池的线程,和线程池执行的任务队列,线程的调度方式有两种FIFO或者LIFO。

3.1图片加载类初始化

图片加载类使用单例模式:

/**
 * 获取实例对象
 * @param context
 * @param mThreadCount  并行线程数量
 * @param type          任务执行顺序
 * @return
 */
public static SDImageLoader getInstance (Context context,int mThreadCount,Type type) {
    if(null==mInstace){
        synchronized (ImageLoader.class) {
            if(null == mInstace) {
                mInstace = new SDImageLoader(mThreadCount,type,context);
            }
        }
    }
    return mInstace;
}

初始化图片加载类:

/**
     * 初始化
     * @param mThreadCount  线程数量
     * @param type           调度类型
     * @param context
     */
    private void init(int mThreadCount,Type type,Context context) {
        mSemaphonreThreadPool = new Semaphore(mThreadCount);  //任务执行信号量
       
        //start 初始化控制线程池任务执行的线程
        mPoolThread = new Thread() {
            @Override
            public void run() {
                super.run();
                Looper.prepare();
                mPoolThreadHandler = new Handler () {
                    @Override
                    public void handleMessage(Message msg) {
                        super.handleMessage(msg);
                       
                        try {
                            mSemaphonreThreadPool.acquire();
                          //线程池去取出一个任务执行
                            mThreadPool.execute(getTask());
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                };
                mSemaphorePoolThreadHandler.release();
                Looper.loop();
            }
        };
        mPoolThread.start();
      //start 初始化控制线程池任务执行的线程
       
/*        int maxMemory = (int)Runtime.getRuntime().maxMemory();
        int cacheMemory = maxMemory/8;*/

      mLruCache = new BitmapCacheL2(context);    //缓存
mTaskQueue = new LinkedList<Runnable>();  //任务队列
mThreadPool = Executors.newFixedThreadPool(mThreadCount); //线程池
    }

3.2图片加载类的主要方法

图片加载类的主要方法:public void loadImage(final String path, final ImageView imageView,boolean isFromNetwork),首先通过isFromNetwork判断是加载本地图片或者网络图片,然后选择一种加载图片Runnable任务,将任务加入到线程池任务队列中,并用Handler发送消息,通知控制控制线程,控制线程按照Type的调度类型取出任务提交给线程池执行。Runnable任务得到Bitmap之后会根据ImageView的高宽和Bitmap的高宽做图片的采样压缩,节省内存;接着使用Handler发送消息更新UI。
 
public void loadImage(final String path, final ImageView imageView,boolean isFromNetwork){
       if(null == imageView) {
          return;
       }
        imageView.setTag(path);
        //start 初始化更新UI方法
        if(null == mUIHandler){
            mUIHandler = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    ImageViewBeanHolder holder = (ImageViewBeanHolder) msg.obj;

                    ImageView img = holder.imageView;
                    String tagPath = img.getTag().toString();
                    if(tagPath.equals(holder.path)){  //判断是否对应的路径
                        Log.i(TAG, " path = " + holder.path + "");
                        img.setImageBitmap(holder.bitmap);
                    }
                }
            };
        }
        //end 初始化更新UI方法
       
        Bitmap bitmap = getBitmapFromLruCache(path);  //从缓存中获取Bitmap
       
        if(null != bitmap ){
            refreshImageView(bitmap, imageView, path); //刷新UI
        }else {
           if(isFromNetwork == true) {  //从网络加载图片
//            addTask(new BitmapFromNetworkRunnable(path,imageView));
             
              addTask(new Runnable() {
              
               @Override
               public void run() {
                  Bitmap bm = null;

                  if(Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO){     //Android 2.2 以前版本使用此方法
                     downloadImgByUrlHttpClient(path,imageView);
                  }else {
                     bm = downloadImgByUrl(path,imageView);
                  }
//                bm = downloadImgByUrlHttpClient(path,imageView);
                  if(null == bm) {
                     mSemaphonreThreadPool.release();
                     return;
                  }
                  mSemaphonreThreadPool.release();
                  addBitmap2LruCache(path, bm);
                  refreshImageView(bm, imageView, path);
                 
               }
            });
             
         } else {   //加载手机本地的图片
            addTask(new Runnable() {
               @Override
               public void run() {
                  // 加载图片
                  // 图片压缩
                  // 1获取图片显示的大小
                  ImageSize imageSize = getImageSize(imageView);
                  // 2图片压缩
                  Bitmap bm = decodeSampleBitmap(path, imageSize.width,
                        imageSize.height);
                  addBitmap2LruCache(path, bm);
                  mSemaphonreThreadPool.release();
                  refreshImageView(bm, imageView, path);

               }
            });
         }
          
        }
    }
 
 
 

3.2.1加载手机本地图片

addTask(new Runnable() {
   @Override
   public void run() {
      // 加载图片
      // 图片压缩
      // 1获取图片显示的大小
      ImageSize imageSize = getImageSize(imageView);
      // 2图片压缩
      Bitmap bm = decodeSampleBitmap(path, imageSize.width,
            imageSize.height);
      addBitmap2LruCache(path, bm);
      mSemaphonreThreadPool.release();
      refreshImageView(bm, imageView, path);

   }
});
 
 

3.2.2 加载网络图片

加载网络图片,考虑到Android版本问题,Android 2.2 以前使用HttpClient,Android 2.2以后使用HttpURLConnection。
 
HttpClient 的下载图片方法:
/**
    * 从网络下载图片
    * @param urlStr
    * @param imageview
    * @return
    */
    @SuppressWarnings("deprecation")
   public Bitmap downloadImgByUrlHttpClient(String urlStr, ImageView imageview) {
       Log.i(TAG,"downloadImgByUrlHttpClient *** ");
       HttpClient httpclient = new DefaultHttpClient(); 
        HttpGet httpget = new HttpGet(urlStr); 
     
        
        try {
         HttpResponse response = httpclient.execute(httpget);
         if(HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) {
            HttpEntity entity = response.getEntity();
            InputStream is = null;
            is = new BufferedInputStream(entity.getContent());
           
/*          is.mark(is.available()); 
               Options opts = new Options(); 
               opts.inJustDecodeBounds = true; 
               bitmap = BitmapFactory.decodeStream(is, null, opts); 
                
               //获取imageview想要显示的宽和高 
               ImageSize imageViewSize = getImageSize(imageview); 
               opts.inSampleSize = getBitmapSampleSize(opts, 
                       imageViewSize.width, imageViewSize.height); 
               opts.inJustDecodeBounds = false; 
               is.reset();
               bitmap = BitmapFactory.decodeStream(is, null, opts);*/
           
           
//          is = new BufferedInputStream(conn.getInputStream());

            Log.i(TAG, " befor available() = " + is.available());

            Bitmap bitmap = BitmapFactory.decodeStream(is);

            Log.i(TAG, "after available() = " + is.available());
            

            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            // start 按照图片格式将bitmap转为输出流
            if (urlStr.endsWith("png")) {
               bitmap.compress(CompressFormat.PNG, 50, baos);
            } else if (urlStr.endsWith("webp")) {
               bitmap.compress(CompressFormat.WEBP, 50, baos);
            } else {
               bitmap.compress(CompressFormat.JPEG, 50, baos);
            }
            // end 按照图片格式将bitmap转为输出流

            InputStream isBm = new ByteArrayInputStream(baos.toByteArray());

            Log.i(TAG, " befor available() isBm = " + isBm.available());
            isBm.mark(isBm.available());
           
            // start 采样压缩图片
            Options opts = new Options();
            opts.inJustDecodeBounds = true;
            bitmap = BitmapFactory.decodeStream(isBm, null, opts);

            Log.i(TAG, "after available() isBm = " + isBm.available());

            // 获取imageview想要显示的宽和高
            ImageSize imageViewSize = getImageSize(imageview);
            opts.inSampleSize = getBitmapSampleSize(opts, imageViewSize.width,
                  imageViewSize.height); // 采样
            opts.inJustDecodeBounds = false;

            if (isBm.markSupported()) {
               isBm.reset();
            }

            bitmap = BitmapFactory.decodeStream(isBm, null, opts);
            // end 采样压缩图片
           
            isBm.close();
            baos.close();
               
//            bitmap = BitmapFactory.decodeStream(is);
               is.close();
               return bitmap;
           
         }
        
      } catch (ClientProtocolException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      } catch (IOException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }finally {
         httpclient.getConnectionManager().shutdown(); 
      }
       
       return null;
    }
 
HttpURLConnection 下载图片的方法:
 
/**
    * 从网络下载图片
    * @param urlStr    图片地址
    * @param imageview
    * @return
    */
public Bitmap downloadImgByUrl(String urlStr, ImageView imageview) {
   Log.i(TAG, "downloadImgByUrl *** ");
   FileOutputStream fos = null;
   BufferedInputStream is = null;
   try {
      URL url = new URL(urlStr);
      HttpURLConnection conn = (HttpURLConnection) url.openConnection();
      conn.connect();
      Log.i(TAG, " ResponseCode = " + conn.getResponseCode());
      is = new BufferedInputStream(conn.getInputStream());

      Log.i(TAG, " befor available() = " + is.available());

      Bitmap bitmap = BitmapFactory.decodeStream(is);

      Log.i(TAG, "after available() = " + is.available());
      

      ByteArrayOutputStream baos = new ByteArrayOutputStream();

      // start 按照图片格式将bitmap转为输出流
      if (urlStr.endsWith("png")) {
         bitmap.compress(CompressFormat.PNG, 50, baos);
      } else if (urlStr.endsWith("webp")) {
         bitmap.compress(CompressFormat.WEBP, 50, baos);
      } else {
         bitmap.compress(CompressFormat.JPEG, 50, baos);
      }
      // end 按照图片格式将bitmap转为输出流

      InputStream isBm = new ByteArrayInputStream(baos.toByteArray());

      Log.i(TAG, " befor available() isBm = " + isBm.available());
      isBm.mark(isBm.available());
     
      // start 采样压缩图片
      Options opts = new Options();
      opts.inJustDecodeBounds = true;
      bitmap = BitmapFactory.decodeStream(isBm, null, opts);

      Log.i(TAG, "after available() isBm = " + isBm.available());

      // 获取imageview想要显示的宽和高
      ImageSize imageViewSize = getImageSize(imageview);
      opts.inSampleSize = getBitmapSampleSize(opts, imageViewSize.width,
            imageViewSize.height); // 采样
      opts.inJustDecodeBounds = false;

      if (isBm.markSupported()) {
         isBm.reset();
      }

      bitmap = BitmapFactory.decodeStream(isBm, null, opts);
      // end 采样压缩图片
     
      isBm.close();
      baos.close();
      is.close();
      conn.disconnect();
      return bitmap;

   } catch (Exception e) {
      e.printStackTrace();
   } finally {
      try {
         if (is != null)
            is.close();
      } catch (IOException e) {
      }

      try {
         if (fos != null)
            fos.close();
      } catch (IOException e) {
      }
   }

   return null;

}
 
 
 

4仿微信图片选择MainActivity1

主要过程:使用ContentResolver搜索手机内所有的图片,得到所有包含图片的文件夹;在搜索的同时得到文件夹的第一张图片的路径,和包含图片最多的文件夹;Handler发送消息更新UI显示包含图片最多的文件夹内的所有图片;增加点击事件可以选择其他的文件夹。

4.1 搜索手机内的图片

/**
 * 利用contentPrivider扫描手机中的图片
 */
private void initDatas(){
    if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
        Toast.makeText(this,"没有存储卡",Toast.LENGTH_LONG).show();
        return;
    }
    mProgressDialog = ProgressDialog.show(this,null,"正在查找..");
    new Thread(){
        @Override
        public void run() {
            super.run();
            Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            ContentResolver cr = MainActivity1.this.getContentResolver();
            Cursor cursor = cr.query(mImageUri, null, MediaStore.Images.Media.MIME_TYPE + " = ? or " +
                    MediaStore.Images.Media.MIME_TYPE + " = ?",
                    new String[]{"image/jpeg", "image/png"},
                    MediaStore.Images.Media.DATE_MODIFIED);
            Set<String> mDirPath = new HashSet<String>(); //已经扫描过的包含图片文件的文件夹路径
            String firstImage = null;
            while (cursor.moveToNext()) {
                String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
                //第一张图片的路径
                if(null == firstImage){
                    firstImage = path;
                }
                //start 获取该图片的父路径
                File parentFile = new File(path).getParentFile();
                if(parentFile==null){
                    continue;
                }
                //end 获取该图片的父路径

                String dirPath = parentFile.getAbsolutePath();
                FolderBean folderBean = null;
                if(mDirPath.contains(dirPath)){
                    continue;
                }else {
                    mDirPath.add(dirPath);
                    folderBean = new FolderBean();
                    folderBean.setDir(dirPath);
                    folderBean.setFirstImgPath(path);
                }

                if(parentFile.list() == null) {
                    continue;
                }

                //start 获取该文件夹下的图片文件数量
                int picsSize = parentFile.list(new FilenameFilter() {
                    @Override
                    public boolean accept(File dir, String filename) {
                        if(filename.endsWith(".jpg")
                                ||filename.endsWith(".jpeg")
                                ||filename.endsWith(".png"))
                        {
                            return true;
                        }
                        return false;
                    }
                }).length;
                //end 获取该文件夹下的图片文件数量

                folderBean.setCount(picsSize);
                mFolderBeans.add(folderBean);

                //start 设置图片文件最多的文件夹为当前文件夹
                if(picsSize > mMaxCount){
                    mMaxCount = picsSize;
                    mCurrentDir = parentFile;
                }
            }
            //end 设置图片文件最多的文件夹为当前文件夹
            cursor.close();
            mDirPath = null;
            mHandler.sendEmptyMessage(0x110);
        }
    }.start();
}
 

4.2 更新UI

private void data2View() {
    if(mCurrentDir == null){
        Toast.makeText(this,"没有扫描到图片",Toast.LENGTH_LONG).show();
        return;
    }
    //start 当前文件夹的图片文件
    mImgs = Arrays.asList(mCurrentDir.list(new FilenameFilter() {
        @Override
        public boolean accept(File dir, String filename) {
            if(filename.endsWith(".jpg")
                    ||filename.endsWith(".jpeg")
                    ||filename.endsWith(".png"))
            {
                return true;
            }
            return false;
        }
    }));
    //end 当前文件夹的图片文件

    if(null==mAdapter){
        mAdapter = new ImageAdapterAdapter(this,mImgs,mCurrentDir.getAbsolutePath());
    }
    mGridView.setAdapter(mAdapter);
    mDirCount.setText(mMaxCount + "");
    mDirName.setText(mCurrentDir.getName());

}
 

4.3 弹出选择文件夹的窗口的初始化

/**
 * 初始化popupwindow
 */
private void initPop() {
    Log.i(TAG,"mFolderBeans = "+mFolderBeans);
    mPop = new ListImageDirPopupWindow(this,mFolderBeans);
    mPop.setAnimationStyle(R.style.dir_popupwindow_anim);
    mPop.setOnDismissListener(new PopupWindow.OnDismissListener() {
        @Override
        public void onDismiss() {
            lightOn();
        }
    });
    //start设置弹出窗口图片路径选择回调监听
    mPop.setOnDirSelectedListener(new ListImageDirPopupWindow.OnDirSelectedListener() {
        @Override
        public void onDirSelected(FolderBean folderBean) {
            if(null != folderBean) {
                mCurrentDir = new File(folderBean.getDir()); //选中文件路径
                mImgs = Arrays.asList(mCurrentDir.list(new FilenameFilter() { //文件路径中图片路径
                    @Override
                    public boolean accept(File dir, String filename) {
                        if(filename.endsWith(".jpg")
                                ||filename.endsWith(".jpeg")
                                ||filename.endsWith(".png"))
                        {
                            return true;
                        }
                        return false;
                    }
                }));
                //start 刷新图片gridView
                if(null==mAdapter){
                    mAdapter = new ImageAdapterAdapter(MainActivity1.this,mImgs,mCurrentDir.getAbsolutePath());
                    mGridView.setAdapter(mAdapter);
                }else {
                    mAdapter.setDirPath(mCurrentDir.getAbsolutePath());
                    mAdapter.setSourceData(mImgs);
                    mAdapter.notifyDataSetChanged();
                }
                //end 刷新图片gridView

                mDirCount.setText(mImgs.size() + "");    //文件中图片的数量
                mDirName.setText(mCurrentDir.getName()); //文件名
            }
            mPop.dismiss();
        }
    });
    //end 设置弹出窗口图片路径选择回调监听
}
 

5加载网络图片MainActivity2

首先活动网络图片的链接再更新UI显示图片

5.1 获取网络加载的Url

所有的网络图片的Url都在Images类中,所有的链接约有3000多张,有些链接可能已经失效,当然你也可以自己抓取百度的图片里面的图片,我是用Chrome浏览器的一个插件“小乐图客”来抓取的。
/**
 * 获取图片链接
 * @param num
 * @return
 */
private List<String> getUrlList(int num) {
   List<String> urlList = null;
   if(num < 0) {  //所有链接
      urlList = Arrays.asList(imageThumbUrls);
   }
   if(num == 0) { //无链接
      urlList = new LinkedList<String>();
     
   }
   if(num >0) {  //根据数量
      if(num < imageThumbUrls.length) {
         urlList = new LinkedList<String>();
         for(int i=0 ;i<num; i++) {
            urlList.add(imageThumbUrls[i]);
         }
      } else {
         urlList = Arrays.asList(imageThumbUrls);
      }
        
   }
  
   return urlList;
}
 
 

5.2 更新UI

private void bindGvData2(){

   mAdapter = new ImageAdapter2(this, mGv,getUrlList(-1));
   mGv.setAdapter(mAdapter);

}
 
本文结束,谢谢各位阅读,如有错误请指出,谢谢!
参考资料:

http://blog.csdn.net/lmj623565791/article/details/41874561
http://blog.csdn.net/guolin_blog/article/details/28863651
http://blog.csdn.net/xiaanming/article/details/9825113
http://my.oschina.net/jeffzhao/blog/80900
源码下载链接:
http://download.csdn.net/detail/luoshishou/9508282

 
 
时间: 2024-10-29 19:10:28

LrcCache和DiskLruCache相结合打造图片加载框架的相关文章

Android 框架练成 教你打造高效的图片加载框架

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/41874561,本文出自:[张鸿洋的博客] 1.概述 优秀的图片加载框架不要太多,什么UIL , Volley ,Picasso,Imageloader等等.但是作为一名合格的程序猿,必须懂其中的实现原理,于是乎,今天我就带大家一起来设计一个加载网络.本地的图片框架.有人可能会说,自己写会不会很渣,运行效率,内存溢出神马的.放心,我们拿demo说话,拼得就是速度,奏事这么任性.

Android中常见的图片加载框架

图片加载涉及到图片的缓存.图片的处理.图片的显示等.而随着市面上手机设备的硬件水平飞速发展,对图片的显示要求越来越高,稍微处理不好就会造成内存溢出等问题.很多软件厂家的通用做法就是借用第三方的框架进行图片加载. 开源框架的源码还是挺复杂的,但使用较为简单.大部分框架其实都差不多,配置稍微麻烦点,但是使用时一般只需要一行,显示方法一般会提供多个重载方法,支持不同需要.这样会减少很不必要的麻烦.同时,第三方框架的使用较为方便,这大大的减少了工作量.提高了开发效率.本文主要介绍四种常用的图片加载框架,

图片加载框架之Glide和Picasso

Glide介绍 Glide是一个加载图片的库,作者是bumptech,它是在泰国举行的google 开发者论坛上google为我们介绍的,这个库被广泛的运用在google的开源项目中. Glide是一个非常成熟的图片加载库,他可以从多个源加载图片,如:网路,本地,Uri等,更重要的是他内部封装了非常好的缓存机制并且在处理图片的时候能保持一个低的内存消耗. Picasso介绍(毕加索) picasso是Square公司开源的一个Android图形缓存库,地址http://square.github

一起写一个Android图片加载框架

本文会从内部原理到具体实现来详细介绍如何开发一个简洁而实用的Android图片加载缓存框架,并在内存占用与加载图片所需时间这两个方面与主流图片加载框架之一Universal Image Loader做出比较,来帮助我们量化这个框架的性能.通过开发这个框架,我们可以进一步深入了解Android中的Bitmap操作.LruCache.LruDiskCache,让我们以后与Bitmap打交道能够更加得心应手.若对Bitmap的大小计算及inSampleSize计算还不太熟悉,请参考这里:高效加载Bit

详谈高大上的图片加载框架Glide -源码篇

在上篇文章中,我们介绍了Glide图片加载框架的使用,通过之前的学习,我们可能已经能熟练的将Glide图片加载框架运用到我们的项目中,但是如果有人问你它是如何加载,工作原理是怎样的?为什么自定义GlideModule只需要在Manifest文件中加入meta-data即可?等等很多加载流程以及使用的注意事项.当然要想搞明白这些问题,就需要我们对Glide源码有个大致的认识,去剖析源码深处的奥秘. 接下来就让我们一起去进入Glide的源码世界,本篇文章分析的是Glide 3.7.0版本.特别提醒,

常用图片加载框架

我们在项目中使用的是Picasso.其实现在的主流图片加载框架除了Picasso还有ImageLoader,Glide,以及Fresco.ImageLoader是比较老的框架了,稳定, 加载速度适中, 缺点在于不支持GIF图片加载, 使用稍微繁琐, 并且缓存机制没有和http的缓存很好的结合, 完全是自己的一套缓存机制.Glide是谷歌的一位工程师开发的,它可以说是Picasso的升级版, 有Picasso的优点, 并且支持GIF图片加载显示, 图片缓存也会自动缩放, 默认使用RGB_565格式

iOS图片加载框架学习之FlyImage

在iOS开发中,其图片加载新框架FlyImage 整合了SDWebImage,FastImageCache,AFNetworking的优点,是一个新的性能高效.接口简单的图片加载框架,下面小编就和大家一起来扒一扒这个框架. 特点 高效 可将多张小图解码后存储到同一张大图上,在同屏渲染多图时,效率极高: 支持 mmap 内存映射,高效的I/O操作,减少一次文件拷贝操作,同时减少内存占用: 支持 Byte Alignment 字节对其,渲染过程中,避免执行 CA::Render::copy_imag

关于图片加载框架

接上篇,这篇开始对现在比较的流行的第三方图片加载框架做一个对比总结. 这篇文章介绍内容如下: 1.目前流行的图片加载框架有什么? 2.各自的使用方法 3.各自的优缺点 4.优化问题 一.目前流行的图片加载框架有什么? ImageLoader   Glide  Picasso  Fresso(2015年) 注:由于现在ImageLoader使用较少,本篇博文将不再对它进行阐述.主要以其它三个框架为主,有兴趣的同学可以自行学习. 二.各自的使用方法 Picasso:  Picasso .with(t

Universal-Image-Loader(UIL)图片加载框架使用简单介绍

这个也是最近项目中使用到的第三方图片加载框架,在这里也自己总结一下,简单的介绍一些使用的方式. UIL图片加载框架特点 简介: 项目地址:https://github.com/nostra13/Android-Universal-Image-Loader 异步加载图片或者加载大量图片经常会遇到图片错乱或者OOM等相关问题.UIL图片缓存,目前使用最广泛的图片缓存,支持主流图片缓存的绝大多数特性. 我们看下该图片加载的三级缓存原理 特点: 1.多线程下载图片,图片可以来源于网络,文件系统,项目文件