0

I can't figure out why I am getting a NullPointerException with my custom BaseAdapter with different row types. I am using the ViewHolder pattern and when I get this NPE, the ViewHolder is null. But looking at my code below, wouldn't there always be a reference to a ViewHolder?

Using getItemViewType should always return a valid row layout, and I cover all of these types in the first switch statement which handles the inflating of the rows.

This line is the issues that is giving me the problem:

case TYPE_TEXT_YOU: if (message != null) holder.message.setText(message);

It is weird because it was working fine before. I didn't change much but now it is giving me this issue. Please help!!!

public class ChatAdapter extends BaseAdapter {

private static final int TYPE_TEXT_YOU = 0;
private static final int TYPE_AUDIO_YOU = 1;
private static final int TYPE_TEXT_THEM = 2;
private static final int TYPE_AUDIO_THEM = 3;
private static final int TYPE_MATCH_NOTICE = 4;
private static final int TYPE_EMPTY_ROW = 5;

private Context mContext;
private List<ChatMessage> mMessages;
private String mPartnerUserId;
private SharedPrefs mPrefs;
private DatabaseHelper mDb;
private User mUser;
private User mPartnerUser;
private AudioHelper mAudioHelper;

public ChatAdapter(Context context, List<ChatMessage> messages, String partnerUserId) {
    mContext = context;
    mMessages = messages;
    mPartnerUserId = partnerUserId;
    mPrefs = new SharedPrefs(context);
    mAudioHelper = AudioHelper.getInstance(context, partnerUserId);
    mDb = DatabaseHelper.getInstance(context);
    mUser = mDb.getUser(mPrefs.getUserId());
    mPartnerUser = mDb.getUser(partnerUserId);
}

@Override
public int getCount() {
    return mMessages.size();
}

@Override
public Object getItem(int position) {
    return mMessages.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public int getItemViewType(int position) {
    ChatMessage message = mMessages.get(position);

    switch (message.getMessageType()) {
        case ChatMessage.TYPE_GAME_DATE:
            return TYPE_MATCH_NOTICE;

        case ChatMessage.TYPE_TEXT:
            if (message.getSenderUserId().equals(mPrefs.getUserId())) {
                return TYPE_TEXT_YOU;
            }
            else {
                return TYPE_TEXT_THEM;
            }

        case ChatMessage.TYPE_AUDIO:
            if (message.getSenderUserId().equals(mPrefs.getUserId())) {
                return TYPE_AUDIO_YOU;
            }
            else {
                return TYPE_AUDIO_THEM;
            }

        default:
            return TYPE_EMPTY_ROW;
    }
}

@Override
public int getViewTypeCount() {
    return 6;
}

public class ViewHolder {
    private ImageView avatar;
    private CustomTextView timestamp;
    private CustomTextView message;
    private CustomTextView date;
    private CustomTextView time;
    private LinearLayout btnPlayAudio;
    private ImageView ivPlayAudio;
    private ProgressBar spinPlayingAudio;
    private CustomTextView tvPlayAudio;
    private ImageView gameCover;
    private ProgressBar spinGameCover;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    int type = getItemViewType(position);

    if (convertView == null) {
        holder = new ViewHolder();
        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context
                .LAYOUT_INFLATER_SERVICE);

        switch (type) {
            case TYPE_TEXT_YOU:
                convertView = inflater.inflate(R.layout.row_chat_you, parent, false);
                holder.avatar = (ImageView) convertView.findViewById(R.id.avatar_you);
                holder.message = (CustomTextView) convertView.findViewById(R.id.message_you);
                holder.timestamp = (CustomTextView) convertView.findViewById(R.id.timestamp_you);
                break;

            case TYPE_AUDIO_YOU:
                convertView = inflater.inflate(R.layout.row_chat_audio_you, parent, false);
                holder.avatar = (ImageView) convertView.findViewById(R.id.avatar_you);
                holder.timestamp = (CustomTextView) convertView.findViewById(R.id.timestamp_you);
                holder.btnPlayAudio = (LinearLayout) convertView.findViewById(R.id.btn_play_audio_you);
                holder.ivPlayAudio = (ImageView) convertView.findViewById(R.id.iv_play_audio);
                holder.spinPlayingAudio = (ProgressBar) convertView.findViewById(R.id.spin_playing_audio);
                holder.tvPlayAudio = (CustomTextView) convertView.findViewById(R.id.tv_play_audio);
                break;

            case TYPE_TEXT_THEM:
                convertView = inflater.inflate(R.layout.row_chat_them, parent, false);
                holder.avatar = (ImageView) convertView.findViewById(R.id.avatar_them);
                holder.message = (CustomTextView) convertView.findViewById(R.id.message_them);
                holder.timestamp = (CustomTextView) convertView.findViewById(R.id.timestamp_them);
                break;

            case TYPE_AUDIO_THEM:
                convertView = inflater.inflate(R.layout.row_chat_audio_them, parent, false);
                holder.avatar = (ImageView) convertView.findViewById(R.id.avatar_them);
                holder.timestamp = (CustomTextView) convertView.findViewById(R.id.timestamp_them);
                holder.btnPlayAudio = (LinearLayout) convertView.findViewById(R.id.btn_play_audio_them);
                holder.ivPlayAudio = (ImageView) convertView.findViewById(R.id.iv_play_audio);
                holder.spinPlayingAudio = (ProgressBar) convertView.findViewById(R.id.spin_playing_audio);
                holder.tvPlayAudio = (CustomTextView) convertView.findViewById(R.id.tv_play_audio);
                break;

            case TYPE_MATCH_NOTICE:
                convertView = inflater.inflate(R.layout.row_chat_match_notice, parent, false);
                holder.gameCover = (ImageView) convertView.findViewById(R.id.game_cover);
                holder.spinGameCover = (ProgressBar) convertView.findViewById(R.id.spin_game_cover);
                holder.date = (CustomTextView) convertView.findViewById(R.id.date);
                holder.time = (CustomTextView) convertView.findViewById(R.id.time);
                break;

            case TYPE_EMPTY_ROW:
                convertView = inflater.inflate(R.layout.row_padding_10dp, parent, false);
                break;
        }
        convertView.setTag(holder);
    }
    else holder = (ViewHolder) convertView.getTag();

    String message = mMessages.get(position).getMessage();
    String timestamp = mMessages.get(position).getTimeStamp();
    final String audioFilepath = mMessages.get(position).getFilepath();
    DateTime dateTime;
    DateTimeFormatter formatter = DateTimeFormat.forPattern(GlobalVars.FORMAT_MESSAGE_TIMESTAMP);

    final ViewHolder finalHolder = holder;

    switch (type) {
        case TYPE_TEXT_YOU:
            if (message != null) holder.message.setText(message);

            if (timestamp != null && !timestamp.isEmpty()) {
                try {
                    dateTime = ISODateTimeFormat.dateTime().parseDateTime(timestamp);
                    if (dateTime != null) holder.timestamp.setText(formatter.print(dateTime));
                }
                catch (IllegalArgumentException e) { e.printStackTrace(); }
            }

            if (mUser != null && mUser.getAvatarType() != null && !mUser.getAvatarType().isEmpty()) {
                try {
                    holder.avatar.setImageDrawable(mContext.getResources().getDrawable(ViewHelper
                            .getAvatarHeadDrawableId(mContext, mUser.getAvatarType())));
                }
                catch (Resources.NotFoundException e) { e.printStackTrace(); }
            }
            break;

        case TYPE_AUDIO_YOU:
            if (timestamp != null && !timestamp.isEmpty()) {
                try {
                    dateTime = ISODateTimeFormat.dateTime().parseDateTime(timestamp);
                    if (dateTime != null) holder.timestamp.setText(formatter.print(dateTime));
                }
                catch (IllegalArgumentException e) { e.printStackTrace(); }
            }

            if (mUser != null && mUser.getAvatarType() != null && !mUser.getAvatarType().isEmpty()) {
                try {
                    holder.avatar.setImageDrawable(mContext.getResources().getDrawable(ViewHelper
                            .getAvatarHeadDrawableId(mContext, mUser.getAvatarType())));
                }
                catch (Resources.NotFoundException e) { e.printStackTrace(); }
            }

            holder.btnPlayAudio.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (audioFilepath != null && !audioFilepath.isEmpty()) {
                        mAudioHelper.changeViewsOfStoppedAudioMessage();
                        mAudioHelper.setPlayingAudioViews(finalHolder.ivPlayAudio,
                                finalHolder.spinPlayingAudio, finalHolder.tvPlayAudio);
                        mAudioHelper.playAudio(audioFilepath);
                    }
                }
            });
            break;

        case TYPE_TEXT_THEM:
            if (message != null) holder.message.setText(message);

            if (timestamp != null && !timestamp.isEmpty()) {
                try {
                    dateTime = ISODateTimeFormat.dateTime().parseDateTime(timestamp);
                    if (dateTime != null) holder.timestamp.setText(formatter.print(dateTime));
                }
                catch (IllegalArgumentException e) { e.printStackTrace(); }
            }

            if (mPartnerUser != null && mPartnerUser.getAvatarType() != null) {
                try {
                    holder.avatar.setImageDrawable(mContext.getResources().getDrawable(ViewHelper
                            .getAvatarHeadDrawableId(mContext, mPartnerUser.getAvatarType())));
                }
                catch (Resources.NotFoundException e) { e.printStackTrace(); }
            }
            break;

        case TYPE_AUDIO_THEM:
            if (timestamp != null && !timestamp.isEmpty()) {
                try {
                    dateTime = ISODateTimeFormat.dateTime().parseDateTime(timestamp);
                    if (dateTime != null) holder.timestamp.setText(formatter.print(dateTime));
                }
                catch (IllegalArgumentException e) { e.printStackTrace(); }
            }

            if (mPartnerUser != null && mPartnerUser.getAvatarType() != null) {
                try {
                    holder.avatar.setImageDrawable(mContext.getResources().getDrawable(ViewHelper
                            .getAvatarHeadDrawableId(mContext, mPartnerUser.getAvatarType())));
                }
                catch (Resources.NotFoundException e) { e.printStackTrace(); }
            }

            holder.btnPlayAudio.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (audioFilepath != null && !audioFilepath.isEmpty()) {
                        mAudioHelper.changeViewsOfStoppedAudioMessage();
                        mAudioHelper.setPlayingAudioViews(finalHolder.ivPlayAudio,
                                finalHolder.spinPlayingAudio, finalHolder.tvPlayAudio);
                        mAudioHelper.playAudio(audioFilepath);
                    }
                }
            });
            break;

        case TYPE_MATCH_NOTICE:
            if (message != null) {
                if (message.contains("{")) {
                    Bundle info = null;
                    message = message.substring(message.indexOf("{"));
                    try {
                        JSONObject obj = new JSONObject(message);
                        info = JsonHelper.parseMatchNoticeMessageJson(obj);
                    }
                    catch (JSONException e) { e.printStackTrace(); }

                    if (info != null) {
                        if (info.containsKey(GlobalVars.KEY_GAME) && info.containsKey(GlobalVars
                                .KEY_PLATFORM)) {
                            Game game = mDb.getGame(info.getString(GlobalVars.KEY_GAME),
                                    info.getString(GlobalVars.KEY_PLATFORM));

                            if (game != null && game.getCoverPhoto() != null) {
                                ViewHelper.loadOrDownloadGameCover(mContext, game.getCoverPhoto(),
                                        holder.gameCover, holder.spinGameCover);
                            }
                        }

                        if (info.containsKey(GlobalVars.KEY_GAME_TIME)) {
                            String matchTime = info.getString(GlobalVars.KEY_GAME_TIME);

                            if (matchTime != null && !matchTime.isEmpty()) {
                                try {
                                    dateTime = ISODateTimeFormat.dateTime().parseDateTime(matchTime);

                                    if (dateTime != null) {
                                        holder.date.setText(DateTimeFormat.forPattern(GlobalVars
                                                .FORMAT_DATE_WITH_DAY_OF_WEEK).print(dateTime));
                                        holder.time.setText(DateTimeFormat.forPattern(GlobalVars
                                                .FORMAT_TIME).print(dateTime));
                                    }
                                }
                                catch (IllegalArgumentException e) { e.printStackTrace(); }
                            }
                        }
                    }
                }
            }
            break;
    }

    return convertView;
}

public void refreshList(List<ChatMessage> updatedMessages) {
    mMessages.clear();
    mMessages.addAll(updatedMessages);
    this.notifyDataSetChanged();
}

}

My Stacktrace

java.lang.NullPointerException
   at com.walintukai.lovelup.adapters.ChatAdapter$ViewHolder.access$100(ChatAdapter.java:118)
   at com.walintukai.lovelup.adapters.ChatAdapter.getView(ChatAdapter.java:201)
   at android.widget.HeaderViewListAdapter.getView(HeaderViewListAdapter.java:230)
   at android.widget.AbsListView.obtainView(AbsListView.java:2739)
   at android.widget.ListView.makeAndAddView(ListView.java:1801)
   at android.widget.ListView.fillUp(ListView.java:733)
   at android.widget.ListView.fillGap(ListView.java:670)
   at android.widget.AbsListView.trackMotionScroll(AbsListView.java:6747)
   at android.widget.AbsListView.scrollIfNeeded(AbsListView.java:3988)
   at android.widget.AbsListView.onTouchMove(AbsListView.java:4840)
   at android.widget.AbsListView.onTouchEvent(AbsListView.java:4668)
   at android.view.View.dispatchTouchEvent(View.java:8135)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2417)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2141)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2423)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2156)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2423)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2156)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2423)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2156)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2423)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2156)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2423)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2156)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2423)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2156)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2423)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2156)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2423)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2156)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2423)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2156)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2423)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2156)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2423)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2156)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2423)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2156)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2423)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2156)
   at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2295)
   at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1622)
   at android.app.Activity.dispatchTouchEvent(Activity.java:2565)
   at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2243)
   at android.view.View.dispatchPointerEvent(View.java:8343)
   at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4743)
   at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4609)
   at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4167)
   at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4221)
   at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4190)
   at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4301)
   at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4198)
   at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4358)
   at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4167)
   at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4221)
   at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4190)
   at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4198)
   at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4167)
   at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6517)
   at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6434)
   at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6405)
   at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6370)
   at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6597)
   at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
   at android.os.MessageQueue.nativePollOnce(MessageQueue.java)
   at android.os.MessageQueue.next(MessageQueue.java:138)
   at android.os.Looper.loop(Looper.java:123)
   at android.app.ActivityThread.main(ActivityThread.java:5579)
   at java.lang.reflect.Method.invokeNative(Method.java)
   at java.lang.reflect.Method.invoke(Method.java:515)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1268)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084)
   at dalvik.system.NativeStart.main(NativeStart.java)
The Nomad
  • 7,155
  • 14
  • 65
  • 100
  • possible duplicate of [What is a Null Pointer Exception, and how do I fix it?](http://stackoverflow.com/questions/218384/what-is-a-null-pointer-exception-and-how-do-i-fix-it) – StackFlowed Mar 12 '15 at 18:55
  • seems like your holder is coming out null. check for null after `code` else holder = (ViewHolder) convertView.getTag();`code` – Shaz Mar 12 '15 at 20:49

1 Answers1

0

Played around and found my answer. So I guess some of the tags of the rows were null so it would call the else statement with the convertView.getTag() which was coming up null.

The solution is to check also if convertView.getTag() == null like so:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    int type = getItemViewType(position);

    if (convertView == null || convertView.getTag() == null) {
    ...
    }
    else {
        holder = (ViewHolder) convertView.getTag();
    }
The Nomad
  • 7,155
  • 14
  • 65
  • 100