-2
alPlayerRoles.addAll(responseModel.getData().prModel);
playerAdapter = new PlayerDetailsAdapter(PlayerDetailsActivity.this, alPlayerRoles);
lvPlayerRoles.setAdapter(playerAdapter);

This is the code in my main thread that I use to initialize the adapter and set it on a ListView by adding an ArrayList containing an object from a model I've created.

alPlayerRoles is the ArrayList that gets passed as data to the adapter initialization and it has all the correct values. Checked it with the debugger.

Here's the entire Adapter class too:

private Activity activity;
public ArrayList<PlayerRolesModel> playerDetails = new ArrayList<>();
Context context;
private LayoutInflater mInflater;

public PlayerDetailsAdapter(Activity activity, ArrayList<PlayerRolesModel> playerDetails) {
    super(activity, 0, playerDetails);
    this.playerDetails = playerDetails;
    this.activity = activity;
}

@Override
public PlayerRolesModel getItem(int position) {
    return playerDetails.get(position);
}



@Override
public View getView(int position, View convertView, ViewGroup parent) {

    ViewHolder vh;

    if (convertView == null) {
        View view = mInflater.inflate(R.layout.player_details_row, parent, false);
        vh = ViewHolder.create((RelativeLayout) view);
        view.setTag(vh);
    } else {
        vh = (ViewHolder) convertView.getTag();
    }

    PlayerRolesModel item = getItem(position);
    PlayerRolesModelTeam team  = item.prmTeam;

    vh.tvRoleSeason.setText(item.startDate.substring(0,3) + "-" + item.endDate.substring(0,3));
    vh.tvRoleTeam.setText(team.prmTeamName);
    vh.tvRoleContractType.setText(item.Type);
    vh.ivTeamLogoImage.setImageResource(R.drawable.ic_launcher);
    return vh.rootView;
}

private static class ViewHolder {
    public final RelativeLayout rootView;
    public final TextView tvRoleSeason;
    public final TextView tvRoleTeam;
    public final TextView tvRoleContractType;
    public final ImageView ivTeamLogoImage;

    private ViewHolder(RelativeLayout rootView, TextView tvRoleSeason, TextView tvRoleTeam, TextView tvRoleContractType, ImageView ivTeamLogoImage) {
        this.rootView = rootView;
        this.tvRoleSeason = tvRoleSeason;
        this.tvRoleTeam =tvRoleTeam;
        this.tvRoleContractType = tvRoleContractType;
        this.ivTeamLogoImage = ivTeamLogoImage;
    }

    public static ViewHolder create(RelativeLayout rootView) {
        TextView tvRoleSeason = (TextView) rootView.findViewById(R.id.tvRoleSeason);
        TextView tvRoleTeam = (TextView) rootView.findViewById(R.id.tvRoleTeam);
        TextView tvRoleContractType = (TextView) rootView.findViewById(R.id.tvRoleContractType);
        ImageView ivTeamLogoImage = (ImageView) rootView.findViewById(R.id.ivTeamLogoImage);
        return new ViewHolder(rootView, tvRoleSeason, tvRoleTeam, tvRoleContractType, ivTeamLogoImage);
    }
}

I've used the same template many times before for adapters and it always worked, no problem, but this time I'm getting the above-mentioned error. Does that mean that data is somehow passed as an empty ArrayList or something else isn't properly initialized?

EDIT: Stacktrace

FATAL EXCEPTION: main
Process: bahisadam.com.bahisadam, PID: 21210
java.lang.NullPointerException
    at com.bahisadam.view.PlayerDetailsActivity$1.onResponse(PlayerDetailsActivity.java:155)
    at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:68)
    at android.os.Handler.handleCallback(Handler.java:733)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:136)
    at android.app.ActivityThread.main(ActivityThread.java:5124)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:797)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:613)
    at dalvik.system.NativeStart.main(Native Method)
G. Blake Meike
  • 6,615
  • 3
  • 24
  • 40
user1938007
  • 459
  • 1
  • 5
  • 14
  • You should a) add the stacktrace and b) tell exactly in which line you get the error. – SJuan76 Jul 01 '17 at 17:56
  • try in getView `View view = convertView` then if `(view == null) {` then `view = mInflater....` and `view.getTag()` also return `view` – Raghunandan Jul 01 '17 at 18:00
  • I already have all that setup in the getView method – user1938007 Jul 01 '17 at 18:05
  • post the stack trace or use break points to debug to figure out the problem yourself – Raghunandan Jul 01 '17 at 18:07
  • Added the stacktrace. Sorry about poor formatting. – user1938007 Jul 01 '17 at 18:17
  • what is on line 155 `PlayerDetailsActivity.java`? put a break point there and step through to figure out whats wrong. you set `view.setTag(vh)` but not convertView.setTag and you do convertView.getTag . – Raghunandan Jul 01 '17 at 18:18
  • `alPlayerRoles.addAll(responseModel.getData().prModel);` `getData` accesses the `data` field in the JSON, while `prModel` is a model for the nested child `roles` which contains multiple children. – user1938007 Jul 01 '17 at 18:19
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/148133/discussion-between-raghunandan-and-user1938007). – Raghunandan Jul 01 '17 at 18:21
  • There are at least three places here this can cause a NPE. I suggest that you break it up into several lines. Use some variables to see where the NPE occurs. – Code-Apprentice Jul 01 '17 at 18:45
  • See http://stackoverflow.com/questions/23353173/unfortunately-myapp-has-stopped-how-can-i-solve-this for some suggestions about how to debug your app when it crashes. – Code-Apprentice Jul 01 '17 at 18:46

1 Answers1

1

From the chat discussion it seems you have not initialized the list

allPlayerRoles = new ArrrayList<>();

before adding items to it

Apart from that change to

static class ViewHolder {

TextView tvRoleSeason;
TextView tvRoleTeam;
TextView tvRoleContractType;
ImageView ivTeamLogoImage;
}

In getView

ViewHolder vh;
if (convertView == null) {
    convertView = mInflater.inflate(R.layout.player_details_row, parent, false);
    vh = new ViewHolder();
    vh.tvRoleSeason = (TextView) convertView.findViewById(R.id.tvRoleSeason);
    vh.tvRoleTeam = (TextView) convertView.findViewById(R.id.tvRoleTeam);
    vh.tvRoleContractType = (TextView) convertView.findViewById(R.id.tvRoleContractType);
     vh.ivTeamLogoImage = (ImageView) convertView.findViewById(R.id.ivTeamLogoImage); 
    convertView.setTag(vh);
    } else {
    vh = (ViewHolder) convertView.getTag();

    }

    PlayerRolesModel item = getItem(position);
    PlayerRolesModelTeam team = item.prmTeam;

    vh.tvRoleSeason.setText(item.startDate.substring(0,3) + "-" + item.endDate.substring(0,3));
    vh.tvRoleTeam.setText(team.prmTeamName);
    vh.tvRoleContractType.setText(item.Type);
    vh.ivTeamLogoImage.setImageResource(R.drawable.ic_launcher);
    return convertView;
    }

ListView recycles view. if there are 100 of items all 100 items are not kept in memory. Say you have 10 items on screen you will have memory for them When you scroll the row at the top gets recycled and that view is used for the one new row at the below.

So using view holder helps.In fact there is a better explanation of the same here How ListView's recycling mechanism works.

Apart from recyling : Your code might call findViewById() frequently during the scrolling of ListView, which can slow down performance. Even when the Adapter returns an inflated view for recycling, you still need to look up the elements and update them. A way around repeated use of findViewById() is to use the "view holder" design pattern.

So this settag and gettag helps and thus avoiding laggy scrolls.

Tip : Use RecyclerView. Learn to use a debugger. All cause of NullPointerExceptions can be easily found out with the help of breakpoints. You can find out which object is null.

Raghunandan
  • 132,755
  • 26
  • 225
  • 256