仿微信图片选择器

仿微信图片选择器

源码下载连接:

先上图,后上代码:
仿微信图片选择器

打开app后点击添加图片按钮:仿微信图片选择器
仿微信图片选择器
获取选择的图片 并返回在gridview中:
仿微信图片选择器
实现该功能的重要组成部分有:利用gridview加载本地图片,gridView控件的使用,Intent之间数据的传递,和利用ContentProvider获取图片,和PopupWindow弹出页面的使用,利用Bitmap解决OOM问题。

下面开始贴出代码:
MainActivity文件的代码如下:
`import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.SimpleAdapter;
import android.widget.SimpleAdapter.ViewBinder;
import android.widget.Toast;

public class MainActivity extends Activity {

private ImageButton imageButton_poprecommend_back;
private Button button_poprecommend_fabu;
private EditText editText_poprecommend;
private ImageButton imageButton_poprecommend_tianjia;
private GridView gridView_poprecommend;
private PopRecommend_ImageAdd_Adapter imageAdapter;

private ArrayList<String> shuju = new ArrayList<String>();
public static MainActivity activity;



@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    activity = this;

    FindId();
    Dianji();

    shuju = new ArrayList<String>();
    Intent intent = this.getIntent();
    shuju = intent.getStringArrayListExtra("shuju");
    if (shuju != null) {
        imageAdapter = new PopRecommend_ImageAdd_Adapter(this, shuju);
        gridView_poprecommend.setAdapter(imageAdapter);
    }

}

private void FindId() {
    imageButton_poprecommend_back = (ImageButton) findViewById(R.id.imagview_poprecommend_back);
    button_poprecommend_fabu = (Button) findViewById(R.id.button_poprecommend_fabu);
    editText_poprecommend = (EditText) findViewById(R.id.edittext_poprecommend);
    imageButton_poprecommend_tianjia = (ImageButton) findViewById(R.id.iamgebutton_poprecommend_tianjiatupian);
    gridView_poprecommend = (GridView)this.findViewById(R.id.gridview_poprecommend);

}

private void Dianji() {
    imageButton_poprecommend_back.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (Activity_Image_Add.imageAdd!=null)
                 Activity_Image_Add.imageAdd.finish();
        }
    });

    button_poprecommend_fabu.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (Activity_Image_Add.imageAdd!=null)
                Activity_Image_Add.imageAdd.finish();



            if (editText_poprecommend.getText().toString().equals("")) {
                Toast.makeText(getApplication(), "发布内容不能为空", Toast.LENGTH_SHORT).show();
            } else
                Toast.makeText(getApplication(), "发布成功", Toast.LENGTH_SHORT).show();
        }
    });

    imageButton_poprecommend_tianjia.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {

            Intent intent = new Intent(getApplication(), Activity_Image_Add.class);
            startActivity(intent);

        }
    });

}

}
`
Activity_Image_Add activity的页面代码:

package com.xiyouliwp.fangweixin;

import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.GridView;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

/**
 * 需求:IPet的图片选择器,
 * Created by lwp940118 on 2016/5/29.
 * 李文朋
 */
public class Activity_Image_Add extends Activity implements List_File_PopWind.OnImageDirSelected {

    private ImageButton imageButton_ImageAdd_back;
    private ImageButton imageButton_ImageAdd_finish;
    private GridView gridView_ImageAdd;
    int totalCount = 0;
    /**
     * 存储文件夹中的图片数量
     */
    private int mPicSize = 0;
    /**
     * 图片数量最多的文件夹
     */
    private File maxImageFile;

    private RelativeLayout relativeLayout_popwind;

    /**
     * 所以图片
     */
    private List<String> mImags;

    /**
     * list存放扫描到的文件夹的信息
     */
    private List<ImageFolder> imageFolders = new ArrayList<ImageFolder>();
    /**
     * hashset  基于hashmap实现的,利用他可以防止一个文件夹  多次扫描
     */
    private HashSet<String> mImagePath = new HashSet<String>();

    //弹出对话框  进度条
    private ProgressDialog mprogressDialog;

    private TextView textview_ChooseDir;
    private TextView textview_ImageCount;

    //定义屏幕的高度
    private int screenHeight = 0;

    /**
     * 用户选择的图片,存储为图片的完整路径
     */
    public static List<String> mSelectedImage = new LinkedList<String>();
    private ArrayList<String> shuju;

    private MyAdapter myAdapter;

    private List_File_PopWind popWind;
    public static Activity_Image_Add imageAdd;

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            //加载的那个对话框  销毁
            mprogressDialog.dismiss();
            //view绑定数据
            dateView();
            //初始化Popwind
            initPopWind();
        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_image_add);

        DisplayMetrics displayMetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        screenHeight = displayMetrics.heightPixels;
        Log.e("screenHeight---->", "" + screenHeight);
        imageAdd = this;

        findId();
        kongJianSheZhi();
        getImages();
        initEvent();


    }

    // 返回按键调用
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {

            if (MainActivity.activity!=null)
                MainActivity.activity.finish();
            shuju = new ArrayList<String>();
            for (int i = 0; i < mSelectedImage.size(); i++)
                shuju.add(mSelectedImage.get(i));
            Intent intent = new Intent(getApplicationContext(),MainActivity.class);
            intent.putStringArrayListExtra("shuju",shuju);
            startActivity(intent);
        }
        return true;
    }

    /**
     * 弹出popwind
     */
    private void initEvent() {
        relativeLayout_popwind.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                popWind.setAnimationStyle(R.style.AnimBottom);
                popWind.showAtLocation(Activity_Image_Add.this.findViewById(R.id.imagebutton_imageadd_back),
                        Gravity.BOTTOM, 0, 0);

                // 设置背景颜色变暗
                WindowManager.LayoutParams lp = getWindow().getAttributes();
                lp.alpha = 0.3f;
                getWindow().setAttributes(lp);
            }
        });

    }

    /**
     * 绑定view的数据
     */
    private void dateView() {
        if (maxImageFile == null) {
            Toast.makeText(getApplicationContext(), "没有扫描到图片", Toast.LENGTH_SHORT).show();
            return;
        }

        //aslist  连接列表与数组,当一个更新时 另一个也自动更新但是没有add  和remove方法
        mImags = Arrays.asList(maxImageFile.list());
        myAdapter = new MyAdapter(getApplicationContext(), mImags, R.layout.item_gridview_imageadd,
                maxImageFile.getAbsolutePath());
        gridView_ImageAdd.setAdapter(myAdapter);
        //显示多少张图片 在popwind中
        textview_ImageCount.setText(totalCount + "张");
    }

    /**
     * 初始化popwind的弹出界面
     */
    private void initPopWind() {
        popWind = new List_File_PopWind(LinearLayout.LayoutParams.MATCH_PARENT, (int) (screenHeight
                * 0.7), imageFolders, LayoutInflater.from(getApplicationContext())
                .inflate(R.layout.list_dir, null));
        popWind.setOnDismissListener(new PopupWindow.OnDismissListener() {
            @Override
            public void onDismiss() {
                // 设置背景颜色变暗
                WindowManager.LayoutParams lp = getWindow().getAttributes();
                lp.alpha = 1.0f;
                getWindow().setAttributes(lp);
            }
        });
        //设置文件夹的回调
        popWind.setOnImageDirSelected(this);
    }

    /**
     * 利用contentProvider扫描手机中的图片,并获取jpn最多的那个文件夹
     * ContentProvider  为Android四大组件,详情见我的博客
     * Android四大组件介绍http://blog.csdn.net/qq_30000411/article/details/51355390
     */

    private void getImages() {

        //判断Sd卡的状态 是否可用
        if (!Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) {
            Toast.makeText(getApplicationContext(), "没有找到SD", Toast.LENGTH_SHORT).show();
        }
        //显示进度条  加载中...
        mprogressDialog = ProgressDialog.show(this, null, "图片读取中...");
        new Thread(new Runnable() {
            @Override
            public void run() {
                //读取第一张图片
                String firstImagePath = null;
                //EXTERNAL_CONTENT_URI多选
                Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                //ContentResolver应用之间数据共享
                ContentResolver mResolver = Activity_Image_Add.this.getContentResolver();
                //数据查找,找出JPEG和png格式的图片,,,MediaStore为Android手机系统的多媒体数据库
                Cursor mCursor = mResolver.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);
                //读取图片
                while (mCursor.moveToNext()) {
                    //定义图片的路径
                    String imagePath = mCursor.getString(mCursor.getColumnIndex
                            (MediaStore.Images.Media.DATA));
                    //获取第一张图片的路径
                    if (firstImagePath == null)
                        firstImagePath = imagePath;

                    //获取该图片的父路径名
                    File parentFile = new File(imagePath).getParentFile();
                    if (parentFile == null)
                        continue;
                    String folderPath = parentFile.getAbsolutePath();
                    ImageFolder imageFolder = null;
                    //利用hashset防止一个文件夹被多次扫描
                    if (mImagePath.contains(folderPath)) {
                        continue;
                    } else {
                        mImagePath.add(folderPath);
                        //初始化  ImageFolder
                        imageFolder = new ImageFolder();
                        imageFolder.setFolderPath(folderPath);
                        imageFolder.setFirstImagePath(imagePath);
                    }
                    int picSize = parentFile.list(new FilenameFilter() {
                        @Override
                        public boolean accept(File dir, String filename) {
                            if (filename.endsWith(".png") || filename.endsWith(".jpg")
                                    || filename.endsWith(".jpeg"))
                                return true;
                            return false;
                        }
                    }).length;

                    totalCount += picSize;
                    imageFolder.setImageCount(picSize);
                    imageFolders.add(imageFolder);
                    //更新最大数量文件夹
                    if (picSize > mPicSize) {
                        mPicSize = picSize;
                        maxImageFile = parentFile;
                    }
                }
                mCursor.close();
                //扫描完成  hashset释放
                mImagePath = null;
                //通知  线程Handler  图片扫秒完成
                handler.sendEmptyMessage(0x110);

            }
        }).start();

    }

    private void findId() {

        gridView_ImageAdd = (GridView) findViewById(R.id.gridview_imageadd);
        imageButton_ImageAdd_back = (ImageButton) findViewById(R.id.imagebutton_imageadd_back);
        imageButton_ImageAdd_finish = (ImageButton) findViewById(R.id.imagebutton_imageadd_finish);
        textview_ChooseDir = (TextView) findViewById(R.id.id_choose_dir);
        textview_ImageCount = (TextView) findViewById(R.id.id_total_count);
        relativeLayout_popwind = (RelativeLayout) findViewById(R.id.id_bottom_ly);

    }

    private void kongJianSheZhi() {

        imageButton_ImageAdd_finish.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("完成--->","完成");
                if (MainActivity.activity!=null)
                    MainActivity.activity.finish();
                shuju = new ArrayList<String>();
                for (int i = 0; i < mSelectedImage.size(); i++)
                    shuju.add(mSelectedImage.get(i));
                Intent intent = new Intent(getApplicationContext(),MainActivity.class);
                intent.putStringArrayListExtra("shuju",shuju);
                startActivity(intent);
            }
        });

        imageButton_ImageAdd_back.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });

    }

    @Override
    public void selected(ImageFolder floder) {

        maxImageFile = new File(floder.getFolderPath());
        mImags = Arrays.asList(maxImageFile.list(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String filename) {
                if (filename.endsWith(".jpg") || filename.endsWith(".png")
                        || filename.endsWith(".jpeg"))
                    return true;
                return false;
            }
        }));
        /**
         * 可以看到文件夹的路径和图片的路径分开保存,极大的减少了内存的消耗;
         */
        myAdapter = new MyAdapter(getApplicationContext(), mImags,
                R.layout.item_gridview_imageadd, maxImageFile.getAbsolutePath());
        gridView_ImageAdd.setAdapter(myAdapter);
        // mAdapter.notifyDataSetChanged();
        textview_ImageCount.setText(floder.getImageCount() + "张");
        textview_ChooseDir.setText(floder.getFolderName());
        popWind.dismiss();

    }

    /**
     * gridview的定义适配器
     */

    public class MyAdapter extends CommonAdapter<String> {

        /**
         * 文件夹路径
         */
        private String mDirPath;

        public MyAdapter(Context context, List<String> mDatas, int itemLayoutId,
                         String dirPath) {
            super(context, mDatas, itemLayoutId);
            this.mDirPath = dirPath;
        }

        @Override
        public void convert(final ViewHolder helper, final String item) {
            //设置no_pic
            helper.setImageResource(R.id.id_item_image, R.drawable.pictures_no);
            //设置no_selected
            helper.setImageResource(R.id.id_item_select,
                    R.drawable.picture_unselected);
            //设置图片
            helper.setImageByUrl(R.id.id_item_image, mDirPath + "/" + item);

            final ImageView mImageView = helper.getView(R.id.id_item_image);
            final ImageView mSelect = helper.getView(R.id.id_item_select);

            mImageView.setColorFilter(null);
            //设置ImageView的点击事件
            mImageView.setOnClickListener(new View.OnClickListener() {
                //选择,则将图片变暗,反之则反之
                @Override
                public void onClick(View v) {

                    // 已经选择过该图片
                    if (mSelectedImage.contains(mDirPath + "/" + item)) {
                        mSelectedImage.remove(mDirPath + "/" + item);
                        mSelect.setImageResource(R.drawable.picture_unselected);
                        mImageView.setColorFilter(null);
                    } else {// 未选择该图片
                        mSelectedImage.add(mDirPath + "/" + item);
                        mSelect.setImageResource(R.drawable.pictures_selected);
                        mImageView.setColorFilter(Color.parseColor("#77000000"));
                    }

                }
            });

            /**
             * 已经选择过的图片,显示出选择过的效果
             */
            if (mSelectedImage.contains(mDirPath + "/" + item)) {
                mSelect.setImageResource(R.drawable.pictures_selected);
                mImageView.setColorFilter(Color.parseColor("#77000000"));
            }

        }
    }
}

BitmapUtilities问价:用于缩小图片的尺寸,避免OOM问题出现

package com.xiyouliwp.fangweixin;

/**
 * Created by lwp940118 on 2016/5/31.
 */
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;

public class BitmapUtilities {

    public BitmapUtilities() {
        // TODO Auto-generated constructor stub
    }

    public static Bitmap getBitmapThumbnail(String path,int width,int height){
        Bitmap bitmap = null;
        //这里可以按比例缩小图片:
        /*BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inSampleSize = 4;//宽和高都是原来的1/4
        bitmap = BitmapFactory.decodeFile(path, opts); */

        /*进一步的,
                如何设置恰当的inSampleSize是解决该问题的关键之一。BitmapFactory.Options提供了另一个成员inJustDecodeBounds。
               设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。
               有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize。*/
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, opts);
        opts.inSampleSize = Math.max((int)(opts.outHeight / (float) height), (int)(opts.outWidth / (float) width));
        opts.inJustDecodeBounds = false;
        bitmap = BitmapFactory.decodeFile(path, opts);
        return bitmap;
    }

    public static Bitmap getBitmapThumbnail(Bitmap bmp,int width,int height){
        Bitmap bitmap = null;
        if(bmp != null ){
            int bmpWidth = bmp.getWidth();
            int bmpHeight = bmp.getHeight();
            if(width != 0 && height !=0){
                Matrix matrix = new Matrix();
                float scaleWidth = ((float) width / bmpWidth);
                float scaleHeight = ((float) height / bmpHeight);
                matrix.postScale(scaleWidth, scaleHeight);
                bitmap = Bitmap.createBitmap(bmp, 0, 0, bmpWidth, bmpHeight, matrix, true);
            }else{
                bitmap = bmp;
            }
        }
        return bitmap;
    }

}

CommonAdapter文件:超级适配器,也成通配器,可以使用gridview和listview共同使用:

package com.xiyouliwp.fangweixin;

import java.util.List;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

/**
 * 通配器,CommonAdapter通过封装BaseAdapter和RecyclerView.Adapter得到通用的、简单易用的Adapter。
 * 作为ListView和GridView的通用适配器。
 * 超级适配器
 * @param <T>
 */

public abstract class CommonAdapter<T> extends BaseAdapter {
    protected LayoutInflater mInflater;
    protected Context mContext;
    protected List<T> mDatas;
    protected final int mItemLayoutId;

    public CommonAdapter(Context context, List<T> mDatas, int itemLayoutId) {
        this.mContext = context;
        this.mInflater = LayoutInflater.from(mContext);
        this.mDatas = mDatas;
        this.mItemLayoutId = itemLayoutId;
    }

    @Override
    public int getCount() {
        return mDatas.size();
    }

    @Override
    public T getItem(int position) {
        return mDatas.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final ViewHolder viewHolder = getViewHolder(position, convertView,
                parent);
        convert(viewHolder, getItem(position));
        return viewHolder.getConvertView();

    }

    public abstract void convert(ViewHolder helper, T item);

    private ViewHolder getViewHolder(int position, View convertView,
                                     ViewGroup parent) {
        return ViewHolder.get(mContext, convertView, parent, mItemLayoutId,
                position);
    }

}

DiskLruCache文件:点击获取到的图片的path路径进行解析

package com.xiyouliwp.fangweixin;
/**
 * Created by lwp940118 on 2016/5/31.
 */

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;

public class DiskLruCache {
    private static final String CACHE_FILENAME_PREFIX = "cache_";
    private static final int MAX_REMOVALS = 4;
    private static final int INITIAL_CAPACITY = 32;
    private static final float LOAD_FACTOR = 0.75f;

    private final File mCacheDir;
    private int cacheSize = 0;
    private int cacheByteSize = 0;
    private final int maxCacheItemSize = 64; // 64 item default
    private long maxCacheByteSize = 1024 * 1024 * 5; // 5MB default
    private CompressFormat mCompressFormat = CompressFormat.JPEG;
    private int mCompressQuality = 70;
    private final int IO_BUFFER_SIZE = 4 * 1024;

    private final Map<String, String> mLinkedHashMap = Collections.synchronizedMap(new LinkedHashMap<String, String>(INITIAL_CAPACITY, LOAD_FACTOR, true));

    /**
     * A filename filter to use to identify the cache filenames which have CACHE_FILENAME_PREFIX prepended.
     */
    private static final FilenameFilter cacheFileFilter = new FilenameFilter() {
        @Override
        public boolean accept(File dir, String filename) {
            return filename.startsWith(CACHE_FILENAME_PREFIX);
        }
    };

    /**
     * Used to fetch an instance of DiskLruCache.
     *
     * @param context
     * @param cacheDir
     * @param maxByteSize
     * @return
     */
    public static DiskLruCache openCache(Context context, File cacheDir, long maxByteSize) {
        if (!cacheDir.exists()) {
            cacheDir.mkdir();
        }

        if (cacheDir.isDirectory() && cacheDir.canWrite()) {
            return new DiskLruCache(cacheDir, maxByteSize);
        }

        return null;
    }

    /**
     * @param cacheDir
     * @param maxByteSize
     */
    private DiskLruCache(File cacheDir, long maxByteSize) {
        mCacheDir = cacheDir;
        maxCacheByteSize = maxByteSize;
    }

    /**
     * Add a bitmap to the disk cache.
     *
     * @param key  A unique identifier for the bitmap.
     * @param data The bitmap to store.
     */
    public void put(String key, Bitmap data) {
        synchronized (mLinkedHashMap) {
            if (mLinkedHashMap.get(key) == null) {
                try {
                    final String file = createFilePath(mCacheDir, key);
                    if (writeBitmapToFile(data, file)) {
                        put(key, file);
                        flushCache();
                    }
                } catch (final FileNotFoundException e) {
                } catch (final IOException e) {
                }
            }
        }
    }

    private void put(String key, String file) {
        mLinkedHashMap.put(key, file);
        cacheSize = mLinkedHashMap.size();
        cacheByteSize += new File(file).length();
    }

    /**
     * Flush the cache, removing oldest entries if the total size is over the specified cache size. Note that this isn‘t keeping track of stale files in the cache directory that
     * aren‘t in the HashMap. If the images and keys in the disk cache change often then they probably won‘t ever be removed.
     */
    private void flushCache() {
        Entry<String, String> eldestEntry;
        File eldestFile;
        long eldestFileSize;
        int count = 0;

        while (count < MAX_REMOVALS && (cacheSize > maxCacheItemSize || cacheByteSize > maxCacheByteSize)) {
            eldestEntry = mLinkedHashMap.entrySet().iterator().next();
            eldestFile = new File(eldestEntry.getValue());
            eldestFileSize = eldestFile.length();
            mLinkedHashMap.remove(eldestEntry.getKey());
            eldestFile.delete();
            cacheSize = mLinkedHashMap.size();
            cacheByteSize -= eldestFileSize;
            count++;
        }
    }

    /**
     * Get an image from the disk cache.
     *
     * @param key The unique identifier for the bitmap
     * @return The bitmap or null if not found
     */
    public Bitmap get(String key) {
        synchronized (mLinkedHashMap) {
            try {
                final String file = mLinkedHashMap.get(key);
                if (file != null) {
                    return BitmapFactory.decodeFile(file);
                } else {
                    final String existingFile = createFilePath(mCacheDir, key);
                    if (new File(existingFile).exists()) {
                        put(key, existingFile);
                        return BitmapFactory.decodeFile(existingFile);
                    }
                }
            } catch (OutOfMemoryError e) {
            }
            return null;
        }
    }

    /**
     * Checks if a specific key exist in the cache.
     *
     * @param key The unique identifier for the bitmap
     * @return true if found, false otherwise
     */
    public boolean containsKey(String key) {
        // See if the key is in our HashMap
        if (mLinkedHashMap.containsKey(key)) {
            return true;
        }

        // Now check if there‘s an actual file that exists based on the key
        final String existingFile = createFilePath(mCacheDir, key);
        if (new File(existingFile).exists()) {
            // File found, add it to the HashMap for future use
            put(key, existingFile);
            return true;
        }
        return false;
    }

    /**
     * Removes all disk cache entries from this instance cache dir
     */
    public void clearCache() {
        DiskLruCache.clearCache(mCacheDir);
    }

    /**
     * Removes all disk cache entries from the application cache directory in the uniqueName sub-directory.
     *
     * @param context    The context to use
     * @param uniqueName A unique cache directory name to append to the app cache directory
     */
    public static void clearCache(Context context, String uniqueName) {
        File cacheDir = getDiskCacheDir(context, uniqueName);
        clearCache(cacheDir);
    }

    /**
     * Removes all disk cache entries from the given directory. This should not be called directly, call {@link DiskLruCache#clearCache(Context, String)} or
     * {@link DiskLruCache#clearCache()} instead.
     *
     * @param cacheDir The directory to remove the cache files from
     */
    private static void clearCache(File cacheDir) {
        final File[] files = cacheDir.listFiles(cacheFileFilter);
        for (int i = 0; i < files.length; i++) {
            files[i].delete();
        }
    }

    /**
     * Get a usable cache directory (external if available, internal otherwise).
     *
     * @param context    The context to use
     * @param uniqueName A unique directory name to append to the cache dir
     * @return The cache dir
     */
    public static File getDiskCacheDir(Context context, String uniqueName) {

        // Check if media is mounted or storage is built-in, if so, try and use external cache dir
        // otherwise use internal cache dir
        final String cachePath = context.getCacheDir().getPath();

        return new File(cachePath + File.separator + uniqueName);
    }

    /**
     * Creates a constant cache file path given a target cache directory and an image key.
     *
     * @param cacheDir
     * @param key
     * @return
     */
    public static String createFilePath(File cacheDir, String key) {
        try {
            // Use URLEncoder to ensure we have a valid filename, a tad hacky but it will do for
            // this example
            return cacheDir.getAbsolutePath() + File.separator + CACHE_FILENAME_PREFIX + URLEncoder.encode(key.replace("*", ""), "UTF-8");
        } catch (final UnsupportedEncodingException e) {
        }

        return null;
    }

    /**
     * Create a constant cache file path using the current cache directory and an image key.
     *
     * @param key
     * @return
     */
    public String createFilePath(String key) {
        return createFilePath(mCacheDir, key);
    }

    /**
     * Sets the target compression format and quality for images written to the disk cache.
     *
     * @param compressFormat
     * @param quality
     */
    public void setCompressParams(CompressFormat compressFormat, int quality) {
        mCompressFormat = compressFormat;
        mCompressQuality = quality;
    }

    /**
     * Writes a bitmap to a file. Call {@link DiskLruCache#setCompressParams(CompressFormat, int)} first to set the target bitmap compression and format.
     *
     * @param bitmap
     * @param file
     * @return
     */
    private boolean writeBitmapToFile(Bitmap bitmap, String file) throws IOException, FileNotFoundException {

        OutputStream out = null;
        try {
            out = new BufferedOutputStream(new FileOutputStream(file), IO_BUFFER_SIZE);
            return bitmap.compress(mCompressFormat, mCompressQuality, out);
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }
}

ImageFolder文件:图片的信息的定义:

package com.xiyouliwp.fangweixin;


/**
 * 需求:对手机中的图片进行扫描,直接显示在gridview上,并且在扫描结束后得到一个list,,list里面存的是所有包含
 * 图片的文件夹
 * Created by lwp940118 on 2016/5/29.
 * 李文朋
 */
public class ImageFolder {

    //文件夹的路径
    private String folderPath;

    //第一张图片的文件夹路径
    private String firstImagePath;

    //文件夹名称
    private String folderName;

    //图片的数量
    private int imageCount = 0;

    public int getImageCount() {
        return imageCount;
    }

    public String getFirstImagePath() {
        return firstImagePath;
    }

    public String getFolderName() {
        return folderName;
    }

    public String getFolderPath() {
        return folderPath;
    }

    public void setFirstImagePath(String firstImagePath) {
        this.firstImagePath = firstImagePath;
    }


    public void setFolderPath(String folderPath) {
        this.folderPath = folderPath;
        //判断字符/它第一次出现的位置
        int start = this.folderPath.lastIndexOf("/");
        //得到从/第一次出现的位置开始  到该字符串结束的子串为folderName
        this.folderName = this.folderPath.substring(start);
    }

    public void setImageCount(int imageCount) {
        this.imageCount = imageCount;
    }
}

ImageLoade文件:缓存图片,使grideview运行流畅

package com.xiyouliwp.fangweixin;

import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v4.util.LruCache;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;

public class ImageLoade {
    /**
     * 图片缓存的核心类
     */
    private LruCache<String, Bitmap> mLruCache;
    /**
     * 线程池
     */
    private ExecutorService mThreadPool;
    /**
     * 线程池的线程数量,默认为1
     */
    private int mThreadCount = 1;
    /**
     * 队列的调度方式
     */
    private Type mType = Type.LIFO;
    /**
     * 任务队列
     */
    private LinkedList<Runnable> mTasks;
    /**
     * 轮询的线程
     */
    private Thread mPoolThread;
    private Handler mPoolThreadHander;

    /**
     * 运行在UI线程的handler,用于给ImageView设置图片
     */
    private Handler mHandler;

    /**
     * 引入一个值为1的信号量,防止mPoolThreadHander未初始化完成
     */
    private volatile Semaphore mSemaphore = new Semaphore(0);

    /**
     * 引入一个值为1的信号量,由于线程池内部也有一个阻塞线程,防止加入任务的速度过快,使LIFO效果不明显
     */
    private volatile Semaphore mPoolSemaphore;

    private static ImageLoade mInstance;

    /**
     * 队列的调度方式
     *
     * @author zhy
     */
    public enum Type {
        FIFO, LIFO
    }


    /**
     * 单例获得该实例对象
     *
     * @return
     */
    public static ImageLoade getInstance() {

        if (mInstance == null) {
            synchronized (ImageLoade.class) {
                if (mInstance == null) {
                    mInstance = new ImageLoade(1, Type.LIFO);
                }
            }
        }
        return mInstance;
    }

    private ImageLoade(int threadCount, Type type) {
        init(threadCount, type);
    }

    private void init(int threadCount, Type type) {
        // loop thread
        mPoolThread = new Thread() {
            @Override
            public void run() {
                Looper.prepare();

                mPoolThreadHander = new Handler() {
                    @Override
                    public void handleMessage(Message msg) {
                        mThreadPool.execute(getTask());
                        try {
                            mPoolSemaphore.acquire();
                        } catch (InterruptedException e) {
                        }
                    }
                };
                // 释放一个信号量
                mSemaphore.release();
                Looper.loop();
            }
        };
        mPoolThread.start();

        // 获取应用程序最大可用内存
        int maxMemory = (int) Runtime.getRuntime().maxMemory();
        int cacheSize = maxMemory / 8;
        mLruCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes() * value.getHeight();
            }

            ;
        };

        mThreadPool = Executors.newFixedThreadPool(threadCount);
        mPoolSemaphore = new Semaphore(threadCount);
        mTasks = new LinkedList<Runnable>();
        mType = type == null ? Type.LIFO : type;

    }

    /**
     * 加载图片
     *
     * @param path
     * @param imageView
     */
    public void loadImage(final String path, final ImageView imageView) {
        // set tag
        imageView.setTag(path);
        // UI线程
        if (mHandler == null) {
            mHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    ImgBeanHolder holder = (ImgBeanHolder) msg.obj;
                    ImageView imageView = holder.imageView;
                    Bitmap bm = holder.bitmap;
                    String path = holder.path;
                    if (imageView.getTag().toString().equals(path)) {
                        imageView.setImageBitmap(bm);
                    }
                }
            };
        }

        Bitmap bm = getBitmapFromLruCache(path);
        if (bm != null) {
            ImgBeanHolder holder = new ImgBeanHolder();
            holder.bitmap = bm;
            holder.imageView = imageView;
            holder.path = path;
            Message message = Message.obtain();
            message.obj = holder;
            mHandler.sendMessage(message);
        } else {
            addTask(new Runnable() {
                @Override
                public void run() {

                    ImageSize imageSize = getImageViewWidth(imageView);

                    int reqWidth = imageSize.width;
                    int reqHeight = imageSize.height;

                    Bitmap bm = decodeSampledBitmapFromResource(path, reqWidth,
                            reqHeight);
                    addBitmapToLruCache(path, bm);
                    ImgBeanHolder holder = new ImgBeanHolder();
                    holder.bitmap = getBitmapFromLruCache(path);
                    holder.imageView = imageView;
                    holder.path = path;
                    Message message = Message.obtain();
                    message.obj = holder;
                    // Log.e("TAG", "mHandler.sendMessage(message);");
                    mHandler.sendMessage(message);
                    mPoolSemaphore.release();
                }
            });
        }

    }

    /**
     * 添加一个任务
     *
     * @param runnable
     */
    private synchronized void addTask(Runnable runnable) {
        try {
            // 请求信号量,防止mPoolThreadHander为null
            if (mPoolThreadHander == null)
                mSemaphore.acquire();
        } catch (InterruptedException e) {
        }
        mTasks.add(runnable);

        mPoolThreadHander.sendEmptyMessage(0x110);
    }

    /**
     * 取出一个任务
     *
     * @return
     */
    private synchronized Runnable getTask() {
        if (mType == Type.FIFO) {
            return mTasks.removeFirst();
        } else if (mType == Type.LIFO) {
            return mTasks.removeLast();
        }
        return null;
    }

    /**
     * 单例获得该实例对象
     *
     * @return
     */
    public static ImageLoade getInstance(int threadCount, Type type) {

        if (mInstance == null) {
            synchronized (ImageLoade.class) {
                if (mInstance == null) {
                    mInstance = new ImageLoade(threadCount, type);
                }
            }
        }
        return mInstance;
    }


    /**
     * 根据ImageView获得适当的压缩的宽和高
     *
     * @param imageView
     * @return
     */
    private ImageSize getImageViewWidth(ImageView imageView) {
        ImageSize imageSize = new ImageSize();
        final DisplayMetrics displayMetrics = imageView.getContext()
                .getResources().getDisplayMetrics();
        final LayoutParams params = imageView.getLayoutParams();

        int width = params.width == LayoutParams.WRAP_CONTENT ? 0 : imageView
                .getWidth(); // Get actual image width
        if (width <= 0)
            width = params.width; // Get layout width parameter
        if (width <= 0)
            width = getImageViewFieldValue(imageView, "mMaxWidth"); // Check
        // maxWidth
        // parameter
        if (width <= 0)
            width = displayMetrics.widthPixels;
        int height = params.height == LayoutParams.WRAP_CONTENT ? 0 : imageView
                .getHeight(); // Get actual image height
        if (height <= 0)
            height = params.height; // Get layout height parameter
        if (height <= 0)
            height = getImageViewFieldValue(imageView, "mMaxHeight"); // Check
        // maxHeight
        // parameter
        if (height <= 0)
            height = displayMetrics.heightPixels;
        imageSize.width = width;
        imageSize.height = height;
        return imageSize;

    }

    /**
     * 从LruCache中获取一张图片,如果不存在就返回null。
     */
    private Bitmap getBitmapFromLruCache(String key) {
        return mLruCache.get(key);
    }

    /**
     * 往LruCache中添加一张图片
     *
     * @param key
     * @param bitmap
     */
    private void addBitmapToLruCache(String key, Bitmap bitmap) {
        if (getBitmapFromLruCache(key) == null) {
            if (bitmap != null)
                mLruCache.put(key, bitmap);
        }
    }

    /**
     * 计算inSampleSize,用于压缩图片
     *
     * @param options
     * @param reqWidth
     * @param reqHeight
     * @return
     */
    private int calculateInSampleSize(BitmapFactory.Options options,
                                      int reqWidth, int reqHeight) {
        // 源图片的宽度
        int width = options.outWidth;
        int height = options.outHeight;
        int inSampleSize = 1;

        if (width > reqWidth && height > reqHeight) {
            // 计算出实际宽度和目标宽度的比率
            int widthRatio = Math.round((float) width / (float) reqWidth);
            int heightRatio = Math.round((float) width / (float) reqWidth);
            inSampleSize = Math.max(widthRatio, heightRatio);
        }
        return inSampleSize;
    }

    /**
     * 根据计算的inSampleSize,得到压缩后图片
     *
     * @param pathName
     * @param reqWidth
     * @param reqHeight
     * @return
     */
    private Bitmap decodeSampledBitmapFromResource(String pathName,
                                                   int reqWidth, int reqHeight) {
        // 第一次解析将inJustDecodeBounds设置为true,来获取图片大小
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(pathName, options);
        // 调用上面定义的方法计算inSampleSize值
        options.inSampleSize = calculateInSampleSize(options, reqWidth,
                reqHeight);
        // 使用获取到的inSampleSize值再次解析图片
        options.inJustDecodeBounds = false;
        Bitmap bitmap = BitmapFactory.decodeFile(pathName, options);

        return bitmap;
    }

    private class ImgBeanHolder {
        Bitmap bitmap;
        ImageView imageView;
        String path;
    }

    private class ImageSize {
        int width;
        int height;
    }

    /**
     * 反射获得ImageView设置的最大宽度和高度
     *
     * @param object
     * @param fieldName
     * @return
     */
    private static int getImageViewFieldValue(Object object, String fieldName) {
        int value = 0;
        try {
            Field field = ImageView.class.getDeclaredField(fieldName);
            field.setAccessible(true);
            int fieldValue = (Integer) field.get(object);
            if (fieldValue > 0 && fieldValue < Integer.MAX_VALUE) {
                value = fieldValue;

                Log.e("TAG", value + "");
            }
        } catch (Exception e) {
        }
        return value;
    }

}

ImageShowManager文件:图片的一些信息及其缓存情况的设置

package com.xiyouliwp.fangweixin;


/**
 * Created by lwp940118 on 2016/5/31.
 */
import java.io.File;

import android.app.ActivityManager;
import android.app.Application;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Looper;
import android.support.v4.util.LruCache;

public class ImageShowManager {

    private static ImageShowManager imageManager;
    private static Application myApp;
    private LruCache<String, Bitmap> mMemoryCache;
    private DiskLruCache mDiskCache;
    // 硬盘缓存区域的大小,可以提升之前浏览过的图片的显示速度
    private static final int DISK_CACHE_SIZE = 1024 * 1024 * 20;
    // 硬盘缓存区域的文件名称
    private static final String DISK_CACHE_SUBDIR = "thumbnails";

    public static final int bitmap_width = 100;
    public static final int bitmap_height = 100;

    public static ImageShowManager from(Context context) {
        // 如果不在ui线程中,则抛出异常
        if (Looper.myLooper() != Looper.getMainLooper()) {
            throw new RuntimeException("Cannot instantiate outside UI thread.");
        }

        if (myApp == null) {
            myApp = (Application) context.getApplicationContext();
        }

        if (imageManager == null) {
            imageManager = new ImageShowManager(myApp);
        }
        //
        return imageManager;
    }

    /**
     * 私有的构造器为了保持单例模式
     */
    private ImageShowManager(Context context) {
        /********** 初始化内存缓冲区 ******/
        int memClass = ((ActivityManager) context
                .getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
        memClass = memClass > 32 ? 32 : memClass;
        // 使用可用内存的1/8作为图片缓存
        final int cacheSize = 1024 * 1024 * memClass / 8;
        mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                return bitmap.getRowBytes() * bitmap.getHeight();
            }
        };

        /********* 初始化硬盘缓冲区 *********/
        File cacheDir = DiskLruCache
                .getDiskCacheDir(context, DISK_CACHE_SUBDIR);
        mDiskCache = DiskLruCache.openCache(context, cacheDir, DISK_CACHE_SIZE);

    }

    /**
     * 将图片保存至本地缓存
     * @param key
     * @param value
     */
    public void putBitmapToDisk(String key,Bitmap value){
        mDiskCache.put(key, value);
    }

    /**
     * 从硬盘缓存中读取图像
     * @param url
     * @return
     */
    public Bitmap getBitmapFormDisk(String url){
        return mDiskCache.get(url);
    }

    /**
     * 从内存缓存区中获取bitmap,根据特定的url
     * @param url
     * @return
     */
    public Bitmap getBitmapFromMemory(String url){
        return mMemoryCache.get(url);
    }

    /**
     * 将新的图片添加至内存缓存区
     * @param key
     * @param value
     */
    public void putBitmapToMemery(String key,Bitmap value){
        mMemoryCache.put(key, value);
    }
}

List_File_PopWind文件:弹出窗口的设置及其定义:

package com.xiyouliwp.fangweixin;


import java.util.List;

import android.content.Context;
import android.graphics.drawable.BitmapDrawable;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.PopupWindow;


/**
 * Created by lwp940118 on 2016/5/29.
 */
public class List_File_PopWind extends
        BasePopupWindowForListView<ImageFolder>{

    private ListView mListDir;

    public List_File_PopWind(int width, int height,
                                   List<ImageFolder> datas, View convertView) {
        super(convertView, width, height, true, datas);
    }

    @Override
    public void initViews() {
        mListDir = (ListView) findViewById(R.id.listviwe_dir);
        mListDir.setAdapter(new CommonAdapter<ImageFolder>(context, mDatas,
                R.layout.list_dir_item) {
            @Override
            public void convert(ViewHolder helper, ImageFolder item) {
                helper.setText(R.id.id_dir_item_name, item.getFolderName());
                helper.setImageByUrl(R.id.id_dir_item_image,
                        item.getFirstImagePath());
                helper.setText(R.id.id_dir_item_count, item.getImageCount() + "张");
            }
        });
    }

    public interface OnImageDirSelected {
        void selected(ImageFolder floder);
    }

    private OnImageDirSelected mImageDirSelected;

    public void setOnImageDirSelected(OnImageDirSelected mImageDirSelected) {
        this.mImageDirSelected = mImageDirSelected;
    }

    @Override
    public void initEvents() {
        mListDir.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                                    int position, long id) {

                if (mImageDirSelected != null) {
                    mImageDirSelected.selected(mDatas.get(position));
                }
            }
        });
    }

    @Override
    public void init() {

    }

    @Override
    protected void beforeInitWeNeedSomeParams(Object... params) {

    }

}

abstract class BasePopupWindowForListView<T> extends PopupWindow {
    /**
     * 布局文件的最外层View
     */
    protected View mContentView;
    protected Context context;
    /**
     * ListView的数据集
     */
    protected List<T> mDatas;

    public BasePopupWindowForListView(View contentView, int width, int height,
                                      boolean focusable) {
        this(contentView, width, height, focusable, null);
    }

    public BasePopupWindowForListView(View contentView, int width, int height,
                                      boolean focusable, List<T> mDatas) {
        this(contentView, width, height, focusable, mDatas, new Object[0]);

    }

    public BasePopupWindowForListView(View contentView, int width, int height,
                                      boolean focusable, List<T> mDatas, Object... params) {
        super(contentView, width, height, focusable);
        this.mContentView = contentView;
        context = contentView.getContext();
        if (mDatas != null)
            this.mDatas = mDatas;

        if (params != null && params.length > 0) {
            beforeInitWeNeedSomeParams(params);
        }

        setBackgroundDrawable(new BitmapDrawable());
        setTouchable(true);
        setOutsideTouchable(true);
        setTouchInterceptor(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
                    dismiss();
                    return true;
                }
                return false;
            }
        });
        initViews();
        initEvents();
        init();
    }

    protected abstract void beforeInitWeNeedSomeParams(Object... params);

    public abstract void initViews();

    public abstract void initEvents();

    public abstract void init();

    public View findViewById(int id) {
        return mContentView.findViewById(id);
    }

    protected static int dpToPx(Context context, int dp) {
        return (int) (context.getResources().getDisplayMetrics().density * dp + 0.5f);
    }

}

PopRecommend_ImageAdd_Adapter文件:返回时存放选择图片的gridview的适配器

package com.xiyouliwp.fangweixin;

import java.lang.ref.WeakReference;
import java.util.ArrayList;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;


/**
 * Created by lwp940118 on 2016/5/31.
 */
public class PopRecommend_ImageAdd_Adapter extends BaseAdapter {

    private Activity uiActivity;
    private ArrayList<String> paths;
    private int size;
    private ImageShowManager imageManager;
    private LayoutInflater li;

    public PopRecommend_ImageAdd_Adapter(Activity a, ArrayList<String> paths) {
        this.uiActivity = a;
        this.paths = paths;
        size = paths.size();
        imageManager = ImageShowManager.from(uiActivity);
        li = LayoutInflater.from(uiActivity);
    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return size;
    }

    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        SurfaceHolder surfaceHolder = new SurfaceHolder();
        if (convertView != null) {
            surfaceHolder = (SurfaceHolder) convertView.getTag();
        } else {
            convertView = li.inflate(R.layout.item_gridview_poprecommend, null);
            surfaceHolder.iv = (ImageView) convertView
                    .findViewById(R.id.imageView1);
        }
        convertView.setTag(surfaceHolder);

        String path = paths.get(position);
        // 首先检测是否已经有线程在加载同样的资源(如果则取消较早的),避免出现重复加载
        if (cancelPotentialLoad(path, surfaceHolder.iv)) {
            AsyncLoadImageTask task = new AsyncLoadImageTask(surfaceHolder.iv);
            surfaceHolder.iv.setImageDrawable(new LoadingDrawable(task));
            task.execute(path);
        }
        return convertView;
    }

    static class SurfaceHolder {
        ImageView iv;
    }

    /**
     * 判断当前的imageview是否在加载相同的资源
     *
     * @param url
     * @param imageview
     * @return
     */
    private boolean cancelPotentialLoad(String url, ImageView imageview) {

        AsyncLoadImageTask loadImageTask = getAsyncLoadImageTask(imageview);
        if (loadImageTask != null) {
            String bitmapUrl = loadImageTask.url;
            if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {
                loadImageTask.cancel(true);
            } else {
                // 相同的url已经在加载中.
                return false;
            }
        }
        return true;
    }

    /**
     * 负责加载图片的异步线程
     *
     * @author Administrator
     */
    class AsyncLoadImageTask extends AsyncTask<String, Void, Bitmap> {

        private final WeakReference<ImageView> imageViewReference;
        private String url = null;

        public AsyncLoadImageTask(ImageView imageview) {
            super();
            imageViewReference = new WeakReference<ImageView>(imageview);
        }

        @Override
        protected Bitmap doInBackground(String... params) {
            /**
             * 具体的获取bitmap的部分,流程: 从内存缓冲区获取,如果没有向硬盘缓冲区获取,如果没有从sd卡/网络获取
             */

            Bitmap bitmap = null;
            this.url = params[0];

            // 从内存缓存区域读取
            bitmap = imageManager.getBitmapFromMemory(url);
            if (bitmap != null) {
                Log.d("dqq", "return by 内存");
                return bitmap;
            }
            // 从硬盘缓存区域中读取
            bitmap = imageManager.getBitmapFormDisk(url);
            if (bitmap != null) {
                imageManager.putBitmapToMemery(url, bitmap);
                Log.d("dqq", "return by 硬盘");
                return bitmap;
            }

            // 没有缓存则从原始位置读取
            bitmap = BitmapUtilities.getBitmapThumbnail(url,
                    ImageShowManager.bitmap_width,
                    ImageShowManager.bitmap_height);
            imageManager.putBitmapToMemery(url, bitmap);
            imageManager.putBitmapToDisk(url, bitmap);
            Log.d("dqq", "return by 原始读取");
            return bitmap;
        }

        @Override
        protected void onPostExecute(Bitmap resultBitmap) {
            if (isCancelled()) {
                // 被取消了
                resultBitmap = null;
            }
            if (imageViewReference != null) {
                ImageView imageview = imageViewReference.get();
                AsyncLoadImageTask loadImageTask = getAsyncLoadImageTask(imageview);
                if (this == loadImageTask) {
                    imageview.setImageDrawable(null);
                    imageview.setImageBitmap(resultBitmap);
                }

            }

            super.onPostExecute(resultBitmap);
        }
    }

    /**
     * 根据imageview,获得正在为此imageview异步加载数据的函数
     *
     * @param imageview
     * @return
     */
    private AsyncLoadImageTask getAsyncLoadImageTask(ImageView imageview) {
        if (imageview != null) {
            Drawable drawable = imageview.getDrawable();
            if (drawable instanceof LoadingDrawable) {
                LoadingDrawable loadedDrawable = (LoadingDrawable) drawable;
                return loadedDrawable.getLoadImageTask();
            }
        }
        return null;
    }

    /**
     * 记录imageview对应的加载任务,并且设置默认的drawable
     *
     * @author Administrator
     */
    public static class LoadingDrawable extends ColorDrawable {
        // 引用与drawable相关联的的加载线程
        private final WeakReference<AsyncLoadImageTask> loadImageTaskReference;

        public LoadingDrawable(AsyncLoadImageTask loadImageTask) {
            super(Color.BLUE);
            loadImageTaskReference = new WeakReference<AsyncLoadImageTask>(
                    loadImageTask);
        }

        public AsyncLoadImageTask getLoadImageTask() {
            return loadImageTaskReference.get();
        }
    }
}

ViewHolde文件:从sd卡中读取图片时gridview和listview的优化:

package com.xiyouliwp.fangweixin;

/**
 * Created by lwp940118 on 2016/5/29.
 */

import android.content.Context;
import android.graphics.Bitmap;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

public class ViewHolder {
    private final SparseArray<View> mViews;
    private int mPosition;
    private View mConvertView;

    private ViewHolder(Context context, ViewGroup parent, int layoutId,
                       int position) {
        this.mPosition = position;
        this.mViews = new SparseArray<View>();
        mConvertView = LayoutInflater.from(context).inflate(layoutId, parent,
                false);
        // setTag
        mConvertView.setTag(this);
    }

    /**
     * 拿到一个ViewHolder对象
     */
    public static ViewHolder get(Context context, View convertView,
                                 ViewGroup parent, int layoutId, int position) {
        ViewHolder holder = null;
        if (convertView == null) {
            holder = new ViewHolder(context, parent, layoutId, position);
        } else {
            holder = (ViewHolder) convertView.getTag();
            holder.mPosition = position;
        }
        return holder;
    }

    public View getConvertView() {
        return mConvertView;
    }

    /**
     * 通过控件的Id获取对于的控件,如果没有则加入views
     *
     * @return
     */
    public <T extends View> T getView(int viewId) {
        View view = mViews.get(viewId);
        if (view == null) {
            view = mConvertView.findViewById(viewId);
            mViews.put(viewId, view);
        }
        return (T) view;
    }

    /**
     * 为TextView设置字符串
     *
     * @return
     */
    public ViewHolder setText(int viewId, String text) {
        TextView view = getView(viewId);
        view.setText(text);
        return this;
    }

    /**
     * 为ImageView设置图片
     *
     * @return
     */
    public ViewHolder setImageResource(int viewId, int drawableId) {
        ImageView view = getView(viewId);
        view.setImageResource(drawableId);

        return this;
    }

    /**
     * 为ImageView设置图片
     */
    public ViewHolder setImageBitmap(int viewId, Bitmap bm) {
        ImageView view = getView(viewId);
        view.setImageBitmap(bm);
        return this;
    }

    /**
     * 为ImageView设置图片
     */
    public ViewHolder setImageByUrl(int viewId, String url) {
        ImageLoade.getInstance(3, ImageLoade.Type.LIFO).loadImage(url, (ImageView) getView(viewId));
        return this;
    }

    public int getPosition() {
        return mPosition;
    }

}

push_bottom_in.xml push_bottom_out.xml文件:定义弹出窗口的划入划出方式:

<?xml version="1.0" encoding="utf-8"?>
<!-- 上下滑入式 -->
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="200"
        android:fromYDelta="100%p"
        android:toYDelta="0"
        />
    <alpha
        android:fromAlpha="0.0"
        android:toAlpha="1.0"
        android:duration="200"
        />
</set>
<?xml version="1.0" encoding="utf-8"?>
<!-- 上下滑入式 -->
<set xmlns:android="http://schemas.android.com/apk/res/android" >


    <translate
        android:duration="200"
        android:fromYDelta="0"
        android:toYDelta="50%p" />
    <alpha
        android:fromAlpha="1.0"
        android:toAlpha="0.0"
        android:duration="200"
        />
</set>

mybutton.xml按钮形状设置:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item>
        <shape
            android:shape="rectangle"
            >
            <corners
                android:radius="8dp"/>
            <solid
                android:color="#ffffff"/>
        </shape>
    </item>
    <item
        android:bottom="1dp"
        android:left="1dp"
        android:right="1dp"
        android:top="1dp">
        <shape android:shape="rectangle" >
            <corners android:radius="8dp" />

            <solid android:color="#ddf0ed" />
        </shape>
    </item>

</layer-list>

myedittext.xml 输入框的边框设置

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <!--     <gradient
            android:angle="45"
            android:endColor="#CCCCCC"
            android:startColor="#CCCCCC" /> -->

    <padding
        android:bottom="7dp"
        android:left="7dp"
        android:right="7dp"
        android:top="7dp" />
    <!-- 设置圆角矩形 -->
    <corners android:radius="6dp" />

    <stroke
        android:width="5px"
        android:color="#1199EF" />

    <solid android:color="#CCCCCC" />

</shape>

下面给出demo中使用的布局文件
activity_image_add.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:orientation="horizontal"
        android:background="#ddf0ed">
        <ImageButton
            android:id="@+id/imagebutton_imageadd_back"
            android:layout_width="25dp"
            android:layout_height="25dp"
            android:layout_gravity="center"
            android:layout_marginLeft="15dp"
            android:background="@drawable/share_search_back"
            />
        <TextView
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="iPet选择图片"
            android:gravity="center"
            android:textSize="20dp"/>

        <TextView
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>

        <ImageButton
            android:id="@+id/imagebutton_imageadd_finish"
            android:layout_width="28dp"
            android:layout_height="28dp"
            android:layout_gravity="center"
            android:layout_marginRight="15dp"
            android:background="@drawable/finish"/>

    </LinearLayout>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <GridView
            android:id="@+id/gridview_imageadd"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:cacheColorHint="@android:color/transparent"
            android:clipChildren="true"
            android:gravity="center"
            android:horizontalSpacing="3dip"
            android:listSelector="@android:color/transparent"
            android:numColumns="3"
            android:stretchMode="columnWidth"
            android:verticalSpacing="3dip">

        </GridView>
        <RelativeLayout
            android:id="@+id/id_bottom_ly"
            android:layout_width="match_parent"
            android:layout_height="50dip"
            android:layout_alignParentBottom="true"
            android:background="#e0000000"
            android:clickable="true">

            <TextView
                android:id="@+id/id_choose_dir"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_alignParentLeft="true"
                android:layout_centerVertical="true"
                android:gravity="center_vertical"
                android:paddingLeft="10dip"
                android:text="所有图片"
                android:textColor="@android:color/white" />

            <TextView
                android:id="@+id/id_total_count"
                android:layout_width="50dip"
                android:layout_height="match_parent"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:gravity="center"
                android:text="0张"
                android:textColor="@android:color/white" />
        </RelativeLayout>

    </RelativeLayout>



</LinearLayout>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:id="@+id/linearlayout_pop_recommend"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="20dp" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:background="#ddf0ed"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/textview_recommend_list"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_marginLeft="15dp"
                android:gravity="left|center"
                android:text="动态发布:"
                android:textColor="#fb0b0b0b"
                android:textSize="20dp" />

            <TextView
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1" />

            <ImageButton
                android:id="@+id/imagview_poprecommend_back"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:layout_gravity="center"
                android:layout_marginRight="15dp"
                android:background="@drawable/quxiao" />
        </LinearLayout>

        <EditText
            android:id="@+id/edittext_poprecommend"
            android:layout_width="match_parent"
            android:layout_height="150dp"
            android:background="@drawable/myedittext" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="70dp"
            android:orientation="horizontal">

            <TextView
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1" />

            <LinearLayout
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:layout_gravity="center"
                android:background="#ddf0ed">

                <ImageButton
                    android:id="@+id/iamgebutton_poprecommend_tianjiatupian"
                    android:layout_width="40dp"
                    android:layout_height="40dp"
                    android:layout_gravity="center"
                    android:background="@drawable/tianjiatupian" />

            </LinearLayout>


            <TextView
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="5" />

            <Button
                android:id="@+id/button_poprecommend_fabu"
                android:layout_width="70dp"
                android:layout_height="40dp"
                android:layout_gravity="center"
                android:background="@drawable/mybutton"
                android:text="发布"
                android:textSize="20dp" />

            <TextView
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1" />

        </LinearLayout>


    </LinearLayout>
    <GridView
        android:id="@+id/gridview_poprecommend"
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:cacheColorHint="@android:color/transparent"
        android:clipChildren="true"
        android:gravity="center"
        android:horizontalSpacing="3dip"
        android:listSelector="@android:color/transparent"
        android:numColumns="4"
        android:stretchMode="columnWidth"
        android:verticalSpacing="3dip">

    </GridView>


    <TextView
        android:layout_width="match_parent"
        android:layout_height="20dp"/>


</LinearLayout>

item_gridview_imageadd.xml

<?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="fill_parent" >

    <ImageView
        android:id="@+id/id_item_image"
        android:layout_width="fill_parent"
        android:layout_height="100dp"
        android:background="@drawable/pictures_no"
        android:scaleType="centerCrop" />

    <ImageButton
        android:id="@+id/id_item_select"
        android:clickable="false"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginRight="3dp"
        android:layout_marginTop="3dp"
        android:background="@null"
        android:src="@drawable/pictures_selected" />

</RelativeLayout>

item_gridview_poprecommend.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <RelativeLayout
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_gravity="center"
        android:orientation="vertical" >

        <ImageView
            android:id="@+id/imageView1"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_margin="10dp"
            android:scaleType="centerInside" 
            android:background="@drawable/pictures_no"/>
    </RelativeLayout>

</LinearLayout>

list_dir_item.xml

<?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"
    android:padding="5dp" >

    <ImageView
        android:id="@+id/id_dir_item_image"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:background="@drawable/pic_dir"
        android:paddingBottom="17dp"
        android:paddingLeft="12dp"
        android:paddingRight="12dp"
        android:paddingTop="9dp"
        android:scaleType="fitXY"
        android:src="@drawable/ic_launcher" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="10dp"
        android:layout_toRightOf="@id/id_dir_item_image"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/id_dir_item_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="所有图片"
            android:textSize="10sp" />

        <TextView
            android:id="@+id/id_dir_item_count"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="4723张"
            android:textColor="#444"
            android:textSize="8sp" />
    </LinearLayout>

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="20dp"
        android:src="@drawable/dir_choose" />

</RelativeLayout>

list_dir.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <ListView
        android:id="@+id/listviwe_dir"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:divider="#EEE3D9"
        android:dividerHeight="1px" >
    </ListView>
</LinearLayout>

本demo参考博文有:
http://blog.csdn.net/lmj623565791/article/details/39943731/
还有一些小的问题是从网上百度的 忘记地址了,总之谢谢他们

最后别忘了给整个demo加入权限设置:

<uses-permission android:name="android.permission.CALL_PHONE"></uses-permission>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

仿微信图片选择器

上一篇:微信支付(JSAPI) - Java


下一篇:androidAPP 集成微信支付