1. 程式人生 > >Android 使用ContentProvider掃描手機中的圖片,仿微信顯示本地圖片效果

Android 使用ContentProvider掃描手機中的圖片,仿微信顯示本地圖片效果

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

轉載請註明本文出自xiaanming的部落格(http://blog.csdn.net/xiaanming/article/details/18730223),請尊重他人的辛勤勞動成果,謝謝!

寫這篇文章之前,先簡單說幾句,首先是先恭喜下自己獲得了2013年的部落格之星稱號,很意外也很開心,自己是從2013年開始寫部落格,那時候也不知道怎麼寫,我從小就不喜歡寫日記,作文什麼的,所以剛開始都是貼程式碼,也沒有人看,後面慢慢的,寫的文章被推薦部落格首頁和CSDN首頁(這裡也要小小的感謝下小編MM),訪問量逐漸的多了起來,有更多的人看我的文章,這也使自己有了繼續寫文章的動力,也希望我寫的東西對大家有點幫助吧,在2014年我會繼續在CSDN上面寫部落格,然後是感謝部落格之星給我投票支援我的朋友們,謝謝你們支援我的每一票,最後就是2014春節馬上就到了,提前祝福大家新年快樂,工作順利,事事順心!

回到主題,之前群裡面有朋友問我,有沒有關於本地圖片選擇的Demo,類似微信的效果,他說網上沒有這方面的Demo,問我能不能寫一篇關於這個效果的Demo,於是我研究了下微信的本地圖片選擇的Demo,自己仿照的寫了下分享給大家,希望對以後有這樣子需求的朋友有一點幫助吧,主要使用的是ContentProvider掃描手機中的圖片,並用GridView將圖片顯示出來,關於GridView和ListView顯示圖片的問題,一直是一個很頭疼的問題,因為我們手機的記憶體有限,手機給每個應用程式分配的記憶體也有限,所以圖片多的情況下很容易伴隨著OOM的發生,不過現在也有很多的開源的圖片顯示框架,對顯示很多圖片進行了優化,大家有興趣的可以去了解了解,今天我的這篇文章使用的是LruCache這個類(之前寫了一篇使用LruCache載入網路圖片的

Android 非同步載入圖片,使用LruCache和SD卡或手機快取,效果非常的流暢)以及對圖片進行相對應的裁剪,這樣也可以儘量的避免OOM的發生,我們先看下微信的效果吧


接下來我們就來實現這些效果吧,首先我們新建一個專案,取名ImageScan

首先我們先看第一個介面吧,使用將手機中的圖片掃描出來,然後根據圖片的所在的資料夾將其分類出來,並顯示所在資料夾裡面的一張圖片和資料夾中圖片個數,我們根據介面元素(資料夾名, 資料夾圖片個數,資料夾中的一張圖片)使用一個實體物件ImageBean來封裝這三個屬性

package com.example.imagescan;/** * GridView的每個item的資料物件 *  * @author
len * */
public class ImageBean/**  * 資料夾的第一張圖片路徑  */ private String topImagePath; /**  * 資料夾名  */ private String folderName;  /**  * 資料夾中的圖片數  */ private int imageCounts;  public String getTopImagePath() {  return topImagePath; } public void setTopImagePath(String topImagePath) {  this.topImagePath = topImagePath; } public String getFolderName() {  return folderName; } public void setFolderName(String folderName) {  this.folderName = folderName; } public int getImageCounts() {  return imageCounts; } public void setImageCounts(int imageCounts) {  this.imageCounts = imageCounts; } }
接下來就是主介面的佈局啦,上面的導航欄我沒有加進去,只有下面的GridView,所以說主介面佈局中只有一個GridView

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent" >    <GridView        android:id="@+id/main_grid"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:listSelector="@android:color/transparent"        android:cacheColorHint="@android:color/transparent"        android:stretchMode="columnWidth"        android:horizontalSpacing="20dip"        android:gravity="center"        android:verticalSpacing="20dip"        android:columnWidth="90dip"        android:numColumns="2" >    </GridView></RelativeLayout>

接下來就是GridView的Item的佈局,看上面的圖也行你會認為他的效果是2張圖片新增的效果,其實不是,後面的疊加效果只是一張背景圖片而已,程式碼先貼上來

<?xml version="1.0" encoding="UTF-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="wrap_content" >    <FrameLayout        android:id="@+id/framelayout"        android:layout_width="fill_parent"        android:layout_height="wrap_content" >        <com.example.imagescan.MyImageView            android:id="@+id/group_image"            android:background="@drawable/albums_bg"            android:src="@drawable/friends_sends_pictures_no"            android:paddingLeft="20dip"            android:paddingRight="20dip"            android:paddingTop="18dip"            android:paddingBottom="30dip"            android:scaleType="fitXY"            android:layout_width="fill_parent"            android:layout_height="150dip" />        <TextView            android:id="@+id/group_count"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:background="@drawable/albums_icon_bg"            android:gravity="center"            android:layout_marginBottom="10dip"            android:text="5"            android:layout_gravity="bottom|center_horizontal" />    </FrameLayout>    <TextView        android:id="@+id/group_title"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:gravity="center"        android:layout_below="@id/framelayout"        android:layout_centerHorizontal="true"        android:ellipsize="end"        android:singleLine="true"        android:text="Camera"        android:textSize="16sp" /></RelativeLayout>
看到上面的佈局程式碼,也行你已經發現了,上面使用的是自定義的MyImageView,我先不說這個自定義MyImageView的作用,待會再給大家說,我們繼續看程式碼

第一個介面的主要程式碼

package com.example.imagescan;import java.io.File;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import android.app.Activity;import android.app.ProgressDialog;import android.content.ContentResolver;import android.content.Intent;import android.database.Cursor;import android.net.Uri;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.provider.MediaStore;import android.view.View;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.GridView;/** * @blog http://blog.csdn.net/xiaanming *  * @author xiaanming *  * */public class MainActivity extends Activity private HashMap<String, List<String>> mGruopMap = new HashMap<String, List<String>>(); private List<ImageBean> list = new ArrayList<ImageBean>(); private final static int SCAN_OK = 1private ProgressDialog mProgressDialog; private GroupAdapter adapter; private GridView mGroupGridView;  private Handler mHandler = new Handler(){  @Override  public void handleMessage(Message msg) {   super.handleMessage(msg);   switch (msg.what) {   case SCAN_OK:    //關閉進度條    mProgressDialog.dismiss();        adapter = new GroupAdapter(MainActivity.this, list = subGroupOfImage(mGruopMap), mGroupGridView);    mGroupGridView.setAdapter(adapter);    break;   }  }   }; @Override protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);    mGroupGridView = (GridView) findViewById(R.id.main_grid);    getImages();    mGroupGridView.setOnItemClickListener(new OnItemClickListener() {   @Override   public void onItemClick(AdapterView<?> parent, View view,     int position, long id) {    List<String> childList = mGruopMap.get(list.get(position).getFolderName());        Intent mIntent = new Intent(MainActivity.this, ShowImageActivity.class);    mIntent.putStringArrayListExtra("data", (ArrayList<String>)childList);    startActivity(mIntent);       }  });   } /**  * 利用ContentProvider掃描手機中的圖片,此方法在執行在子執行緒中  */ private void getImages() {  //顯示進度條  mProgressDialog = ProgressDialog.show(this, null, "正在載入...");    new Thread(new Runnable() {      @Override   public void run() {    Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;    ContentResolver mContentResolver = MainActivity.this.getContentResolver();    //只查詢jpeg和png的圖片    Cursor mCursor = mContentResolver.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);        if(mCursor == null){     return;    }        while (mCursor.moveToNext()) {     //獲取圖片的路徑     String path = mCursor.getString(mCursor       .getColumnIndex(MediaStore.Images.Media.DATA));          //獲取該圖片的父路徑名     String parentName = new File(path).getParentFile().getName();          //根據父路徑名將圖片放入到mGruopMap中     if (!mGruopMap.containsKey(parentName)) {      List<String> chileList = new ArrayList<String>();      chileList.add(path);      mGruopMap.put(parentName, chileList);     } else {      mGruopMap.get(parentName).add(path);     }    }        //通知Handler掃描圖片完成    mHandler.sendEmptyMessage(SCAN_OK);    mCursor.close();   }  }).start();   }   /**  * 組裝分組介面GridView的資料來源,因為我們掃描手機的時候將圖片資訊放在HashMap中  * 所以需要遍歷HashMap將資料組裝成List  *   * @param mGruopMap  * @return  */ private List<ImageBean> subGroupOfImage(HashMap<String, List<String>> mGruopMap){  if(mGruopMap.size() == 0){   return null;  }  List<ImageBean> list = new ArrayList<ImageBean>();    Iterator<Map.Entry<String, List<String>>> it = mGruopMap.entrySet().iterator();  while (it.hasNext()) {   Map.Entry<String, List<String>> entry = it.next();   ImageBean mImageBean = new ImageBean();   String key = entry.getKey();   List<String> value = entry.getValue();      mImageBean.setFolderName(key);   mImageBean.setImageCounts(value.size());   mImageBean.setTopImagePath(value.get(0));//獲取該組的第一張圖片      list.add(mImageBean);  }    return list;   }}
  • 首先看getImages()這個方法,該方法是使用ContentProvider將手機中的圖片掃描出來,我這裡只掃描了手機的外部儲存中的圖片,由於手機中可能存在很多的圖片,掃描圖片又比較耗時,所以我們在這裡開啟了子執行緒去獲取圖片,掃描的圖片都存放在Cursor中,我們先要將圖片按照資料夾進行分類,我們使用了HashMap來進行分類並將結果儲存到mGruopMap(Key是資料夾名,Value是資料夾中的圖片路徑的List)中,分類完了關閉Cursor並利用Handler來通知主執行緒
  • 然後是subGroupOfImage()方法,改方法是將mGruopMap的資料組裝到List中,在List中存放GridView中的每個item的資料物件ImageBean, 遍歷HashMap物件,具體的邏輯看程式碼,之後就是給GridView設定Adapter。
  • 設定item點選事件,點選資料夾跳轉到展示資料夾圖片的Activity, 我們需要傳遞每個資料夾中的圖片的路徑的集合

看GroupAdapter的程式碼之前,我們先看一個比較重要的類,本地圖片載入器NativeImageLoader

package com.example.imagescan;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Point;import android.os.Handler;import android.os.Message;import android.support.v4.util.LruCache;/** * 本地圖片載入器,採用的是非同步解析本地圖片,單例模式利用getInstance()獲取NativeImageLoader例項 * 呼叫loadNativeImage()方法載入本地圖片,此類可作為一個載入本地圖片的工具類 *  * @blog http://blog.csdn.net/xiaanming *  * @author xiaanming * */public class NativeImageLoader private LruCache<String, Bitmap> mMemoryCache; private static NativeImageLoader mInstance = new NativeImageLoader(); private ExecutorService mImageThreadPool = Executors.newFixedThreadPool(1);   private NativeImageLoader(){  //獲取應用程式的最大記憶體  final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);  //用最大記憶體的1/4來儲存圖片  final int cacheSize = maxMemory / 4;  mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {      //獲取每張圖片的大小   @Override   protected int sizeOf(String key, Bitmap bitmap) {    return bitmap.getRowBytes() * bitmap.getHeight() / 1024;   }  }; }  /**  * 通過此方法來獲取NativeImageLoader的例項  * @return  */ public static NativeImageLoader getInstance(){  return mInstance; }   /**  * 載入本地圖片,對圖片不進行裁剪  * @param path  * @param mCallBack  * @return  */ public Bitmap loadNativeImage(final String path, final NativeImageCallBack mCallBack){  return this.loadNativeImage(path, null, mCallBack); }  /**  * 此方法來載入本地圖片,這裡的mPoint是用來封裝ImageView的寬和高,我們會根據ImageView控制元件的大小來裁剪Bitmap  * 如果你不想裁剪圖片,呼叫loadNativeImage(final String path, final NativeImageCallBack mCallBack)來載入  * @param path  * @param mPoint  * @param mCallBack  * @return  */ public Bitmap loadNativeImage(final String path, final Point mPoint, final NativeImageCallBack mCallBack){  //先獲取記憶體中的Bitmap  Bitmap bitmap = getBitmapFromMemCache(path);    final Handler mHander = new Handler(){   @Override   public void handleMessage(Message msg) {    super.handleMessage(msg);    mCallBack.onImageLoader((Bitmap)msg.obj, path);   }     };    //若該Bitmap不在記憶體快取中,則啟用執行緒去載入本地的圖片,並將Bitmap加入到mMemoryCache中  if(bitmap == null){   mImageThreadPool.execute(new Runnable() {        @Override    public void run() {     //先獲取圖片的縮圖     Bitmap mBitmap = decodeThumbBitmapForFile(path, mPoint == null ? 0: mPoint.x, mPoint == null ? 0: mPoint.y);     Message msg = mHander.obtainMessage();     msg.obj = mBitmap;     mHander.sendMessage(msg);          //將圖片加入到記憶體快取     addBitmapToMemoryCache(path, mBitmap);    }   });  }  return bitmap;   }   /**  * 往記憶體快取中新增Bitmap  *   * @param key  * @param bitmap  */ private void addBitmapToMemoryCache(String key, Bitmap bitmap) {  if (getBitmapFromMemCache(key) == null && bitmap != null) {   mMemoryCache.put(key, bitmap);  } } /**  * 根據key來獲取記憶體中的圖片  * @param key  * @return  */ private Bitmap getBitmapFromMemCache(String key) {  return mMemoryCache.get(key); }   /**  * 根據View(主要是ImageView)的寬和高來獲取圖片的縮圖  * @param path  * @param viewWidth  * @param viewHeight  * @return  */ private Bitmap decodeThumbBitmapForFile(String path, int viewWidth, int viewHeight){  BitmapFactory.Options options = new BitmapFactory.Options();  //設定為true,表示解析Bitmap物件,該物件不佔記憶體  options.inJustDecodeBounds = true;  BitmapFactory.decodeFile(path, options);  //設定縮放比例  options.inSampleSize = computeScale(options, viewWidth, viewHeight);    //設定為false,解析Bitmap物件加入到記憶體中  options.inJustDecodeBounds = false;    return BitmapFactory.decodeFile(path, options); }   /**  * 根據View(主要是ImageView)的寬和高來計算Bitmap縮放比例。預設不縮放  * @param options  * @param width  * @param height  */ private int computeScale(BitmapFactory.Options options, int viewWidth, int viewHeight){  int inSampleSize = 1;  if(viewWidth == 0 || viewWidth == 0){   return inSampleSize;  }  int bitmapWidth = options.outWidth;  int bitmapHeight = options.outHeight;    //假如Bitmap的寬度或高度大於我們設定圖片的View的寬高,則計算縮放比例  if(bitmapWidth > viewWidth || bitmapHeight > viewWidth){   int widthScale = Math.round((float) bitmapWidth / (float) viewWidth);   int heightScale = Math.round((float) bitmapHeight / (float) viewWidth);      //為了保證圖片不縮放變形,我們取寬高比例最小的那個   inSampleSize = widthScale < heightScale ? widthScale : heightScale;  }  return inSampleSize; }   /**  * 載入本地圖片的回撥介面  *   * @author xiaanming  *  */ public interface NativeImageCallBack{  /**   * 當子執行緒載入完了本地的圖片,將Bitmap和圖片路徑回撥在此方法中   * @param bitmap   * @param path   */  public void onImageLoader(Bitmap bitmap, String path); }}

該類是一個單例類,提供了本地圖片載入,記憶體快取,裁剪等邏輯,該類在載入本地圖片的時候採用的是非同步載入的方式,對於大圖片的載入也是比較耗時的,所以採用子執行緒的方式去載入,對於圖片的快取機制使用的是LruCache,使用手機分配給應用程式記憶體的1/4用來快取圖片,除了使用LruCache快取圖片之外,還對圖片進行了裁剪,舉個很簡單的例子,假如我們的控制元件大小是100 * 100, 而我們的圖片是400*400,我們載入這麼大的圖片需要很多的記憶體,所以我們採用了圖片裁剪,根據控制元件的大小來確定圖片的裁剪比例,從而減小記憶體的消耗,提高GridView滑動的流暢度,介紹裡面幾個比較重要的方法
  1. computeScale()計算圖片需要裁剪的比例,根據控制元件的大小和圖片的大小確定比例,如果圖片比控制元件大,我們就進行裁剪,否則不需要。
  2. decodeThumbBitmapForFile()方法是根據計算好了圖片裁剪的比例之後從檔案中載入圖片,我們先設定options.inJustDecodeBounds = true表示解析不佔用記憶體,但是我們能獲取圖片的具體大小,利用computeScale()計算好比例,在將options.inJustDecodeBounds=false,再次解析Bitmap,這樣子就對圖片進行了裁剪。
  3. loadNativeImage(final String path, final Point mPoint, final NativeImageCallBack mCallBack)我們在客戶端只需要呼叫該方法就能獲取到Bitmap物件,裡面的具體邏輯是先判斷記憶體快取LruCache中是否存在該Bitmap,不存在就開啟子執行緒去讀取,為了方便管理載入本地圖片執行緒,這裡使用了執行緒池,池中只能容納一個執行緒,讀取完了本地圖片先將Bitmap加入到LruCache中,儲存的Key為圖片路徑,然後再使用Handler通知主執行緒圖片載入好了,之後將Bitmap和路徑回撥到方法onImageLoader(Bitmap bitmap, String path)中,該方法的mPoint是用來封裝控制元件的寬和高的物件
  4. 如果不對圖片進行裁剪直接這個方法的過載方法loadNativeImage(final String path, final NativeImageCallBack mCallBack) 就行了,邏輯是一樣的,只是這個方法不對圖片進行裁剪

接下來就是GridView的Adapter類的程式碼

package com.example.imagescan;import java.util.List;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Point;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.GridView;import android.widget.ImageView;import android.widget.TextView;import com.example.imagescan.MyImageView.OnMeasureListener;import com.example.imagescan.NativeImageLoader.NativeImageCallBack;public class GroupAdapter extends BaseAdapterprivate List<ImageBean> list; private Point mPoint = new Point(0, 0);//用來封裝ImageView的寬和高的物件 private GridView mGridView; protected LayoutInflater mInflater;  @Override public int getCount() {  return list.size(); } @Override public Object getItem(int position) {  return list.get(position); } @Override public long getItemId(int position) {  return position; }  public GroupAdapter(Context context, List<ImageBean> list, GridView mGridView){  this.list = list;  this.mGridView = mGridView;  mInflater = LayoutInflater.from(context); }  @Override public View getView(int position, View convertView, ViewGroup parent) {  final ViewHolder viewHolder;  ImageBean mImageBean = list.get(position);  String path = mImageBean.getTopImagePath();  if(convertView == null){   viewHolder = new ViewHolder();   convertView = mInflater.inflate(R.layout.grid_group_item, null);   viewHolder.mImageView = (MyImageView) convertView.findViewById(R.id.group_image);   viewHolder.mTextViewTitle = (TextView) convertView.findViewById(R.id.group_title);   viewHolder.mTextViewCounts = (TextView) convertView.findViewById(R.id.group_count);      //用來監聽ImageView的寬和高   viewHolder.mImageView.setOnMeasureListener(new OnMeasureListener() {        @Override    public void onMeasureSize(int width, int height) {     mPoint.set(width, height);    }   });      convertView.setTag(viewHolder);  }else{   viewHolder = (ViewHolder) convertView.getTag();   viewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no);  }    viewHolder.mTextViewTitle.setText(mImageBean.getFolderName());  viewHolder.mTextViewCounts.setText(Integer.toString(mImageBean.getImageCounts()));  //給ImageView設定路徑Tag,這是非同步載入圖片的小技巧  viewHolder.mImageView.setTag(path);      //利用NativeImageLoader類載入本地圖片  Bitmap bitmap = NativeImageLoader.getInstance().loadNativeImage(path, mPoint, new NativeImageCallBack() {      @Override   public void onImageLoader(Bitmap bitmap, String path) {    ImageView mImageView = (ImageView) mGridView.findViewWithTag(path);    if(bitmap != null && mImageView != null){     mImageView.setImageBitmap(bitmap);    }   }  });    if(bitmap != null){   viewHolder.mImageView.setImageBitmap(bitmap);  }else{   viewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no);  }      return convertView; }    public static class ViewHolder{  public MyImageView mImageView;  public TextView mTextViewTitle;  public TextView mTextViewCounts; } }

首先我們將每個item的圖片路徑設定Tag到該ImageView上面,然後利用NativeImageLoader來載入本地圖片,但是我們顯示的圖片的寬和高可能遠大於GirdView item中ImageView的大小,於是為了節省記憶體,我們需要對圖片進行裁剪,需要對圖片裁剪我們利用loadNativeImage(final String path, final Point mPoint, final NativeImageCallBack mCallBack)方法,我們就必須要獲取ImageView的寬和高了

但是我們想在getView()中獲取ImageView的寬和高存在問題,在getView()裡面剛開始顯示item的時候利用ImageView.getWidth() 獲取的都是0,為什麼剛開始獲取不到寬和高呢,因為我們使用LayoutInflater來將XML佈局檔案Inflater()成View的時候,View並沒有顯示在介面上面,表明並沒有對View進行onMeasure(), onLayout(), onDraw()等操作,必須等到retrue convertView的時候,表示該item對應的View已經繪製在ListView的位置上了, 此時才對item對應的View進行onMeasure(), onLayout(), onDraw()等操作,這時候才能獲取到Item的寬和高,於是我想到了自定義ImageView,在onMeasure()中利用回撥的模式主動通知我ImageView測量的寬和高,但是這有一個小小的問題,就是顯示GridView的第一個item的時候,獲取的寬和高還是0,第二個就能正常獲取了,第一個寬和高為0,表示我們不對第一張圖片進行裁剪而已,在效率上也沒啥問題,不知道大家有沒有好的方法,可以在getView()中獲取Item中某個控制元件的寬和高。


自定義MyImageView的程式碼,我們只需要設定OnMeasureListener監聽,當MyImageView測量完畢之後,就會將測量的寬和高回撥到onMeasureSize()中,然後我們可以根據MyImageView的大小來裁剪圖片

package com.example.imagescan;import android.content.Context;import android.util.AttributeSet;import android.widget.ImageView;public class MyImageView extends ImageView private OnMeasureListener onMeasureListener;  public void setOnMeasureListener(OnMeasureListener onMeasureListener) {  this.onMeasureListener = onMeasureListener; } public MyImageView(Context context, AttributeSet attrs) {  super(context, attrs); } public MyImageView(Context context, AttributeSet attrs, int defStyle) {  super(context, attrs, defStyle); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  super.onMeasure(widthMeasureSpec, heightMeasureSpec);    //將圖片測量的大小回調到onMeasureSize()方法中  if(onMeasureListener != null){   onMeasureListener.onMeasureSize(getMeasuredWidth(), getMeasuredHeight());  } } public interface OnMeasureListener{  public void onMeasureSize(int width, int height); } }
上面這些程式碼就完成了第一個介面的功能了,接下來就是點選GridView的item跳轉另一個介面來顯示該資料夾下面的所有圖片,功能跟第一個介面差不多,也是使用GridView來顯示圖片,第二個介面的佈局程式碼我就不貼了,直接貼上介面的程式碼

package com.example.imagescan;import java.util.List;import android.app.Activity;import android.os.Bundle;import android.widget.GridView;import android.widget.Toast;public class ShowImageActivity extends Activity private GridView mGridView; private List<String> list; private ChildAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.show_image_activity);    mGridView = (GridView) findViewById(R.id.child_grid);  list = getIntent().getStringArrayListExtra("data");    adapter = new ChildAdapter(this, list, mGridView);  mGridView.setAdapter(adapter);   } @Override public void onBackPressed() {  Toast.makeText(this, "選中 " + adapter.getSelectItems().size() + " item", Toast.LENGTH_LONG).show();  super.onBackPressed(); }  }
GridView的item上面一個我們自定義的MyImageView用來顯示圖片,另外還有一個CheckBox來記錄我們選中情況,Adapter的程式碼如下
package com.example.imagescan;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Point;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.CheckBox;import android.widget.CompoundButton;import android.widget.ImageView;import android.widget.CompoundButton.OnCheckedChangeListener;import android.widget.GridView;import com.example.imagescan.MyImageView.OnMeasureListener;import com.example.imagescan.NativeImageLoader.NativeImageCallBack;import com.nineoldandroids.animation.AnimatorSet;import com.nineoldandroids.animation.ObjectAnimator;public class ChildAdapter extends BaseAdapter private Point mPoint = new Point(0, 0);//用來封裝ImageView的寬和高的物件 /**  * 用來儲存圖片的選中情況  */ private HashMap<Integer, Boolean> mSelectMap = new HashMap<Integer, Boolean>(); private GridView mGridView; private List<String> list; protected LayoutInflater mInflater; public ChildAdapter(Context context, List<String> list, GridView mGridView) {  this.list = list;  this.mGridView = mGridView;  mInflater = LayoutInflater.from(context); }  @Override public int getCount() {  return list.size(); } @Override public Object getItem(int position) {  return list.get(position); } @Override public long getItemId(int position) {  return position; }  @Override public View getView(final int position, View convertView, ViewGroup parent) {  final ViewHolder viewHolder;  String path = list.get(position);    if(convertView == null){   convertView = mInflater.inflate(R.layout.grid_child_item, null);   viewHolder = new ViewHolder();   viewHolder.mImageView = (MyImageView) convertView.findViewById(R.id.child_image);   viewHolder.mCheckBox = (CheckBox) convertView.findViewById(R.id.child_checkbox);      //用來監聽ImageView的寬和高   viewHolder.mImageView.setOnMeasureListener(new OnMeasureListener() {        @Override    public void onMeasureSize(int width, int height) {     mPoint.set(width, height);    }   });      convertView.setTag(viewHolder);  }else{   viewHolder = (ViewHolder) convertView.getTag();   viewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no);  }  viewHolder.mImageView.setTag(path);  viewHolder.mCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {      @Override   public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {    //如果是未選中的CheckBox,則新增動畫    if(!mSelectMap.containsKey(position) || !mSelectMap.get(position)){     addAnimation(viewHolder.mCheckBox);    }    mSelectMap.put(position, isChecked);   }  });    viewHolder.mCheckBox.setChecked(mSelectMap.containsKey(position) ? mSelectMap.get(position) : false);   &nb