1. 程式人生 > >recyclerView的checkBox複用錯亂問題解決方案

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顯示出所裝應用的圖示和名字,並實現單項選擇。