1

I know that there are many questions about nullpointexeception, but if i could find where is a mistake, i wouldn't ask here this question. So i'm getting this error when i come to the bottom of list and try to use method load more data. I'm doing this with recyclerview. So first time, all data are loaded, but when i try to load more, i'm getting error mentioned in title. Here is the code:

public class ProfileUserFragment extends Fragment implements OnBackPressedListener {

private ResideMenu resideMenu;
private SmoothRecyclerView mRecyclerView;
private PostListAdapter mAdapter;

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View parentView = inflater.inflate(R.layout.fragment_profile, container, false);
    setUpViews(parentView);
    initList(parentView);
    return parentView;
}

private void initList(View view) {
    bindData();
    mRecyclerView = (SmoothRecyclerView) view.findViewById(R.id.list);
    mRecyclerView.setHasFixedSize(true);
    LinearLayoutManager manager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
    mRecyclerView.setLayoutManager(manager);
    mRecyclerView.addItemDecoration(new HorizontalDividerItemDecoration(getActivity()));
    mAdapter      = new PostListAdapter(getActivity());

    mRecyclerView.setAdapter(mAdapter);

    // Load more data when user reach bottom
    mAdapter.setOnLoadMoreListener(new OnLoadMoreListener() {
        @Override
        public void onLoadMore() {
            // add null , so the adapter will check view_type and show progress bar at bottom
            mPosts.add(null);
            mAdapter.notifyItemInserted(mPosts.size() - 1);

            // Load data
            Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    // Remove loading item
                    mPosts.remove(mPosts.size() - 1);
                    mAdapter.notifyItemRemoved(mPosts.size());

                    // Load data
                    int start = mPosts.size();
                    int end   = start + 20;
                    for (int i = start + 1; i <= end; i++) {
                        Post post = new Post();
                        post.setTitle("Title ");
                        post.setDesc("Desc ");
                        post.setTimestamp("Time ");
                        mPosts.add(post);
                    }

                    mAdapter.setLoaded();
                    mAdapter.notifyDataSetChanged();
                }
            }, 2000);
        }
    });
}

private void setUpViews(View view) {
    HomeActivity parentActivity = (HomeActivity) getActivity();
    resideMenu = parentActivity.getResideMenu();
    ImageButton imageButton = (ImageButton) view.findViewById(R.id.drawer_menu);
    imageButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            resideMenu.openMenu(ResideMenu.DIRECTION_LEFT);
        }
    });
}

private void bindData() {
    mPosts.clear();
    for (int i = 1; i <= 20; i++) {
        Post post = new Post();
        post.setTitle("Title " + i);
        post.setDesc("Desc " + i);
        post.setTimestamp("Time " + i);
        mPosts.add(post);
    }
}

@Override
public void onBackPressed() {
    resideMenu.openMenu(ResideMenu.DIRECTION_LEFT);
}

private List<Post> mPosts = new ArrayList<>();

public class PostListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private Context mContext;
    private OnLoadMoreListener mOnLoadMoreListener;

    private final int VIEW_TYPE_ITEM    = 0;
    private final int VIEW_TYPE_LOADING = 1;

    private boolean isLoading;
    private int visibleThreshold = 2;
    private int lastVisibleItem, totalItemCount;

    public PostListAdapter(Context context) {
        this.mContext = context;
        final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                totalItemCount  = linearLayoutManager.getItemCount();
                lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();

                if (!isLoading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
                    // End has been reached
                    // Do something
                    if (mOnLoadMoreListener != null) {
                        mOnLoadMoreListener.onLoadMore();
                    }
                    isLoading = true;
                }
            }
        });
    }

    public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
        this.mOnLoadMoreListener = mOnLoadMoreListener;
    }

    @Override
    public int getItemViewType(int position) {
        return mPosts == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        RecyclerView.ViewHolder vh = null;
        if (viewType == VIEW_TYPE_ITEM) {
            View view = LayoutInflater.from(mContext).inflate(
                    R.layout.post_list_item,
                    parent,
                    false);
            vh = new PostHolder(view);
        } else if (viewType == VIEW_TYPE_LOADING){
            View view = LayoutInflater.from(mContext).inflate(
                    R.layout.progress_bar,
                    parent,
                    false);
            vh = new LoadingHolder(view);
        }
        return vh;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof PostHolder) {
            PostHolder postHolder = (PostHolder) holder;
            Post post = mPosts.get(position);
            postHolder.tvPostTitle.setText(post.getTitle());
            postHolder.tvPostDesc.setText(post.getDesc());
            postHolder.tvPostTimestamp.setText(post.getTimestamp());
        } else if (holder instanceof LoadingHolder) {
            LoadingHolder loadingHolder = (LoadingHolder) holder;
            loadingHolder.mProgressBar.setIndeterminate(true);
        }
    }

    @Override
    public int getItemCount() {
        return mPosts == null ? 0 : mPosts.size();
    }

    public class PostHolder extends RecyclerView.ViewHolder {
        MyTextView tvPostTitle;
        MySecondTextView tvPostTimestamp, tvPostDesc;

        public PostHolder(View view) {
            super(view);
            tvPostTitle     = (MyTextView) view.findViewById(R.id.tv_post_title);
            tvPostDesc      = (MySecondTextView) view.findViewById(R.id.tv_post_desc);
            tvPostTimestamp = (MySecondTextView) view.findViewById(R.id.tv_created_at);
        }
    }

    public class LoadingHolder extends RecyclerView.ViewHolder {
        ProgressBar mProgressBar;

        public LoadingHolder(View view) {
            super(view);
            mProgressBar = (ProgressBar) view.findViewById(R.id.progressBar1);
        }
    }

    public void setLoaded() {
        isLoading = false;
    }
}
}

Here is an error i'm getting:

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.solaris.timster.model.Post.getTitle()' on a null object reference
                                                                     at com.solaris.timster.fragments.ProfileUserFragment$PostListAdapter.onBindViewHolder(ProfileUserFragment.java:191)
                                                                     at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:5471)
                                                                     at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:5504)
                                                                     at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4741)
                                                                     at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4617)
                                                                     at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1994)
                                                                     at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1390)
                                                                     at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1353)
                                                                     at android.support.v7.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1180)
                                                                     at android.support.v7.widget.LinearLayoutManager.scrollVerticallyBy(LinearLayoutManager.java:1031)
                                                                     at android.support.v7.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:4061)
                                                                     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:920)
                                                                     at android.view.Choreographer.doCallbacks(Choreographer.java:695)
                                                                     at android.view.Choreographer.doFrame(Choreographer.java:628)
                                                                     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:906)
                                                                     at android.os.Handler.handleCallback(Handler.java:739)
                                                                     at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                     at android.os.Looper.loop(Looper.java:158)
                                                                     at android.app.ActivityThread.main(ActivityThread.java:7229)
                                                                     at java.lang.reflect.Method.invoke(Native Method)
                                                                     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
                                                                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
Dusan Dimitrijevic
  • 2,971
  • 5
  • 20
  • 42

2 Answers2

2

update getItemViewType as follows

@Override
public int getItemViewType(int position) {
    return mPosts.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
}

This way you are checking if the item at position is null. Earlier you were checking if the entire list was null and so getting incorrect view holder type in onBindViewHolder.

user3215142
  • 306
  • 2
  • 6
1

You see where you call mPosts.add(null); in onLoadMore()? That is when the null value is inserted to the item list, and then when you call post.getTitle() in onBindViewHolder(), it will cause NullPointerException.

One thing you can do is check if the post is null in onBincViewHolder(), if it is then just return.

Or you can just don't add the null value to the list in the first place.

P.S: You are calling mAdapter.notifyItemRemoved(mPosts.size());, shouldn't it be mAdapter.notifyItemRemoved(mPosts.size()-1);?

Joel Min
  • 3,168
  • 1
  • 15
  • 35