自定义arrayadapter notifyDataSetChanged导致崩溃

时间:2016-03-04 03:26:08

标签: java android mobile

我有一个自定义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();
}

}

3 个答案:

答案 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.