Error in Android Studio project

187 views Asked by At

I have 2 activities: Feed and User. Both activities use same adapter, same layout, but in first activity adapter loads the Feed (and crashes), in the second activity adapter loads user's feed (not crashes).

This what I found in console for Feed.class:

E/AndroidRuntime: FATAL EXCEPTION: main
              Process: com.flaunder.flaunder, PID: 5906
              java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference
                  at com.android.volley.toolbox.ImageLoader.getCacheKey(ImageLoader.java:503)
                  at com.android.volley.toolbox.ImageLoader.get(ImageLoader.java:213)
                  at com.android.volley.toolbox.ImageLoader.get(ImageLoader.java:191)
                  at com.android.volley.toolbox.ImageLoader.get(ImageLoader.java:182)
                  at com.flaunder.flaunder.QuestionsAdapter.onBindViewHolder(QuestionsAdapter.java:69)
                  at com.flaunder.flaunder.QuestionsAdapter.onBindViewHolder(QuestionsAdapter.java:30)
                  at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:6062)
                  at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:6095)
                  at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5277)
                  at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5153)
                  at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2061)
                  at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1445)
                  at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1408)
                  at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:580)
                  at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3374)
                  at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3183)
                  at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3627)
                  at android.view.View.layout(View.java:16630)
                  at android.view.ViewGroup.layout(ViewGroup.java:5437)
                  at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1079)
                  at android.view.View.layout(View.java:16630)
                  at android.view.ViewGroup.layout(ViewGroup.java:5437)
                  at android.support.design.widget.HeaderScrollingViewBehavior.layoutChild(HeaderScrollingViewBehavior.java:131)
                  at android.support.design.widget.ViewOffsetBehavior.onLayoutChild(ViewOffsetBehavior.java:42)
                  at android.support.design.widget.AppBarLayout$ScrollingViewBehavior.onLayoutChild(AppBarLayout.java:1367)
                  at android.support.design.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:849)
                  at android.view.View.layout(View.java:16630)
                  at android.view.ViewGroup.layout(ViewGroup.java:5437)
                  at android.support.v4.widget.DrawerLayout.onLayout(DrawerLayout.java:1193)
                  at android.view.View.layout(View.java:16630)
                  at android.view.ViewGroup.layout(ViewGroup.java:5437)
                  at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
                  at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
                  at android.view.View.layout(View.java:16630)
                  at android.view.ViewGroup.layout(ViewGroup.java:5437)
                  at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743)
                  at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1586)
                  at android.widget.LinearLayout.onLayout(LinearLayout.java:1495)
                  at android.view.View.layout(View.java:16630)
                  at android.view.ViewGroup.layout(ViewGroup.java:5437)
                  at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
                  at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
                  at android.view.View.layout(View.java:16630)
                  at android.view.ViewGroup.layout(ViewGroup.java:5437)
                  at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743)
                  at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1586)
                  at android.widget.LinearLayout.onLayout(LinearLayout.java:1495)
                  at android.view.View.layout(View.java:16630)
                  at android.view.ViewGroup.layout(ViewGroup.java:5437)
                  at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
                  at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
                  at com.android.internal.policy.PhoneWindow$DecorView.onLayout(PhoneWindow.java:2678)
                  at android.view.View.layout(View.java:16630)
                  at android.view.ViewGroup.layout(ViewGroup.java:5437)
                  at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2171)
                at android

Adapter gets json from server's db and parses them. Fields for json are the same for Feed and User.

Code in adapter:

@Override
    public void onBindViewHolder(ViewHolder holder, int position) {

        regular = Typeface.createFromAsset(context.getAssets(),"OpenSans-Regular.ttf");
        bold = Typeface.createFromAsset(context.getAssets(),"OpenSans-Semibold.ttf");

        //Getting the particular item from the list
        QuestionList questionHero =  questionList.get(position);

        //Loading image from url
        imageLoader = CustomVolleyRequest.getInstance(context).getImageLoader();
        imageLoader.get(questionHero.getUserphoto(), ImageLoader.getImageListener(holder.genUserPhoto, R.drawable.header, android.R.drawable.ic_dialog_alert));
        imageLoader.get(questionHero.getPhoto(), ImageLoader.getImageListener(holder.genPhoto, R.drawable.header, android.R.drawable.ic_dialog_alert));

        //Showing data on the views
        holder.genUserPhoto.setImageUrl(questionHero.getUserphoto(), imageLoader);
        holder.genQuestion.setText(questionHero.getQuestion());
        holder.genQuestion.setTypeface(bold);
        holder.genAnswer.setText(questionHero.getAnswer());
        holder.genAnswer.setTypeface(regular);
        holder.genFroms.setText(questionHero.getFroms());
        holder.genFroms.setTypeface(regular);
        holder.genTos.setText(questionHero.getTos());
        holder.genTos.setTypeface(regular);
        holder.genFromslogin.setText(questionHero.getFromslogin());
        holder.genToslogin.setText(questionHero.getToslogin());
        holder.genToslogin2.setText(questionHero.getToslogin());
        holder.genDate.setText(questionHero.getDate());
        holder.genDate.setTypeface(regular);
        holder.genLikenum.setText(questionHero.getLikenum());
        holder.genLikenum.setTypeface(regular);
        holder.genCommentnum.setText(questionHero.getCommentnum());
        holder.genCommentnum.setTypeface(regular);
        holder.genPhoto.setImageUrl(questionHero.getPhoto(), imageLoader);
        holder.genVideo.setText(questionHero.getVideo());
        holder.genId.setText(questionHero.getQid());

    }

Feed:

private void parseData(JSONArray array) {
        for (int i = 0; i < array.length(); i++) {
            //Creating the superhero object
            QuestionList qHero = new QuestionList();
            JSONObject json = null;
            try {
                //Getting json
                json = array.getJSONObject(i);

                //Adding data to the superhero object
                qHero.setQuestion(json.getString("question"));
                qHero.setAnswer(json.getString("answer"));
                qHero.setUserphoto(json.getString("userphoto"));
                qHero.setFroms(json.getString("froms"));
                qHero.setTos(json.getString("tos"));
                qHero.setFromslogin(json.getString("fromslogin"));
                qHero.setToslogin(json.getString("toslogin"));
                qHero.setDate(json.getString("date"));
                qHero.setLikenum(json.getString("likenum"));
                qHero.setCommentnum(json.getString("commentnum"));
                qHero.setPhoto(json.getString("photo"));
                qHero.setVideo(json.getString("video"));
                qHero.setQid(json.getString("id"));

            } catch (JSONException e) {
                e.printStackTrace();
            }

            //Adding the superhero object to the list
            listQuestions.add(qHero);
        }

        //Notifying the adapter that data has been added or changed
        adapter.notifyDataSetChanged();
    }

Adapter init:

class ViewHolder extends RecyclerView.ViewHolder{
        //Views
        public NetworkImageView genUserPhoto;
        public TextView genQuestion;
        public TextView genAnswer;
        public TextView genFroms;
        public TextView genTos;
        public TextView genFromslogin;
        public TextView genToslogin;
        public TextView genToslogin2;
        public TextView genDate;
        public TextView genLikenum;
        public TextView genCommentnum;
        public NetworkImageView genPhoto;
        public TextView genVideo;
        public TextView genId;
        public TextView genPhotourl;
        public CardView cardRview;

        //Initializing Views
        public ViewHolder(View itemView) {
            super(itemView);
            genUserPhoto = (NetworkImageView) itemView.findViewById(R.id.genUserPhoto);
            genQuestion = (TextView) itemView.findViewById(R.id.genQuestion);
            genAnswer = (TextView) itemView.findViewById(R.id.genAnswer);
            genFroms = (TextView) itemView.findViewById(R.id.genFroms);
            genTos = (TextView) itemView.findViewById(R.id.genTos);
            genFromslogin = (TextView) itemView.findViewById(R.id.genFromslogin);
            genToslogin = (TextView) itemView.findViewById(R.id.genToslogin);
            genToslogin2 = (TextView) itemView.findViewById(R.id.genToslogin2);
            genDate = (TextView) itemView.findViewById(R.id.genDate);
            genLikenum = (TextView) itemView.findViewById(R.id.genLikenum);
            genCommentnum = (TextView) itemView.findViewById(R.id.genCommentnum);
            genPhoto = (NetworkImageView) itemView.findViewById(R.id.genPhoto);
            genVideo = (TextView) itemView.findViewById(R.id.genVideo);
            genId = (TextView) itemView.findViewById(R.id.genId);
            genPhotourl = (TextView) itemView.findViewById(R.id.genPhotourl);
            cardRview = (CardView) itemView.findViewById(R.id.cardRview);
        }
    }
1

There are 1 answers

1
Akhil Dad On BEST ANSWER

So as you are parsing JSON some of the keys may be null or not present. In that case your questionHero will contain null. So before calling the code you should check like this

 if (questionHero.getUserphoto() != null ) {
//in case you handle visibility in else block make //holder.genUserPhoto.setVisibility(View.VISIBLE) here visible 
     imageLoader.get(questionHero.getUserphoto(), ImageLoader.getImageListener(holder.genUserPhoto, R.drawable.header, android.R.drawable.ic_dialog_alert));
    } else {
//reset image by questionHero.genUserPhoto.setImageBitmap(null), or handle //visibility of holder.genUserPhoto
}

same way you can write for questionHero.getPhoto()

Why VISIBILITY or Resetting is needed?

Recycler view reuses items so the same views will be reused at other positions in case you don't handle that you will end up showing wrong images at wrong places.

Couple of performance tips

regular = Typeface.createFromAsset(context.getAssets(),"OpenSans-Regular.ttf");
        bold = Typeface.createFromAsset(context.getAssets(),"OpenSans-Semibold.ttf");

Never ever right such code in bindViewHolder, this method would be invoked again and agin when you scroll, each time it will create font from assets which is enough of task to make your scroll laggy. You should create a singleton class for this which will create font once and cache it and supply to app whenever required.

 holder.genDate.setTypeface(regular);
imageLoader = CustomVolleyRequest.getInstance(context).getImageLoader();

Right now you have written this code in bindViewHolder, move this code to createViewHolder, because setting the font would be enough once similarly you should get image loader once though it won't make much difference as ImageLoader is itself singleton but still its good to have at ViewHolder level, only the data or properties of view which will change for each recycler view item should be handled in bindViewHolder method.