仿微信图片选择器

Posted 小小葡萄干

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了仿微信图片选择器相关的知识,希望对你有一定的参考价值。

仿微信图片选择器

源码下载连接:

先上图,后上代码:

打开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, Bit

以上是关于仿微信图片选择器的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin 实现仿微信图片选择器(增删(长按无拖动))+RecyclerView+BaseQuickAdapter(官网github)的功能

Kotlin 实现仿微信图片选择器(增删(长按无拖动))+RecyclerView+BaseQuickAdapter(官网github)的功能

android 仿微信图片选择器

Android 超高仿微信图片选择器 图片该这么载入

Android高仿微信图片选择上传工具

Android高仿微信图片选择上传工具