0

I have a custom ArrayAdapter PlayerAdapter that refers to an ArrayList of Players. I'm trying to add new Players to the ArrayList then update the ListView via notifyDataSetChanged, but it is causing a crash. I think I need to provide some additional overrides to my custom PlayerAdapter, but I don't know what needs to be fixed. I've searched other topics here but everything has been slightly different. I'm sure I'm missing something obvious...

Crash log

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;
    }
}

And lastly the 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();
}

}
Community
  • 1
  • 1
Kevin Lau
  • 1
  • 2

3 Answers3

0
player_data.add(new Player(R.drawable.blue, "Player " + nextPlayerNum, 0));
adapter.add(new Player(R.drawable.blue, "Player " + nextPlayerNum, 0));
adapter.notifyDataSetChanged();

what this means??

you should never add items like this.

instead you can do like,

declare and initialize array list globally.

ArrayList<Player> list = new ArrayList<>();

then after everytime you should add data in array list and just call.

 list.add(PLAYER OBJECT);
 adapter.notifyDataSetChanged()
ErShani
  • 392
  • 2
  • 9
0

comment below line and try once

 adapter.add(new Player(R.drawable.blue, "Player " + nextPlayerNum, 0));

It is not required as you are already adding data in list.

sanky jain
  • 873
  • 1
  • 6
  • 14
  • I went ahead and commented out adapter.add but I am still seeing the crash. I verified that the length of `player_data` and `adapter` are both 5 after calling `player_data.add(new Player(R.drawable.blue, "Player " + nextPlayerNum, 0));`, but once I call `adapter.notifyDataSetChanged()` it crashes – Kevin Lau Mar 04 '16 at 17:06
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.

Kevin Lau
  • 1
  • 2