notifyItemChanged(position) 只适用于第一次
notifyItemChanged(position) only works first time
我在尝试更新我的适配器中的项目时遇到了奇怪的行为。
我先解释一下:
对于这个问题,假设我的 ViewHolder
中的 TextView
是 (FirstText
),然后我将文本更新为 (SecondText
),它完美地工作,它被更改为预期的。
然后我再次将其更改为 (ThirdText
),然后将 returns 更改为 (FirstText
) 而不是预期的 (ThirdText
)。如果我关闭 Activity 并再次打开它,文本是 (ThirdText
)。
换句话说,该项目仅在第二次正确更新。
我希望这是有道理的。这是我的适配器:
public class MainActivityVideoAdapter extends Adapter<RecyclerView.ViewHolder> {
Context context;
View myLayoutView;
ArrayList<PathModel> thumbPathList;
ArrayList<PathModel> videoPathList;
long _id;
class MenuViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView videoName;
CircularImageView videoThumb;
ImageButton viewholderOtions;
MenuViewHolder(View itemView) {
super(itemView);
viewholderOtions = myLayoutView.findViewById(R.id.viewholderOptions);
videoName = myLayoutView.findViewById(R.id.FilePath);
videoThumb = myLayoutView.findViewById(R.id.VideoThumbnail);
itemView.setOnClickListener(this);
viewholderOtions.setOnClickListener(this);
}
//Handling click events
@Override
public void onClick(View v) {
if (v == viewholderOtions) {
int position = (int) v.getTag();
showPopupMenu(viewholderOtions, position);
}
}
}
public MainActivityVideoAdapter(Context context, ArrayList<PathModel> thumbPathList, ArrayList<PathModel> videoPathList) {
this.context = context;
this.thumbPathList = thumbPathList;
this.videoPathList = videoPathList;
}
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
myLayoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.video_list, parent, false);
return new MenuViewHolder(myLayoutView);
}
public void onBindViewHolder(final RecyclerView.ViewHolder myHolder, final int position) {
MenuViewHolder ad = new MenuViewHolder(myLayoutView);
PathModel videoPathModel = this.videoPathList.get(position);
PathModel thumbathModel = this.thumbPathList.get(position);
File file = new File(videoPathModel.getPath());
final String filename = file.getName();
ad.videoName.setText(filename);
ad.videoName.setTypeface(custom_font_desc);
ad.videoThumb.setImageURI(Uri.parse(thumbathModel.getPath()));
ad.viewholderOtions.setTag(position);
}
private void showPopupMenu(final View view, final int position) {
final PopupMenu popup = new PopupMenu(view.getContext(), view);
popup.setGravity(Gravity.END);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.popup_menu, popup.getMenu());
popup.show();
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.rename:
Typeface font = Typeface.createFromAsset(context.getAssets(), "fonts/KelsonSansLight.otf");
final String[] Rename = {"newname.mp4"};
LayoutInflater layoutInflater = LayoutInflater.from(context);
View promptView = layoutInflater.inflate(R.layout.dialoginput, null);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
alertDialogBuilder.setView(promptView);
final String[] nameExtention = new String[1];
final EditText editText = (EditText) promptView.findViewById(R.id.input_text);
final TextView title = (TextView) promptView.findViewById(R.id.title);
title.setTypeface(font);
editText.setTypeface(font);
alertDialogBuilder.setCancelable(false)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Rename[0] = editText.getEditableText().toString();
if (!Rename[0].endsWith(".mp4")) {
Rename[0] = Rename[0] + ".mp4";
}
nameExtention[0] = editText.getEditableText().toString();
if (!Rename[0].equalsIgnoreCase("newname.mp4")) {
String temporary = fileRename(videoPathList.get(position).getPath(), Rename[0]);
String temporary2 = fileRename(videoPathList.get(position).getPath().replace(".mp4", ".jpg"), Rename[0].replace(".mp4", ".jpg"));
if (temporary != null && temporary2 != null) {
SQLiteHelper helper = new SQLiteHelper(context);
PathModel path1 = new PathModel();
path1.setPath(temporary);
PathModel path2 = new PathModel();
path2.setPath(temporary2);
String id_of_thumbpath = helper.getMainThumbID(thumbPathList.get(position).getPath());
videoPathList.set(position, path1);
thumbPathList.set(position, path2);
helper.updateMainThumbPath(temporary2, temporary, id_of_thumbpath);
helper.updateMainVideoPath(videoPathList.get(position).getPath(), id_of_thumbpath);
helper.close();
MainActivityVideoAdapter.this.notifyItemChanged(position);
Toast.makeText(view.getContext(), "Video Renamed", Toast.LENGTH_LONG).show();
}
}
}
})
.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = alertDialogBuilder.create();
alert.show();
return true;
default:
return true;
}
}
});
}
//Rename files
public String fileRename(String _path, String nameChange) {
Log.d("FilePath", _path);
File file = new File(_path);
Log.d("FileName", file.getName());
Log.d("FileDir", file.getParent());
File rename = new File(file.getParent() + "/" + nameChange);
if (file.renameTo(rename))
return rename.getPath();
else
return null;
}
因此,在更新特定项目后,我调用 MainActivityVideoAdapter.this.notifyItemChanged(position);
我在 onBindViewHolder
中放置了一个 Log
,当我调用上面的代码时它会被调用。
我注意到的另一件事是当我在我的片段中调用 ((SimpleItemAnimator)recyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
然后项目变得混乱,这是我的片段:
public class MyFragment extends Fragment {
RecyclerView recyclerView;
private DBManager dbManager;
private long _id;
ArrayList<PathModel> MAINVideoPathList = new ArrayList<>();
ArrayList<PathModel> MAINThumbPathList = new ArrayList<>();
SQLiteHelper sqLiteHelper;
MainActivityVideoAdapter videoAdapter;
View v;
LinearLayoutManager layoutManager;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
v = View.inflate(getContext(),R.layout.fragment_my, null);
sqLiteHelper = new SQLiteHelper(getActivity());
dbManager = new DBManager(getActivity());
dbManager = dbManager.open();
_id = Long.parseLong("1");
this.MAINThumbPathList = this.sqLiteHelper.MAINGetAllThumbPath(String.valueOf(this._id));
this.MAINVideoPathList = this.sqLiteHelper.MAINGetAllVideoPath(String.valueOf(this._id));
recyclerView = (RecyclerView) v.findViewById(R.id.frag2recycler);
txtEmptyAdapter = (TextView) v.findViewById(R.id.txtEmptyAdapter);
txtEmptyAdapter.setTypeface(custom_font_desc);
((SimpleItemAnimator)recyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
videoAdapter = new MainActivityVideoAdapter(getContext(), this.MAINThumbPathList, this.MAINVideoPathList);
layoutManager = new LinearLayoutManager(getActivity());
layoutManager.setStackFromEnd(true);
layoutManager.setReverseLayout(true);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(videoAdapter);
videoAdapter.notifyDataSetChanged();
dbManager.close();
sqLiteHelper.close();
return v;
}
}
}
@Override
public void onResume() {
super.onResume();
MAINThumbPathList.clear();
MAINVideoPathList.clear();
MAINThumbPathList.addAll(sqLiteHelper.MAINGetAllThumbPath(String.valueOf(this._id)));
MAINVideoPathList.addAll(sqLiteHelper.MAINGetAllVideoPath(String.valueOf(this._id)));
videoAdapter = new MainActivityVideoAdapter(getContext(), this.MAINThumbPathList, this.MAINVideoPathList);
videoAdapter.notifyDataSetChanged();
recyclerView.setAdapter(videoAdapter);
sqLiteHelper.close();
if (recyclerView.getAdapter().getItemCount() > 0){
txtEmptyAdapter.setVisibility(View.GONE);
}else {
txtEmptyAdapter.setVisibility(View.VISIBLE);
}
}
我不确定我做错了什么。任何帮助将不胜感激。
我认为还值得一提的是,我尝试删除特定位置的项目,使用以下方法效果很好:
thumbPathList.remove(position);
videoPathList.remove(position);
MainActivityVideoAdapter.this.notifyItemRemoved(position);
MainActivityVideoAdapter.this.notifyItemRangeChanged(position, thumbPathList.size());
MainActivityVideoAdapter.this.notifyItemRangeChanged(position, videoPathList.size());
您似乎没有理解 RecyclerView 的核心 ViewHolder
模式。通过将 mLayoutView
存储在 onCreateViewHolder
中并在 onBindViewHolder
中重用它,您正在使适配器发生灾难。
onCreateViewHolder
仅被调用足够的次数来获得足够的 ViewHolders
来填充您的视口(因此,如果您可以看到 5 个项目,它被调用大约 6-7 次)。
onBindViewHolder
用于在 ViewHolders
中显示数据集中的数据。只要您的视图进入和离开视口,它就会被多次调用(即使您看到 5 个项目,它也会在滚动时无限期地被调用)。您会注意到 ViewHolders
离开视口在此方法中被重新使用并绑定到另一个项目(您可以在此方法中记录文本视图的文本以供学习)。
我的建议是删除 mLayoutView
,并让您的 onBindViewHolder
实际上将数据绑定到函数参数中提供的 ViewHolder
。你不能在那里创建新的 ViewHolders
。
我在尝试更新我的适配器中的项目时遇到了奇怪的行为。
我先解释一下:
对于这个问题,假设我的 ViewHolder
中的 TextView
是 (FirstText
),然后我将文本更新为 (SecondText
),它完美地工作,它被更改为预期的。
然后我再次将其更改为 (ThirdText
),然后将 returns 更改为 (FirstText
) 而不是预期的 (ThirdText
)。如果我关闭 Activity 并再次打开它,文本是 (ThirdText
)。
换句话说,该项目仅在第二次正确更新。
我希望这是有道理的。这是我的适配器:
public class MainActivityVideoAdapter extends Adapter<RecyclerView.ViewHolder> {
Context context;
View myLayoutView;
ArrayList<PathModel> thumbPathList;
ArrayList<PathModel> videoPathList;
long _id;
class MenuViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView videoName;
CircularImageView videoThumb;
ImageButton viewholderOtions;
MenuViewHolder(View itemView) {
super(itemView);
viewholderOtions = myLayoutView.findViewById(R.id.viewholderOptions);
videoName = myLayoutView.findViewById(R.id.FilePath);
videoThumb = myLayoutView.findViewById(R.id.VideoThumbnail);
itemView.setOnClickListener(this);
viewholderOtions.setOnClickListener(this);
}
//Handling click events
@Override
public void onClick(View v) {
if (v == viewholderOtions) {
int position = (int) v.getTag();
showPopupMenu(viewholderOtions, position);
}
}
}
public MainActivityVideoAdapter(Context context, ArrayList<PathModel> thumbPathList, ArrayList<PathModel> videoPathList) {
this.context = context;
this.thumbPathList = thumbPathList;
this.videoPathList = videoPathList;
}
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
myLayoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.video_list, parent, false);
return new MenuViewHolder(myLayoutView);
}
public void onBindViewHolder(final RecyclerView.ViewHolder myHolder, final int position) {
MenuViewHolder ad = new MenuViewHolder(myLayoutView);
PathModel videoPathModel = this.videoPathList.get(position);
PathModel thumbathModel = this.thumbPathList.get(position);
File file = new File(videoPathModel.getPath());
final String filename = file.getName();
ad.videoName.setText(filename);
ad.videoName.setTypeface(custom_font_desc);
ad.videoThumb.setImageURI(Uri.parse(thumbathModel.getPath()));
ad.viewholderOtions.setTag(position);
}
private void showPopupMenu(final View view, final int position) {
final PopupMenu popup = new PopupMenu(view.getContext(), view);
popup.setGravity(Gravity.END);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.popup_menu, popup.getMenu());
popup.show();
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.rename:
Typeface font = Typeface.createFromAsset(context.getAssets(), "fonts/KelsonSansLight.otf");
final String[] Rename = {"newname.mp4"};
LayoutInflater layoutInflater = LayoutInflater.from(context);
View promptView = layoutInflater.inflate(R.layout.dialoginput, null);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
alertDialogBuilder.setView(promptView);
final String[] nameExtention = new String[1];
final EditText editText = (EditText) promptView.findViewById(R.id.input_text);
final TextView title = (TextView) promptView.findViewById(R.id.title);
title.setTypeface(font);
editText.setTypeface(font);
alertDialogBuilder.setCancelable(false)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Rename[0] = editText.getEditableText().toString();
if (!Rename[0].endsWith(".mp4")) {
Rename[0] = Rename[0] + ".mp4";
}
nameExtention[0] = editText.getEditableText().toString();
if (!Rename[0].equalsIgnoreCase("newname.mp4")) {
String temporary = fileRename(videoPathList.get(position).getPath(), Rename[0]);
String temporary2 = fileRename(videoPathList.get(position).getPath().replace(".mp4", ".jpg"), Rename[0].replace(".mp4", ".jpg"));
if (temporary != null && temporary2 != null) {
SQLiteHelper helper = new SQLiteHelper(context);
PathModel path1 = new PathModel();
path1.setPath(temporary);
PathModel path2 = new PathModel();
path2.setPath(temporary2);
String id_of_thumbpath = helper.getMainThumbID(thumbPathList.get(position).getPath());
videoPathList.set(position, path1);
thumbPathList.set(position, path2);
helper.updateMainThumbPath(temporary2, temporary, id_of_thumbpath);
helper.updateMainVideoPath(videoPathList.get(position).getPath(), id_of_thumbpath);
helper.close();
MainActivityVideoAdapter.this.notifyItemChanged(position);
Toast.makeText(view.getContext(), "Video Renamed", Toast.LENGTH_LONG).show();
}
}
}
})
.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = alertDialogBuilder.create();
alert.show();
return true;
default:
return true;
}
}
});
}
//Rename files
public String fileRename(String _path, String nameChange) {
Log.d("FilePath", _path);
File file = new File(_path);
Log.d("FileName", file.getName());
Log.d("FileDir", file.getParent());
File rename = new File(file.getParent() + "/" + nameChange);
if (file.renameTo(rename))
return rename.getPath();
else
return null;
}
因此,在更新特定项目后,我调用 MainActivityVideoAdapter.this.notifyItemChanged(position);
我在 onBindViewHolder
中放置了一个 Log
,当我调用上面的代码时它会被调用。
我注意到的另一件事是当我在我的片段中调用 ((SimpleItemAnimator)recyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
然后项目变得混乱,这是我的片段:
public class MyFragment extends Fragment {
RecyclerView recyclerView;
private DBManager dbManager;
private long _id;
ArrayList<PathModel> MAINVideoPathList = new ArrayList<>();
ArrayList<PathModel> MAINThumbPathList = new ArrayList<>();
SQLiteHelper sqLiteHelper;
MainActivityVideoAdapter videoAdapter;
View v;
LinearLayoutManager layoutManager;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
v = View.inflate(getContext(),R.layout.fragment_my, null);
sqLiteHelper = new SQLiteHelper(getActivity());
dbManager = new DBManager(getActivity());
dbManager = dbManager.open();
_id = Long.parseLong("1");
this.MAINThumbPathList = this.sqLiteHelper.MAINGetAllThumbPath(String.valueOf(this._id));
this.MAINVideoPathList = this.sqLiteHelper.MAINGetAllVideoPath(String.valueOf(this._id));
recyclerView = (RecyclerView) v.findViewById(R.id.frag2recycler);
txtEmptyAdapter = (TextView) v.findViewById(R.id.txtEmptyAdapter);
txtEmptyAdapter.setTypeface(custom_font_desc);
((SimpleItemAnimator)recyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
videoAdapter = new MainActivityVideoAdapter(getContext(), this.MAINThumbPathList, this.MAINVideoPathList);
layoutManager = new LinearLayoutManager(getActivity());
layoutManager.setStackFromEnd(true);
layoutManager.setReverseLayout(true);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(videoAdapter);
videoAdapter.notifyDataSetChanged();
dbManager.close();
sqLiteHelper.close();
return v;
}
}
}
@Override
public void onResume() {
super.onResume();
MAINThumbPathList.clear();
MAINVideoPathList.clear();
MAINThumbPathList.addAll(sqLiteHelper.MAINGetAllThumbPath(String.valueOf(this._id)));
MAINVideoPathList.addAll(sqLiteHelper.MAINGetAllVideoPath(String.valueOf(this._id)));
videoAdapter = new MainActivityVideoAdapter(getContext(), this.MAINThumbPathList, this.MAINVideoPathList);
videoAdapter.notifyDataSetChanged();
recyclerView.setAdapter(videoAdapter);
sqLiteHelper.close();
if (recyclerView.getAdapter().getItemCount() > 0){
txtEmptyAdapter.setVisibility(View.GONE);
}else {
txtEmptyAdapter.setVisibility(View.VISIBLE);
}
}
我不确定我做错了什么。任何帮助将不胜感激。
我认为还值得一提的是,我尝试删除特定位置的项目,使用以下方法效果很好:
thumbPathList.remove(position);
videoPathList.remove(position);
MainActivityVideoAdapter.this.notifyItemRemoved(position);
MainActivityVideoAdapter.this.notifyItemRangeChanged(position, thumbPathList.size());
MainActivityVideoAdapter.this.notifyItemRangeChanged(position, videoPathList.size());
您似乎没有理解 RecyclerView 的核心 ViewHolder
模式。通过将 mLayoutView
存储在 onCreateViewHolder
中并在 onBindViewHolder
中重用它,您正在使适配器发生灾难。
onCreateViewHolder
仅被调用足够的次数来获得足够的 ViewHolders
来填充您的视口(因此,如果您可以看到 5 个项目,它被调用大约 6-7 次)。
onBindViewHolder
用于在 ViewHolders
中显示数据集中的数据。只要您的视图进入和离开视口,它就会被多次调用(即使您看到 5 个项目,它也会在滚动时无限期地被调用)。您会注意到 ViewHolders
离开视口在此方法中被重新使用并绑定到另一个项目(您可以在此方法中记录文本视图的文本以供学习)。
我的建议是删除 mLayoutView
,并让您的 onBindViewHolder
实际上将数据绑定到函数参数中提供的 ViewHolder
。你不能在那里创建新的 ViewHolders
。