我有一个自定义ArrayAdapter
PlayerAdapter,引用了ArrayList
个玩家。我正在尝试向ArrayList
添加新玩家,然后通过ListView
更新notifyDataSetChanged
,但这会导致崩溃。我想我需要为我的自定义PlayerAdapter提供一些额外的覆盖,但我不知道需要修复什么。我搜索了其他主题here,但一切都略有不同。我确定我错过了一些明显的东西......
崩溃日志
03-04 09:43:50.836 3016-3016/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.laudev.android.crossoff, PID: 3016
java.lang.IndexOutOfBoundsException: Invalid index 4, size is 4
at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
at java.util.ArrayList.get(ArrayList.java:308)
at com.laudev.android.crossoff.PlayerAdapter.getView(PlayerAdapter.java:53)
at android.widget.AbsListView.obtainView(AbsListView.java:2347)
at android.widget.ListView.makeAndAddView(ListView.java:1864)
at android.widget.ListView.fillDown(ListView.java:698)
at android.widget.ListView.fillSpecific(ListView.java:1356)
at android.widget.ListView.layoutChildren(ListView.java:1651)
at android.widget.AbsListView.onLayout(AbsListView.java:2151)
at android.view.View.layout(View.java:15671)
at android.view.ViewGroup.layout(ViewGroup.java:5038)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1466)
at android.view.View.layout(View.java:15671)
at android.view.ViewGroup.layout(ViewGroup.java:5038)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)
at android.widget.FrameLayout.onLayout(FrameLayout.java:514)
at android.view.View.layout(View.java:15671)
at android.view.ViewGroup.layout(ViewGroup.java:5038)
at android.support.v7.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:435)
at android.view.View.layout(View.java:15671)
at android.view.ViewGroup.layout(ViewGroup.java:5038)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)
at android.widget.FrameLayout.onLayout(FrameLayout.java:514)
at android.view.View.layout(View.java:15671)
at android.view.ViewGroup.layout(ViewGroup.java:5038)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1466)
at android.view.View.layout(View.java:15671)
at android.view.ViewGroup.layout(ViewGroup.java:5038)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)
at android.widget.FrameLayout.onLayout(FrameLayout.java:514)
at android.view.View.layout(View.java:15671)
at android.view.ViewGroup.layout(ViewGroup.java:5038)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2086)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1843)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1061)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5885)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
at android.view.Choreographer.doCallbacks(Choreographer.java:580)
at android.view.Choreographer.doFrame(Choreographer.java:550)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
PlayerAdapter.java
public class PlayerAdapter extends ArrayAdapter<Player> {
Context context;
int layoutResourceId;
ArrayList<Player> data;
public PlayerAdapter(Context context, int layoutResourceId, ArrayList<Player> data) {
super(context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.context = context;
this.data = new ArrayList<Player>(data);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
PlayerHolder holder = null;
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new PlayerHolder();
holder.imgIcon = (ImageView)row.findViewById(R.id.imgIcon);
holder.txtName = (TextView)row.findViewById(R.id.txtName);
holder.txtScore = (TextView)row.findViewById(R.id.txtScore);
row.setTag(holder);
}
else
{
holder = (PlayerHolder)row.getTag();
}
Player player = data.get(position);
holder.txtName.setText(player.name);
holder.imgIcon.setImageResource(player.icon);
holder.txtScore.setText("" + player.score);
return row;
}
static class PlayerHolder
{
ImageView imgIcon;
TextView txtName;
TextView txtScore;
}
}
Player.java
public class Player {
public int icon;
public String name;
public int score;
public Player(){
super();
}
public Player(int icon, String name, int score) {
super();
this.icon = icon;
this.name = name;
this.score = score;
}
}
最后是MainActivity.java
public class MainActivity extends AppCompatActivity {
private PlayerAdapter adapter;
private ListView listViewPlayers;
private List<Player> player_data;
// Called when activity is first created
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initialize view with 4 players
player_data = new ArrayList<Player>();
for (int i = 1; i < 5; i++) {
player_data.add(new Player(R.drawable.red, "Player " + i, 0));
}
// Set adapter with the four players above
adapter = new PlayerAdapter(this,
R.layout.simplerow, (ArrayList<Player>) player_data);
// Hook up ListView with adapter
listViewPlayers = (ListView)findViewById(R.id.playerList);
listViewPlayers.setAdapter(adapter);
}
// press button to add a new player to ListView
public void addPlayer (View v) {
int nextPlayerNum = player_data.size() + 1;
player_data.add(new Player(R.drawable.blue, "Player " + nextPlayerNum, 0));
// EDIT: commenting out this line since not necessary. Still seeing crash.
// adapter.add(new Player(R.drawable.blue, "Player " + nextPlayerNum, 0));
adapter.notifyDataSetChanged();
}
}
答案 0 :(得分:0)
player_data.add(new Player(R.drawable.blue, "Player " + nextPlayerNum, 0));
adapter.add(new Player(R.drawable.blue, "Player " + nextPlayerNum, 0));
adapter.notifyDataSetChanged();
这意味着什么?
你永远不应该添加这样的项目。
相反,你可以这样做,
全局声明并初始化数组列表。
ArrayList<Player> list = new ArrayList<>();
然后每次你应该在数组列表中添加数据然后调用。
list.add(PLAYER OBJECT);
adapter.notifyDataSetChanged()
答案 1 :(得分:0)
在下面注释并尝试一次
adapter.add(new Player(R.drawable.blue, "Player " + nextPlayerNum, 0));
这不是必需的,因为您已经在列表中添加数据。
答案 2 :(得分:0)
It seems like answering your own question is frowned upon here...but I'll do it anyway. The problem was in the constructor for PlayerAdapter.java
. The line
this.data = new ArrayList<Player>(data);
should be replaced with
this.data = data;
so that the new ArrayAdapter and the global list in MainActivity.java
are referring to the same object. Thanks to everyone for helping me get here...I used the debugger and found that there was an out of bounds exception, then found that there were two different ArrayList
in play.