我有一份清单。我为列表中的每个项目设置了cardview卡。我已经在向上滑动时实现了删除,但是当我删除最后一个项目(最后一张卡片)时,抛出了一个IndexOutOfBoundsException。 我的代码:
的活动:
public class FirstPage extends Activity
{
RallyRestApi restApi;
private RecyclerView recyclerView;
private CustomAdapter adapter;
private List<MyData> data_list;
private Context mcontext;
String username;
String password;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_first_page);
mcontext=this;
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
data_list = new ArrayList<>();
load_data();
recyclerView.setLayoutManager(new LinearLayoutManager(mcontext,LinearLayoutManager.HORIZONTAL,false));
adapter = new CustomAdapter(FirstPage.this,data_list);
recyclerView.setAdapter(adapter);
username=getIntent().getStringExtra("username");
password=getIntent().getStringExtra("password");
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.UP )
{
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target)
{
Toast.makeText(getApplicationContext(), "on Move", Toast.LENGTH_SHORT).show();
return false;
}
@Override
public void onSwiped(final RecyclerView.ViewHolder viewHolder, int swipeDir)
{
Toast.makeText(getApplicationContext(), "Task Status changed to COMPLETE", Toast.LENGTH_LONG).show();
String username = getIntent().getStringExtra("username");
String password = getIntent().getStringExtra("password");
try
{
restApi=new RallyRestApi(new URI("https://rally1.rallydev.com"),username,password);
JsonObject updatedValues = new JsonObject();
updatedValues.addProperty("State", "Completed");
UpdateRequest taskUpdate = new UpdateRequest(data_list.get(viewHolder.getAdapterPosition()).getRef(), updatedValues);
restApi.update(taskUpdate);
data_list.remove(viewHolder.getAdapterPosition());
adapter.notifyDataSetChanged();
}
catch (URISyntaxException | IOException e)
{
e.printStackTrace();
}
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
itemTouchHelper.attachToRecyclerView(recyclerView);
}
我的Adapter类:
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
private Context context;
private List<MyData> my_data;
FirstPage activity;
RallyRestApi restApi;
public CustomAdapter(FirstPage activity, List<MyData> my_data)
{
this.my_data = my_data;
this.activity=activity;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card,parent,false);
itemView.setMinimumWidth(parent.getMeasuredWidth());
itemView.setMinimumHeight(parent.getMeasuredHeightAndState());
return new ViewHolder(itemView);
}
@Override
public void onBindViewHolder(final ViewHolder holder, final int position)
{
holder.userstory.setText("User Story: "+my_data.get(position).getUserstory());
holder.tasks.setText("Task: "+my_data.get(position).getTask());
holder.seekBar.setMax(my_data.get(position).getEstimate());
holder.seekBar.setProgress(my_data.get(position).getActual());
holder.actual_estimate.setText(my_data.get(position).getActual()+"/"+my_data.get(position).getEstimate());
holder.seekBar.setOnSeekBarChangeListener(new CircularSeekBar.OnCircularSeekBarChangeListener() {
@Override
public void onProgressChanged(CircularSeekBar circularSeekBar, int progress, boolean fromUser)
{
//IOB exception
holder.seekBar.setProgress(holder.seekBar.getProgress());
holder.actual_estimate.setText(holder.seekBar.getProgress()+"/"+my_data.get(position).getEstimate());
}
@Override
public void onStopTrackingTouch(CircularSeekBar seekBar)
{
try
{
restApi=new RallyRestApi(new URI("https://rally1.rallydev.com"),activity.username,activity.password);
JsonObject updatedValues = new JsonObject();
updatedValues.addProperty("Actuals", holder.seekBar.getProgress());
UpdateRequest taskUpdate = new UpdateRequest(my_data.get(position).getRef(), updatedValues);
restApi.update(taskUpdate);
holder.actual_estimate.setText(holder.seekBar.getProgress()+"/"+my_data.get(position).getEstimate());
holder.seekBar.setProgress(holder.seekBar.getProgress());
}
catch (URISyntaxException | IOException e)
{
e.printStackTrace();
}
}
@Override
public void onStartTrackingTouch(CircularSeekBar seekBar)
{
}
});
holder.seekBar.setProgress(holder.seekBar.getProgress());
holder.actual_estimate.setText(holder.seekBar.getProgress()+"/"+my_data.get(position).getEstimate());
}
@Override
public int getItemCount()
{
return my_data.size();
}
public class ViewHolder extends RecyclerView.ViewHolder
{
public TextView userstory,tasks,actual_estimate;
public CircularSeekBar seekBar;
//
public ViewHolder(View itemView)
{
super(itemView);
userstory=(TextView) itemView.findViewById(R.id.tvUserStory);
tasks=(TextView) itemView.findViewById(R.id.tvTask);
seekBar=(CircularSeekBar) itemView.findViewById(R.id.circularSeekBar1);
actual_estimate=(TextView) itemView.findViewById(R.id.tvactuals_estimate);
}
}
}
错误日志:
java.lang.IndexOutOfBoundsException:索引2无效,大小为2 在 java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255) at java.util.ArrayList.get(ArrayList.java:308) 在 com.bmc.apetkar.akshay_rallyrest.CustomAdapter $ 1.onProgressChanged(CustomAdapter.java:68) 在 com.circularseekbar.CircularSeekBar.setProgress(CircularSeekBar.java:530) 在 com.bmc.apetkar.akshay_rallyrest.CustomAdapter $ 1.onProgressChanged(CustomAdapter.java:67) 在 com.circularseekbar.CircularSeekBar.setProgress(CircularSeekBar.java:530) 在 com.bmc.apetkar.akshay_rallyrest.CustomAdapter.onBindViewHolder(CustomAdapter.java:61) 在 com.bmc.apetkar.akshay_rallyrest.CustomAdapter.onBindViewHolder(CustomAdapter.java:32) 在 android.support.v7.widget.RecyclerView $ Adapter.onBindViewHolder(RecyclerView.java:5277) 在 android.support.v7.widget.RecyclerView $ Adapter.bindViewHolder(RecyclerView.java:5310) 在 android.support.v7.widget.RecyclerView $ Recycler.getViewForPosition(RecyclerView.java:4568) 在 android.support.v7.widget.RecyclerView $ Recycler.getViewForPosition(RecyclerView.java:4461) 在 android.support.v7.widget.LinearLayoutManager $ LayoutState.next(LinearLayoutManager.java:1962) 在 android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1371) 在 android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1334) 在 android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:563) 在 android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:2847) 在 android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3145) 在android.view.View.layout(View.java:16630) 在android.view.ViewGroup.layout(ViewGroup.java:5437) 在android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743) 在android.widget.LinearLayout.layoutVertical(LinearLayout.java:1586) 在android.widget.LinearLayout.onLayout(LinearLayout.java:1495) 在android.view.View.layout(View.java:16630) 在android.view.ViewGroup.layout(ViewGroup.java:5437) 在android.widget.FrameLayout.layoutChildren(FrameLayout.java:336) 在android.widget.FrameLayout.onLayout(FrameLayout.java:273) 在android.view.View.layout(View.java:16630) 在android.view.ViewGroup.layout(ViewGroup.java:5437) 在android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743) 在android.widget.LinearLayout.layoutVertical(LinearLayout.java:1586) 在android.widget.LinearLayout.onLayout(LinearLayout.java:1495) 在android.view.View.layout(View.java:16630) 在android.view.ViewGroup.layout(ViewGroup.java:5437) 在android.widget.FrameLayout.layoutChildren(FrameLayout.java:336) 在android.widget.FrameLayout.onLayout(FrameLayout.java:273) 在 com.android.internal.policy.PhoneWindow $ DecorView.onLayout(PhoneWindow.java:2678) 在android.view.View.layout(View.java:16630) 在android.view.ViewGroup.layout(ViewGroup.java:5437) 在android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2171) 在android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1931) 在android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1107) 在 android.view.ViewRootImpl $ TraversalRunnable.run(ViewRootImpl.java:6013) 在 android.view.Choreographer $ CallbackRecord.run(Choreographer.java:858) 在android.view.Choreographer.doCallbacks(Choreographer.java:670) 在android.view.Choreographer.doFrame(Choreographer.java:606) 在 android.view.Choreographer $ FrameDisplayEventReceiver.run(Choreographer.java:844) 在android.os.Handler.handleCallback(Handler.java:739) 在android.os.Handler.dispatchMessage(Handler.java:95) 在android.os.Looper.loop(Looper.java:148) 在android.app.ActivityThread.main(ActivityThread.java:5417) at java.lang.reflect.Method.invoke(Native Method) 在 com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:726) 在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
我知道它可能是IndexOutOfBoundsException的副本,但是我引用它并且不明白我需要更改为position-1
的位置,因为列表从0开始;
答案 0 :(得分:3)
该异常源自my_data.get(position)
侦听器中的onProgressChanged()
。
当进度发生变化时,异步调用此侦听器,但是当您执行onBindViewHolder()时,它会引用提供的原始position
。
因此,当您在时间X执行onBindViewHolder()时,值为2的位置有效(如果列表中至少有3个条目)。听众将保持这个值2并坚持下去。
现在,如果删除项目并且只剩下2个项目,则position = 2不再有效,但是侦听器仍然保留该值,并且在调用它时,它会尝试访问位置= 2的my_data,现在已经变得无效。
要解决此问题,您必须使侦听器保持实际数据,而不是位置。你可以这样做:
public void onBindViewHolder(final ViewHolder holder, final int position)
{
final SomeClass data = my_data.get(position);
holder.seekBar.setOnSeekBarChangeListener(new CircularSeekBar.OnCircularSeekBarChangeListener() {
@Override
public void onProgressChanged(CircularSeekBar circularSeekBar, int progress, boolean fromUser)
{
holder.seekBar.setProgress(holder.seekBar.getProgress());
holder.actual_estimate.setText(holder.seekBar.getProgress()+"/" + data.getEstimate());
}
答案 1 :(得分:0)
在删除项目之前,您可以检查列表是否已空。
if(!data_list.isEmpty()){
data_list.remove(viewHolder.getAdapterPosition());
adapter.notifyDataSetChanged();
}