Android之相册实现

本文主要记录一些零碎的东西

使用recycleeView实现一个相册,相册里面的编辑可以参考这篇,主要是扫描系统相册,然后展示出来



主要是使用 getLoaderManager().initLoader 查询数据库,其实遍历文件也是可以的,不过偷懒啦,而且提供的查询是异步的

看看list界面

/**
 * 相册列表
 * Create by slack on 2016/09/06 15:58
 */
public class AlbumListActivity extends BaseFullScreenActivity {

    private RecyclerView mRecyclerView;
    private Boolean isVideo;
    private TextView textView;

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

        initView();
        initData();

    }

    private void initData() {

        if(getIntent() != null ){
            isVideo =  getIntent().getBooleanExtra("video",false);
        }

        mHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                if(msg.what == REQ_SACN_ALBUM_LIST){
                    mRecyclerView.setVisibility(View.VISIBLE);
                    mRecyclerView.setAdapter(
                            new AlbumListAdapter(mRecyclerView,albumImageList,itemClickListener));
                    // 进入第一个 相册详情界面
                    /***
                     * 发现会有一个假死的现象,从相册返回后整个界面无法点击
                     * so 来个延时
                     */
                    mHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            // 点击视频首打开视频,点击照片首打开照片
                            for (int i = 0; i < albumImageList.size(); i++) {
                                AlbumImage a = albumImageList.get(i);
                                if(isVideo && a.imagePath.startsWith("v")){
                                    enterAlbumView(i);
                                    break;
                                }else if(!isVideo && a.imagePath.startsWith("i")){
                                    enterAlbumView(i);
                                    break;
                                }
                            }

                        }
                    }, 100);

                }
            }
        };

        // 虽然使用了 getLoaderManager ,结果操作在主线程里跑
        initAlbumImages(mHandler);

    }


    private void initView() {
        mRecyclerView = (RecyclerView) findViewById(R.id.album_list);

        textView = (TextView) findViewById(R.id.album_scanning);
        textView.setVisibility(View.VISIBLE);

        ((TextView)findViewById(R.id.top_center)).setText(getString(R.string.album_choose));
        ((ImageView)findViewById(R.id.top_left)).setImageResource(R.drawable.home_red);
        findViewById(R.id.top_left).setOnClickListener(this);
        ((ImageView)findViewById(R.id.top_right)).setImageResource(R.drawable.home_red);
        findViewById(R.id.top_right).setOnClickListener(this);

        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        mRecyclerView.setVisibility(View.GONE);
    }

    AlbumListAdapter.ItemClickListener itemClickListener = new AlbumListAdapter.ItemClickListener() {
        @Override
        public void onItemClick(int pos) {
            if(pos >= 0 && pos < albumImageList.size()){
                enterAlbumView(pos);
            }
        }
    };

    private void enterAlbumView(int position){
        textView.setVisibility(View.GONE);
        List childList = mGruopMap.get(albumImageList.get(position).folderName);
//        if(childList.get(0).endsWith("gif")){
//            startNewActivity(PhotoSelectActivity.class,false);
//        }else
        {
            Intent mIntent = new Intent(AlbumListActivity.this, AlbumImagesActivity.class);
            mIntent.putStringArrayListExtra("list", (ArrayList) childList);
            startActivity(mIntent);
        }
    }

主要是 base里的查询

public abstract class BaseFullScreenActivity 
{

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

    }

   

    protected final int REQ_SACN_ALBUM_LIST = 0x01;
    // 一个文件夹,下面好多文件  父目录名 : 子文件list(文件路径)
    protected Map> mGruopMap = new HashMap<>();
    private final long imagesSize = 1024 * 50; // 图片size > 50KB = ( 1024 * 50 )
    protected List albumImageList = new ArrayList<>();
    private String[] prefix = {"i","v"};// images  video

    // 查询条件 大小50kb以上
    public void initAlbumImages(final Handler handler){

        mGruopMap.clear();

        final String[] imagesColums = new String[]{
                MediaStore.Images.Media.DATA,
                MediaStore.Images.Media.SIZE,
                MediaStore.Images.Media.DATE_MODIFIED
        };
        getLoaderManager().initLoader(DEFAULT_QUERY_LOADER_ID, null, new LoaderManager.LoaderCallbacks() {
            @Override
            public Loader onCreateLoader(int id, Bundle args) {
                return new CursorLoader(BaseFullScreenActivity.this,
                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imagesColums,
//                        MediaStore.Images.Media.MIME_TYPE + "=? or "
//                        + MediaStore.Images.Media.MIME_TYPE + "=?",
//                        new String[] { "image/jpeg", "image/png" },
                        // error  单位是什么 B    图片size > 50KB = ( 1024 * 50 )
                        MediaStore.Images.Media.SIZE + "> ? and "
                        + MediaStore.Images.Media.MIME_TYPE + "!= ? ",
                        // 不扫描 gif
                        new String[] { String.valueOf(imagesSize) , "image/gif"},
//                        null,null,
                        MediaStore.Images.Media.DATE_MODIFIED + " DESC");
            }

            @Override
            public void onLoadFinished(Loader loader, Cursor data) {
                if (data != null && !data.isClosed() && data.getCount() > 0) {
                    D.i("slack","count: " + data.getCount());
                    while (data.moveToNext()) {
                        String path = prefix[0] + data.getString(data.getColumnIndex(MediaStore.Images.Media.DATA));
                        //获取该图片的父路径名
                        File file = new File(path);
                        String parentName = file.getParentFile().getName();

//                        long size = data.getLong(data.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE));
//                        D.i("slack", "pic: " + path + ", " + parentName + ", " +
////                        file.getTotalSpace() + ", " + file.getUsableSpace() + ", " + file.getFreeSpace() +
//                        size);

                        //根据父路径名将图片放入到mGruopMap中
                        if (mGruopMap.containsKey(parentName)) {
                            mGruopMap.get(parentName).add(path);
                        } else {
                            List chileList = new ArrayList();
                            chileList.add(path);
                            mGruopMap.put(parentName, chileList);
                        }

                    }
                    // 通知完成扫描 TODO
                    data.close();
                    getLoaderManager().destroyLoader(DEFAULT_QUERY_LOADER_ID);
                    initAlbumVideos(handler);
//                    // 没有图片? 不会有这情况吧
//                    formatGroupImages(mGruopMap);
//                    handler.sendEmptyMessage(REQ_SACN_ALBUM_LIST);
                } else {
                    D.i("slack", "pic no data");
                    getLoaderManager().destroyLoader(DEFAULT_QUERY_LOADER_ID);
                    initAlbumVideos(handler);
                }

            }

            @Override
            public void onLoaderReset(Loader loader) {
            }
        });


    }


    public void initAlbumVideos(final Handler handler){

        final String[] mediaColumns = new String[]{
                MediaStore.Video.Media.DATA,
                MediaStore.Video.Media._ID
        };
        getLoaderManager().initLoader(DEFAULT_QUERY_LOADER_ID, null, new LoaderManager.LoaderCallbacks() {

            @Override
            public Loader onCreateLoader(int id, Bundle args) {

                return new CursorLoader(BaseFullScreenActivity.this,
                        MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
                        mediaColumns,
                        null, null, MediaStore.Video.Media.DATE_MODIFIED + " DESC");
            }

            @Override
            public void onLoadFinished(Loader loader, Cursor data) {
                if (data != null && !data.isClosed() && data.getCount() > 0) {
                    D.i("slack","video count: " + data.getCount());
                    while (data.moveToNext()) {
                        String path = prefix[1] + data.getString(data.getColumnIndex(MediaStore.Video.Media.DATA));
                        String parentName = new File(path).getParentFile().getName();

                        // video 和 images 不会在同一个文件夹下吧,会存在的
                        if (mGruopMap.containsKey(parentName)) {
                            mGruopMap.get(parentName).add(path);
                        } else {
                            List chileList = new ArrayList<>();
                            chileList.add(path);
                            mGruopMap.put(parentName, chileList);
                        }

                    }

                    data.close();
                    // 没有图片? 不会有这情况吧
                    formatGroupImages(mGruopMap);
                    handler.sendEmptyMessage(REQ_SACN_ALBUM_LIST);

                } else {
                    D.i("slack", "Video no data");
                }
                getLoaderManager().destroyLoader(DEFAULT_QUERY_LOADER_ID);
            }

            @Override
            public void onLoaderReset(Loader loader) {
            }
        });
    }

    // 因为扫描手机的时候将图片信息放在HashMap中
    // 所以需要遍历HashMap将数据组装成List
    private List  formatGroupImages(Map> map) {
        if(map.size() == 0){
            return null;
        }
        albumImageList.clear();

        Iterator>> it = map.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry> entry = it.next();
            AlbumImage mAlbumImage = new AlbumImage();
            String key = entry.getKey();
            List value = entry.getValue();

            mAlbumImage.folderName = key;
            mAlbumImage.imageCount = value.size();
            mAlbumImage.imagePath = value.get(0);//获取该组的第一张图片

            albumImageList.add(mAlbumImage);
        }
        D.i("slack", "pic list " + albumImageList.size() );
        return albumImageList;
    }

}

查询时使用map集合存储,扫了图片和视频,图片视频使用v,i 前缀区分

布局就一个RecycleView




    

    

    


看看 list 那个adapter

/**
 * 

Description: 相册 列表

* Created by slack on 2016/9/7 10:54 . */ public class AlbumImagesAdapter extends BaseAdapter { private List imagesList; private ItemClickListener mClickListener; public AlbumImagesAdapter(@NonNull RecyclerView recyclerView,List list,ItemClickListener itemClickListener) { super(recyclerView.getContext()); this.imagesList = list; this.mClickListener = itemClickListener; } @Override public AlbumImagesHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new AlbumImagesHolder(mLayoutInflater.inflate(R.layout.item_album_images,parent,false)); } @Override public void onBindViewHolder(AlbumImagesHolder holder, int position) { holder.bindView(position); } @Override public int getItemCount() { return imagesList.size(); } class AlbumImagesHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ private ImageView photoView; public AlbumImagesHolder(View itemView) { super(itemView); photoView = (ImageView) itemView.findViewById(R.id.album_item_img); ViewGroup.LayoutParams lp = photoView.getLayoutParams(); lp.height = lp.width = (WT.mScreenWidth - 100) / 4 ;// 每个图片 屏幕的 1/4 (减去padding) photoView.setLayoutParams(lp); } public void bindView(int position){ String path = imagesList.get(position); if(path.startsWith("v")){ MediaMetadataRetriever mmr = new MediaMetadataRetriever(); mmr.setDataSource(mContext, Uri.fromFile(new File(path.substring(1)))); photoView.setImageBitmap(mmr.getFrameAtTime()); }else{ WTUtils.showAlbumImage(photoView,path.substring(1)); } itemView.setOnClickListener(this); } @Override public void onClick(View v) { D.i("slack","click :" + getAdapterPosition()); // 进入相册详情界面 if(mClickListener != null){ mClickListener.onItemClick(getAdapterPosition()); } } } }

recycleview的item布局




    

    
        

        

    

    




base里面

public abstract class BaseAdapter extends RecyclerView.Adapter
{

    protected Context mContext;
    protected LayoutInflater mLayoutInflater;
    protected OnItemClickListener mItemClickListener = null;


    public BaseAdapter(@NonNull Context context)
    {
        mContext = context;
        mLayoutInflater = LayoutInflater.from(context);
    }

    public void setItemClickListener(OnItemClickListener listener)
    {
        mItemClickListener = listener;
    }

    public interface OnItemClickListener
    {
        void onItemClicked(Adapter adapter, VH holder);
    }

    public interface ItemClickListener{
        void onItemClick(int pos);
    }


    /*
    * 从Assets中读取图片
    */
    public Bitmap getImageFromAssetsFile(String path,String fileFullName)
    {
        Bitmap image = null;
        AssetManager am = mContext.getResources().getAssets();
        try {
//            InputStream is = am.open( path + File.separator + fileName + ".png");
            InputStream is = am.open( path + File.separator + fileFullName);
            image = BitmapFactory.decodeStream(is);
            is.close();
        }
        catch (IOException e) {
            e.printStackTrace();
        }

        return image;

    }

}

然后是点击进入的详情,也是只有一个recycleView布局

/**
 * 展示相册图片
 * Create by slack on 2016/09/07 10:40
 */
public class AlbumImagesActivity extends BaseFullScreenActivity {

    private List imagesList;
    private RecyclerView mRecyclerView;

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

        initData();
        initView();
    }

    private void initView() {

        mRecyclerView = (RecyclerView) findViewById(R.id.album_images);

        ((TextView)findViewById(R.id.top_center)).setText(new File(imagesList.get(0)).getParentFile().getName());

        findViewById(R.id.top_left).setOnClickListener(this);
        ((ImageView)findViewById(R.id.top_right)).setImageResource(R.drawable.home_red);
        findViewById(R.id.top_right).setOnClickListener(this);

        mRecyclerView.setLayoutManager(new GridLayoutManager(this,4));
        mRecyclerView.setAdapter(new AlbumImagesAdapter(mRecyclerView,imagesList,itemClickListener));

    }

    AlbumListAdapter.ItemClickListener itemClickListener = new AlbumListAdapter.ItemClickListener() {
        @Override
        public void onItemClick(int pos) {
            if(pos >= 0 && pos < imagesList.size()){
                D.i("slack","pos:" + pos);
                String path = imagesList.get(pos);
                if(path.startsWith("v")){
                    if (WTRenderer.mProcessVideoCtrl.prepare(new File(path.substring(1)))) {
                        startNewActivity(EditVideoActivity.class, false);
                    }
                }else {
                    Bitmap bitmap = ImageUtils.getCorrectBitmap(path.substring(1));
                    if (WTRenderer.mPictureCtrl.processPicture(bitmap)) {
                        startNewActivity(EditPhotoActivity.class, false);
                    }
                }
            }
        }
    };

    private void initData() {
        if(getIntent() != null ){
            imagesList =  getIntent().getStringArrayListExtra("list");
            if(imagesList.size() == 0){
                finish();
            }
        }

    }

adapter

/**
 * 

Description: 相册 列表

* Created by slack on 2016/9/7 10:54 . */ public class AlbumImagesAdapter extends BaseAdapter { private List imagesList; private ItemClickListener mClickListener; public AlbumImagesAdapter(@NonNull RecyclerView recyclerView,List list,ItemClickListener itemClickListener) { super(recyclerView.getContext()); this.imagesList = list; this.mClickListener = itemClickListener; } @Override public AlbumImagesHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new AlbumImagesHolder(mLayoutInflater.inflate(R.layout.item_album_images,parent,false)); } @Override public void onBindViewHolder(AlbumImagesHolder holder, int position) { holder.bindView(position); } @Override public int getItemCount() { return imagesList.size(); } class AlbumImagesHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ private ImageView photoView; public AlbumImagesHolder(View itemView) { super(itemView); photoView = (ImageView) itemView.findViewById(R.id.album_item_img); ViewGroup.LayoutParams lp = photoView.getLayoutParams(); lp.height = lp.width = (WT.mScreenWidth - 100) / 4 ;// 每个图片 屏幕的 1/4 (减去padding) photoView.setLayoutParams(lp); } public void bindView(int position){ String path = imagesList.get(position); if(path.startsWith("v")){ MediaMetadataRetriever mmr = new MediaMetadataRetriever(); mmr.setDataSource(mContext, Uri.fromFile(new File(path.substring(1)))); photoView.setImageBitmap(mmr.getFrameAtTime()); }else{ WTUtils.showAlbumImage(photoView,path.substring(1)); } itemView.setOnClickListener(this); } @Override public void onClick(View v) { D.i("slack","click :" + getAdapterPosition()); // 进入相册详情界面 if(mClickListener != null){ mClickListener.onItemClick(getAdapterPosition()); } } } }

recycleview的item布局,就一个imageView


这样就完成啦,代码都贴出来了

- - - - update - - - 

太傻太傻,发现视频加载时缓慢,是我自己处理了视频图片,还没有做缓存,可以使用lrucache做缓存

// 手机内存的 1/10
        LruCache lruCache = new LruCache<>( ((int)(Runtime.getRuntime().maxMemory() / 1024 )) / 10 );

由于使用了ImageLoader,就支持视频的缩略图,把adapter里bindview的判断是否是视频哪里注释了就好

https://github.com/nostra13/Android-Universal-Image-Loader

private static DisplayImageOptions fileOptions = new DisplayImageOptions.Builder()
            .showImageOnLoading(R.drawable.loading) // 设置图片下载期间显示的图片
            .showImageForEmptyUri(R.drawable.wutaicon) // 设置图片Uri为空或是错误的时候显示的图片
            .showImageOnFail(R.drawable.wutaicon) // 设置图片加载或解码过程中发生错误显示的图片
            .cacheInMemory(true) // 设置下载的图片是否缓存在内存中
//            .cacheOnDisk(true) // 设置下载的图片是否缓存在SD卡中
//            .displayer(new RoundedBitmapDisplayer(20)) // 设置成圆角图片
            .build(); // 构建完成


    public static void showAlbumImage(ImageView imageView,String path){
        mImageLoader.displayImage("file://" + path ,imageView,fileOptions);
    }




你可能感兴趣的:(android,studio)