Recycle view's checkBox reuse disorder solution

Keywords: Android Java Mobile

Solution to the problem of recycle view reuse disorder

Achieving results

  • Single item selection with checkBox
  • After killing the application in the background, enter the application again to display the options when killing the application in the background

Problem description

  • Because recyclerView adopts the reuse strategy, when refreshing the list downward, the item objects out of view will be reused on the new list, resulting in the confusion of click events.
  • Check box clicking is not mutually exclusive
  • Can't display the options before killing the application

Solutions

1. The recyclerview click event will reuse the confusion. However, the content displayed will not be disordered. You can know that the position will not be disordered.
2. Add a boolean field selected in our data class to record the selected status.
3. Add a click event in the recyclerView to change the selected value, and implement it correctly during initialization
4. Define the mSelectedPos field of int type in activity, which is used to record the mutually exclusive event of checkBox implemented by the position of item in the last clicked

Don't talk too much. Add code and comments

1.activity class description

public class MainActivity extends Activity {

    private List<AppInfo> mAppInfoList = new ArrayList<>();
    private int mSelectedPos = 0;//Define the location of the last clicked item in the field record to realize mutual exclusion
    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;
        }

//Each time you scroll to add a new item, the following functions are polled and executed to initialize the 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());//Mappinfo list is the collection of objects we want to display. AppInfo objects are placed in the collection. AppInfo objects encapsulate the pictures and text information to be displayed. It is important to add a boolean type selected field.
            if (mAppInfoList.get(position).isSelected()) {
                mSelectedPos = position;//This if statement is used in conjunction with our initialization of the data set. It sets the selected field of the appInfo instance of the item before we exit the application to true. When we encounter an item that is true, it is the item that we select before we exit the application. Assign its position to mSelectedPos. when we click the new item, set the checkBox of the original item to 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);//The widget util class is a tool class that encapsulates various methods and fields. This is to get the Editor object and save the packageName value
                    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. Widget util source code of tool class

class WidgetUtil {

//You don't need to know the specific meaning of these fields, just focus on how we realize mutual exclusion
    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
    //The main purpose of this function is to obtain the information of all installed apps in the system, encapsulate the package name, application name, icon and version of the installed app into AppInfo object, and put the AppInfo object into the collection
    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);//Important: set the selected of all objects to false by default, that is to say, the item on the view is not selected by default.
                if (share.getString(PACKAGE_NAME,"a").equals(packageInfo.packageName)){
                    appInfo.setSelected(true);//The key point of the entire if statement is to record the item option you clicked when you quit the application. When you restart the application, reset the item you selected before exiting to the selected state
                }
                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 class analysis


public class AppInfo implements Serializable {

    private String packageName;
    private String appName;
    private String versionName;
    private Drawable icon;
    private int ID;
    private boolean selected;//Pay attention to this field. There is no comment for ordinary Java beans


    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;
    }
}

The role of the whole code

The whole code is to extract all the apps installed in the mobile phone and use recyclerView to display the icon and name of the installed app, and realize single selection.

Posted by BinaryBird on Sat, 30 May 2020 23:01:19 -0700