recyclerView的checkBox複用錯亂問題解決方案
阿新 • • 發佈:2019-01-26
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顯示出所裝應用的圖示和名字,並實現單項選擇。