Android LruCache和DiskLruCache相结合打造图片加载框架(仿微信图片选择,照片墙)

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


转载请标明出处:http://blog.csdn.net/luoshishou/article/details/51299169

源码下载链接:
http://download.csdn.net/detail/luoshishou/9508282


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(Kkey,Vvalue) {
    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 finalVput(Kkey,Vvalue)和private voidtrimToSize(intmaxSize)方法。

 

/**
 * 将对象加入缓存,如果缓存已经满,则删除最近最少使用的对象,并返回被删除的对象列表
 * @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
 
 
 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值