Android 尝试从RecyclerView中删除项时,RecyclerView正在计算布局或滚动时无法调用此方法
我正试图从recyclerview中删除我的项目,但我总是遇到错误 java.lang.IllegalStateException:无法在 RecyclerView正在计算布局或滚动 我正在使用notify datasetchanged,我可以解决此问题吗Android 尝试从RecyclerView中删除项时,RecyclerView正在计算布局或滚动时无法调用此方法,android,android-recyclerview,Android,Android Recyclerview,我正试图从recyclerview中删除我的项目,但我总是遇到错误 java.lang.IllegalStateException:无法在 RecyclerView正在计算布局或滚动 我正在使用notify datasetchanged,我可以解决此问题吗 public class AdapterIntransit extends RecyclerView.Adapter<AdapterIntransit.ViewHolder> { private Context conte
public class AdapterIntransit extends RecyclerView.Adapter<AdapterIntransit.ViewHolder> {
private Context context;
List<DataIntransit> data;
public AdapterIntransit(Context context, List<DataIntransit> data) {
this.context = context;
this.data = data;
}
@Override
public AdapterIntransit.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.cardintransit, parent, false);
return new ViewHolder(itemView);
}
@Override
public void onBindViewHolder(AdapterIntransit.ViewHolder holder, int position) {
if (data.get(position).getJml1() - data.get(position).getJml2() <= 0) {
data.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, getItemCount());
notifyDataSetChanged();
} else {
holder.kode.setText(data.get(position).getKode());
holder.nama.setText(data.get(position).getNama());
holder.jumlah.setText(String.valueOf(data.get(position).getJml1() - data.get(position).getJml2()));
}
}
@Override
public int getItemCount() {
return data.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
TextView kode, nama, jumlah;
public ViewHolder(View itemView) {
super(itemView);
kode = (TextView)itemView.findViewById(R.id.kode);
nama = (TextView)itemView.findViewById(R.id.nama);
jumlah = (TextView)itemView.findViewById(R.id.jumlah);
}
}
}
公共类适配器Transit扩展了RecyclerView.Adapter{
私人语境;
列出数据;
公共交通适配器(上下文、列表数据){
this.context=上下文;
这个数据=数据;
}
@凌驾
public AdapterTransit.ViewHolder onCreateViewHolder(视图组父级,int-viewType){
View itemView=LayoutInflater.from(parent.getContext()).inflate(R.layout.cardintransit,parent,false);
返回新的ViewHolder(itemView);
}
@凌驾
BindViewHolder上的公共无效(AdapterTransit.ViewHolder,内部位置){
如果(data.get(position).getJml1()-data.get(position).getJml2()我给你另一个解决问题的方法。我认为它会更好
我们的想法是,我们不会删除onBindViewHolder
中的无效数据,我们会在之前删除它
public AdapterIntransit(Context context, List < DataIntransit > data) {
this.context = context;
this.data = removeInValidData(data);
}
private void removeInValidData(List < DataIntransit > data) {
for (int position = 0, position < data.size(); position++) {
if (data.get(position).getJml1() - data.get(position).getJml2() <= 0) {
data.remove(position);
}
}
}
@Override
public void onBindViewHolder(AdapterIntransit.ViewHolder holder, int position) {
holder.kode.setText(data.get(position).getKode());
holder.nama.setText(data.get(position).getNama());
holder.jumlah.setText(String.valueOf(data.get(position).getJml1() - data.get(position).getJml2()));
}
公共适配器传输(上下文,列表data){
this.context=上下文;
this.data=removeInValidData(数据);
}
私有void removeInValidData(列表数据){
对于(int position=0,position下面的答案对我有用
这只是问题的解决方法
这通常发生在您在后台线程
上调用notifyDataSetChanged()
时。因此只需将notify移动到UI线程
dialeecyclerView.post(new Runnable()
{
@Override
public void run() {
myadapter.notifyDataSetChanged();
}
});
您使用您的RecyclerView
实例,并在post方法中向消息队列添加一个新的Runnable。Runnable将在用户界面线程上运行。这是Android从后台访问UI
线程的限制(例如,在将在后台线程中运行的方法中)。
如需了解更多信息,请在UI
线程上运行它
如果需要,您可以在UI
线程上运行它
runOnUiThread(new Runnable(){
public void run() {
// UI code goes here
}
});
当在recyclerview中单击顶部复选框时选中所有复选框时,这非常有用
recyclerview.post(new Runnable()
{
@Override
public void run() {
myadapter.notifyDataSetChanged();
}
});
当您的项目处于构建过程中时,您正在onBindViewHolder()
方法中通知项目更改。很可能您可以改进逻辑以避免此情况。如果您正在通知recylew项目,则使用isComputingLayout方法:
if (!mRecyclerView.isComputingLayout())
{
// add your code here
}
您需要两种方法来实现此功能:
if (!rv.isComputingLayout && rv.scrollState == SCROLL_STATE_IDLE) {
rv.adapter?.notifyDataSetChanged()
}
我只是像贝娄那样推迟了
new Handler().postDelayed(() -> notifyDataSetChanged(), 1000);
当recycler视图正在计算布局时,如果我们试图通知项目更改或数据更改,则会发生此问题。但根据官方文档,它被写为
当布局遍历发生或RecyclerView开始滚动以响应系统事件(触摸、可访问性等)时,代码不太可能在框架调用的状态(isComputingLayout)期间运行。
但有时这个问题会导致崩溃。所以,最好按照下面的说明进行操作
if (isComputingLayout(recyclerView).not()) {
if (Looper.myLooper() != Looper.getMainLooper()) {
// If BG thread,then post task to recycler view
recyclerView?.post { notifyItemChanged(position, obj) }
} else {
notifyItemChanged(position, obj)
}
}
您能解释一下为什么需要删除onBindViewHolder
中的项目吗?我想您可以简单地说,不要将它添加到您的RecyclerView@PhanVanLinh,我想是因为,我可以从onBindViewHolder
访问位置,谢谢您的回答,但我不能从那里访问位置。只需没有为什么代码可以解决这个问题的想法不是很有帮助。请解释你的解决方案背后的想法。@Janusz谢谢。更新了答案。我过去认为,如果人们已经阅读了问题+检查日志+检查我的答案,人们会得到这个答案的想法。这个解决方案只有在你想在项目建设时过滤数据时才有效Adapter这似乎是RecyclerView库中的一个错误,当快速连续(50毫秒内)调用notifyDataSetChanged()
或在滚动时调用它时,即使在onBindViewHolder()
之外调用它。例如,使用notifyDataSetChanged()刷新整个列表时会发生此错误
,不一定要添加或删除项。Runnable
建议效果很好。这里有一个错误报告:一般来说,为UI做一些依赖于时间的事情是个坏主意。这会起作用,但它是一个闩锁,而不是一个解决方案。原因之一可能是您的视图保持架中有一个可以动画的视图。可能是这样的一个开关,在你切换之后,你调用了notify…
@Sermilion:是的,我有一个开关&切换它,我做一些操作&然后通知。上面的解决方案对它有效吗?@AndroidGuy这会有效,但这不是正确的方法。如果你有一个开关,并且你手动切换它,不要通知。开关将启动动画它自己的,您就完成了。如果您想通过编程更改开关的状态,那么您需要通知,并且开关在通知后会更改。如果它正在计算布局,那么来自代码的请求将永远无法完成?处理程序不是最佳解决方案