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显示出所装应用的图标和名字,并实现单项选择。