recyclerView的checkBox复用错乱问题解决方案

recyclerView复用错乱问题解决方案

实现效果

  • 用checkBox实现单项选择
  • 当后台杀掉应用后,重新进入应用显示你后台杀掉应用时的选项

问题描述

  • 由于recyclerView采用复用的策略,在向下刷新列表时候,移出视野的item对象会被复用到新的列表上导致点击事件错乱。
  • checkBox点击之间不互斥
  • 显示不出来杀掉应用前的选项

解决思路

1.recyclerView点击事件会复用错乱。但是显示的内容不会错乱,可以知道position是不会错乱的。
2.在我们的数据类中增加一个boolean的字段selected用来记录选中状态。
3.在recyclerView中添加点击事件来改变selected的值,在初始化的时候正确的实现
4.在activity中定义int类型的mSelectedPos字段,用来记录上一个被点中的item的position实现checkBox的互斥事件

废话不多说啦,上代码,会加注释的(>.<

1.activity类描述

public class MainActivity extends Activity {

    private List<AppInfo> mAppInfoList = new ArrayList<>();
    private int mSelectedPos = 0;//定义字段记录上一个点击的item位置,实现互斥
    private ListAdapter mAdapter;
    private RecyclerView mRecyclerView;
    private Handler mHandler = new Handler();

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

        mAdapter = new ListAdapter();
        mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        mRecyclerView.setAdapter(mAdapter);

        initData();

    }


    class ListAdapter extends RecyclerView.Adapter<ListAdapter.MyViewHolder> {

        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            MyViewHolder holder = new MyViewHolder(LayoutInflater.from(
                    MainActivity.this).inflate(R.layout.item_home, parent,
                    false));
            return holder;
        }

//每次滚动添加新的item时候都会轮询执行下面的函数进行item的初始化
        @Override
        public void onBindViewHolder(final MyViewHolder holder, final int position) {
            holder.textView.setText(mAppInfoList.get(position).getAppName());
            holder.imageView.setImageDrawable(mAppInfoList.get(position).getIcon());
            holder.checkBox.setChecked(mAppInfoList.get(position).isSelected());//mAppInfoList就是我们要显示的对象集合,集合里面放的是AppInfo对象,AppInfo对象封装了要显示的图片和文字信息。重要的是加了一个布尔类型的selected字段。
            if (mAppInfoList.get(position).isSelected()) {
                mSelectedPos = position;//这个if语句配合着我们初始化数据集合使用,把我们退出应用前的item的appInfo实例的selected的字段设为true,当我们在碰到为true的item就是我们退出应用前选择的item,把它的position赋值给mSelectedPos.完成点击新的item时把原先的item的checkBox置为false。
            }
            holder.checkBox.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mAppInfoList.get(mSelectedPos).setSelected(false);
                    //setting up a new Item checkout state
                    mSelectedPos = position;
                    mAppInfoList.get(mSelectedPos).setSelected(true);
                    notifyDataSetChanged();
                    SharedPreferences.Editor editor = WidgetUtil.getEditor(MainActivity.this);//WidgetUtil类是一个工具类,里封装了各种方法和字段。这句话是获得Editor对象,并把packageName值存进去
                    editor.putString(WidgetUtil.PACKAGE_NAME, mAppInfoList.get(position).getPackageName());
                    editor.putInt("radioId", position);
                    editor.commit();
                    Intent intent = new Intent();
                    intent.setAction(WidgetUtil.BINGING_ICON_ACTION);
                    sendBroadcast(intent);
                }
            });
        }

        @Override
        public int getItemCount() {
            return mAppInfoList.size();
        }

        class MyViewHolder extends RecyclerView.ViewHolder {
            TextView textView;
            ImageView imageView;
            CheckBox checkBox;

            public MyViewHolder(View view) {
                super(view);
                textView = (TextView) view.findViewById(R.id.id_num);
                imageView = (ImageView) view.findViewById(R.id.id_image);
                checkBox = (CheckBox) view.findViewById(R.id.id_check_box);
            }
        }

    }

    public ListAdapter getAdapter() {
        if (mAdapter == null) {
            return null;
        } else {
            return mAdapter;
        }
    }


    public void initData() {
        final Runnable mUpdateResults = new Runnable() {
            public void run() {
                mAdapter.notifyDataSetChanged();
            }
        };
        new Thread(new Runnable() {
            @Override
            public void run() {
                mAppInfoList = WidgetUtil.getAppsInfoList(MainActivity.this);
                mHandler.post(mUpdateResults);
            }
        }).start();
    }

}

2.工具类WidgetUtil源代码

class WidgetUtil {

//这些字段不必知道具体含义,只要关注我们怎么实现互斥的就可以啦
    public static final String WIDGET_BUTTON_ACTION = "cn.byd.Widget_Button_Click";
    public static final String BINGING_ICON_ACTION = "com.byd.intent.action.BINGING_ICON";
    public static final String PACKAGE_ADDED_ACTION = "android.intent.action.PACKAGE_ADDED";
    public static final String PACKAGE_REMOVED_ACTION = "android.intent.action.PACKAGE_REMOVED";
    public static final String WIDGET_OPEN_APP_INFO = "widget_open_app_info";
    public static final String PACKAGE_NAME = "packageName";
    public static final String PACKAGE = "package";
    public static final String WIDGET_APP_NAME = "com.android.firstapp";

    //Get the package name of the system installed for all applications,
    // and return to the list of all the package names
    //这个函数主要目的是获得系统的所有安装app的信息,并把安装的app的包名、应用名字、图标、版本封装成AppInfo对象,并把AppInfo对象放入到集合中
    public static List<AppInfo> getAppsInfoList(Context context) {
        List<PackageInfo> packages = context.getPackageManager().getInstalledPackages(0);
        List<AppInfo> allAppInfo = new ArrayList<>();
        SharedPreferences share = context.getSharedPreferences(WIDGET_OPEN_APP_INFO, context.MODE_PRIVATE);
        Intent intent = new Intent(Intent.ACTION_MAIN, null);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        for (int i = 0; i < packages.size(); i++) {
            AppInfo appInfo = new AppInfo();
            PackageInfo packageInfo = packages.get(i);
            //If non - system applications are used, add to "allAppInfo
            if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                appInfo.setPackageName(packageInfo.packageName);
                appInfo.setAppName(packageInfo.applicationInfo.loadLabel(context.getPackageManager()).toString());
                appInfo.setVersionName(packageInfo.versionName);
                appInfo.setIcon(packageInfo.applicationInfo.loadIcon(context.getPackageManager()));
                appInfo.setSelected(false);//重点:默认把所有对象的selected设为false也就是说视图上的item默认是没有被选中。
                if (share.getString(PACKAGE_NAME,"a").equals(packageInfo.packageName)){
                    appInfo.setSelected(true);//重点整个if语句是为了记录你在退出应用时候点击的item选项,在重新启动应用时候把你退出前选择的item重现设置为被选中状态
                }
                allAppInfo.add(appInfo);//If non - system applications are used, add to "allAppInfo"
            }

        }
        return allAppInfo;
    }



    //Getting editor
    public static SharedPreferences.Editor getEditor(Context context) {
        SharedPreferences sharedPreferences = context.getSharedPreferences(WIDGET_OPEN_APP_INFO, context.MODE_PRIVATE);
        SharedPreferences.Editor mEditor = sharedPreferences.edit();
        return mEditor;
    }


}

3.AppInfo类分析



public class AppInfo implements Serializable {

    private String packageName;
    private String appName;
    private String versionName;
    private Drawable icon;
    private int ID;
    private boolean selected;//关注下这个字段,其他就是普通的java bean没有什么好注释的啦


    public int getID() {
        return ID;
    }

    public String getPackageName() {
        return packageName;
    }

    public String getAppName() {
        return appName;
    }

    public String getVersionName() {
        return versionName;
    }

    public Drawable getIcon() {
        return icon;
    }

    public boolean isSelected() {
        return selected;
    }

    public void setID(int ID) {
        this.ID = ID;
    }

    public void setPackageName(String packageName) {
        this.packageName = packageName;
    }

    public void setAppName(String appName) {
        this.appName = appName;
    }

    public void setVersionName(String versionName) {
        this.versionName = versionName;
    }

    public void setIcon(Drawable icon) {
        this.icon = icon;
    }

    public void setSelected(boolean selected) {
        this.selected = selected;
    }
}

整个代码的作用

整个代码是把手机中装的app全部提取出来用recyclerView显示出所装应用的图标和名字,并实现单项选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值