请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

关于图片选择器Adapter无法正常运行的问题

老师好,我跟着老师的代码写遇到了图片选择Adapter无法显示的问题,Android 8.0,已经申请动态权限。

图片描述
图片描述

GalleyView

package ink.techat.client.common.widget;

import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.AttributeSet;
import android.view.View;
import android.widget.CheckBox;
import android.widget.ImageView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import androidx.loader.app.LoaderManager;
import androidx.loader.content.CursorLoader;
import androidx.loader.content.Loader;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;

import java.io.File;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

import ink.techat.client.common.R;
import ink.techat.client.common.widget.recycler.RecycierAdapter;

/**
 * GalleyView.java
 */
public class GalleyView extends RecyclerView {

    /**
     * final int LOADER_ID            LoaderID
     * List<Image> mSelectedImages    图片类列表
     * Adapter mAdapter               老子的Adapter
     * SelectChangeListener mLisener  用于回调的图片选择器更改监听器
     * LoaderCallback mLoaderCallback Loader回调方法 用于图片加载
     * final int MAX_IMAGE_COUNT      最大图片选中数量
     * final int MIN_IMAGE_FILE_SIZE  上传图片大小限定
     */
    private static final int LOADER_ID = 0x0100;
    private List<Image> mSelectedImages = new LinkedList<>();
    private Adapter mAdapter = new Adapter();
    private SelectedChangeListener mLisener;
    private LoaderCallback mLoaderCallback = new LoaderCallback();
    private static final int MAX_IMAGE_COUNT = 3;
    private static final int MIN_IMAGE_FILE_SIZE = 10*1024;

    public GalleyView(Context context) {
        super(context);
        init();
    }

    public GalleyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public GalleyView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        setLayoutManager(new GridLayoutManager(getContext(), 4));
        setAdapter(mAdapter);
        mAdapter.setmListener(new RecycierAdapter.AdapterListerImpl<Image>() {
            @SuppressWarnings("unchecked")
            @Override
            public void onItemClick(RecycierAdapter.ViewHolder holder, Image image) {
                // Cell点击操作,如果点击运行,则跟新对应Cell的状态
                // 然后更新界面,如果不允许点击(如以达到最大选中数量),则不刷新界面
                if (onItemSelectClick(image)){
                    holder.updataData(image);
                }
            }
        });
    }

    /**
     * setup(LoaderManager loaderManager)
     * 初始化方法
     * @param loaderManager Loader管理器
     * @return 任何一个LOADER_ID,用于销毁Loader
     */
    public int setup(LoaderManager loaderManager, SelectedChangeListener lisener){
        mLisener = lisener;
        loaderManager.initLoader(LOADER_ID, null, mLoaderCallback);
        return LOADER_ID;
    }

    /**
     * onItemSelectClick(Image image)
     * Cell点击的具体逻辑
     *
     * @param image Image
     * @return True or False,进行了数据更改或没更改,更改了则刷新
     */
    private boolean onItemSelectClick(Image image){
        // 是否需要进行刷新
        boolean notifyRefresh;
        if(mSelectedImages.contains(image)){
            // 如存在,则移除
            mSelectedImages.remove(image);
            image.isSelect = false;
            // 通知更新
            notifyRefresh = true;
        }else {
            if (mSelectedImages.size() >= MAX_IMAGE_COUNT){
                // Toast
                notifyRefresh = false;
            }else{
                mSelectedImages.add(image);
                image.isSelect = true;
                notifyRefresh = true;
            }
        }
        // 如数据有改变,则需通知外边的监听器数据选中改变了
        if (notifyRefresh) {
            notifySelectChanged();
        }
        return true;
    }

    /**
     * getSelectedPath()
     * 得到选中的图片的全部地址
     * @return paths 数组
     */
    public String[] getSelectedPath(){
        String[] paths = new String[mSelectedImages.size()];
        int index = 0;
        for (Image image : mSelectedImages) {
            paths[index++] = image.path;
        }
        return paths;
    }

    /**
     * clear()
     * 用于清空选中的图片
     */
    public void clear(){
        // 一定一定要先重置状态再通知更新
        for (Image image : mSelectedImages) {
            image.isSelect = false;
        }
        mSelectedImages.clear();
        mAdapter.notifyDataSetChanged();
    }

    /**
     * GalleyView 的内部类 class Image
     * 内部的数据结构
     */
    private static class Image {
        int id;             // 数据Id
        String path;        // 图片路就
        long date;          // 图片创建时间
        boolean isSelect;   // 图片是否选中

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            Image image = (Image) o;
            return path != null ? Objects.equals(path, image.path) : image.path == null;
        }

        @Override
        public int hashCode() {
            return Objects.hash(path);
        }
    }

    /**
     * notifySelectChanged()
     * 通知选中状态改变
     */
    private void notifySelectChanged(){
        // 得到监听者并且判断是否有监听,然后进行回调数量变化
        SelectedChangeListener listener = mLisener;
        if (listener != null){
            listener.onSelectedCountChanged(mSelectedImages.size());
        }
    }

    /**
     * 用于通知Adapter数据更改
     * @param images 新的图片数据
     */
    private void updateSource(List<Image> images){
        mAdapter.replace(images);
    }

    /**
     * GalleyView的子类 class LoaderCallback
     * 用于图片选择器内置正方形控件(Cell)的图片加载
     */
    private class LoaderCallback implements LoaderManager.LoaderCallbacks<Cursor>{
        private final String[] IMAGE_PROJECTION = new String[]{
                MediaStore.Images.Media._ID,        // ID
                MediaStore.Images.Media.DATA,       // 图片Url
                MediaStore.Images.Media.DATE_ADDED  // 图片创建时间
        };

        @NonNull
        @Override
        public Loader<Cursor> onCreateLoader(int id, @Nullable Bundle args) {
            // 创建一个Loader
            if (id == LOADER_ID){
                // 如果ID相同则进行初始化
                return new CursorLoader(getContext(),
                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                        IMAGE_PROJECTION,
                        null,
                        null,
                        IMAGE_PROJECTION[2] + " DESC");  // 倒叙查询 DESC前有应该空格!!!
            }
            return null;
        }

        @Override
        public void onLoadFinished(@NonNull Loader<Cursor> loader, Cursor data) {
            // 当Loader加载完成时调用
            List<Image> images = new ArrayList<>();
            if (data != null){
                int count = data.getCount();
                if (count > 0){
                    // 移动游标到Start
                    data.moveToFirst();

                    // 得到对应列的Index坐标
                    int indexId = data.getColumnIndexOrThrow(IMAGE_PROJECTION[0]);
                    int indexPath = data.getColumnIndexOrThrow(IMAGE_PROJECTION[1]);
                    int indexDate = data.getColumnIndexOrThrow(IMAGE_PROJECTION[2]);
                    do {
                        // 循环读取直到没有下一条数据
                        int id = data.getInt(indexId);
                        String path = data.getString(indexPath);
                        long dateTime = data.getLong(indexDate);

                        File file = new File(path);
                        if (!file.exists() || file.length() < MIN_IMAGE_FILE_SIZE){
                            // 如果没有图片或图片大小不符合规范则跳过
                            continue;
                        }

                        // 添加一条新的数据
                        Image image = new Image();
                        image.id = id;
                        image.path = path;
                        image.date = dateTime;
                        images.add(image);
                    }while (data.moveToNext());
                }
            }
            // 通知刷新
            updateSource(images);
        }

        @Override
        public void onLoaderReset(@NonNull Loader<Cursor> loader) {
            // 当Loader销毁或重置时调用 直接清空刷新
            updateSource(null);
        }
    }

    /**
     * Adapter适配器
     */
    private class Adapter extends RecycierAdapter<Image> {

        @Override
        protected int getItemViewType(int position, Image image) {
            return R.layout.cell_galley;
        }

        @Override
        protected ViewHolder<Image> onCreateiewHolder(View root, int viewType) {
            return new GalleyView.ViewHolder(root);
        }
    }

    /**
     * Cell 对应的Holder
     */
    private class ViewHolder extends RecycierAdapter.ViewHolder<Image> {
        private ImageView mPic;
        private View mShade;
        private CheckBox mSelected;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            mPic = (ImageView) itemView.findViewById(R.id.img_image);
            mShade = itemView.findViewById(R.id.view_shade);
            mSelected = (CheckBox) itemView.findViewById(R.id.cb_select);
        }

        @Override
        protected void onBind(Image image) {
            Glide.with(getContext())
                    .load(image.path)                           // 加载路径
                    .diskCacheStrategy(DiskCacheStrategy.NONE)  // 直接使用原图加载,不进行缓存
                    .centerCrop()                               // 居中剪切
                    .placeholder(R.color.grey_200)              // 默认图片(颜色)
                    .into(mPic);
            // 设置阴影显示和选中状态
            mShade.setVisibility(image.isSelect ? VISIBLE : INVISIBLE);
            mSelected.setChecked(image.isSelect);
        }
    }

    /**
     * 对外监听器
     */
    public interface SelectedChangeListener{
        /**
         * 用于通知选中更改的监听器接口
         * @param count Count
         */
        void onSelectedCountChanged(int count);
    }
}

ActivityFragment

package ink.techat.client.push.fragments.main;


import android.os.Bundle;


import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import butterknife.BindView;
import ink.techat.client.common.app.Fragment;
import ink.techat.client.common.widget.GalleyView;
import ink.techat.client.push.R;

/**
 * @author NickCharlie
 */
public class ActiveFragment extends Fragment {
    @BindView(R.id.galleyView)
    GalleyView mGalley;


    @Override
    protected int getContentLayoutId() {
        return R.layout.fragment_active;
    }

    @Override
    protected void initData() {
        super.initData();
        Log.i("TEST_mGalley",mGalley == null ? "yes":"no");
        mGalley.setup(getLoaderManager(), new GalleyView.SelectedChangeListener() {
            @Override
            public void onSelectedCountChanged(int count) {

            }
        });
    }
}

正在回答

6回答

抱歉,这阵子太忙了,才看见消息。

请问是否已全部解决了么?我看你不断的在新增你的解决方案,可以看出的确是挺棒的,可以自己找到问题。的确这里出问题一般来说都是你说的这些问题导致的。

一般我建议调试,看一下运行流程,这样会更加方便定位问题。

1 回复 有任何疑惑可以回复我~
  • 提问者 NickCharlie #1
    老师正好给了我一段时间自己解决问题哈哈哈,问题已经全部解决!
    回复 有任何疑惑可以回复我~ 2020-02-19 13:13:39
  • Qiujuer 回复 提问者 NickCharlie #2
    不错哈~
    回复 有任何疑惑可以回复我~ 2020-02-20 00:08:40
提问者 NickCharlie 2020-02-17 20:34:47

问题已解决,GalleyView里的ViewHolder ---> onBind方法没有运行是因为父类Rec...ViewAdapter中的onBind没有被自动调用,在bind里调用一下就解决了,基类粗心了

0 回复 有任何疑惑可以回复我~
提问者 NickCharlie 2020-02-17 15:53:57

GalleyView里的ViewHolder ---> onBind方法没有运行

0 回复 有任何疑惑可以回复我~
提问者 NickCharlie 2020-02-17 12:53:36

解决了一个问题了,RecycierAdapter 的 onCreateViewHolder 我返回了个null 应该返回holder,但是还是显示不出图片,只有方格子,之前的那个找不到class的报错不影响什么

0 回复 有任何疑惑可以回复我~
提问者 NickCharlie 2020-02-15 21:07:05

https://github.com/Caoblocks/AndroidAppTest

0 回复 有任何疑惑可以回复我~
提问者 NickCharlie 2020-02-15 19:26:27

补充 fragment_active

https://img1.sycdn.imooc.com//szimg/5e47d5350957916008400358.jpg

cell_galley.xml

https://img1.sycdn.imooc.com//szimg/5e47d560095bb2a712400871.jpg

0 回复 有任何疑惑可以回复我~
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信