How to send multiple Json request and populate ReyclerView with the data

I am practicing building an android app for wordpress blog and what I basically want to do is to fetech the post title and it’s author. I am able to get and display the post title without any hassles but what’s giving headache is the post author.

This is the link of the json https://hmn.md/wp-json/wp/v2/posts

Read More

This are my codes

PostItems

public class PostItems implements Parcelable {
    private String post_title;
    private String post_author;

    public String getPost_title() {
        return post_title;
    }

    public void setPost_title(String post_title) {
        this.post_title = post_title;
    }



    public String getPost_author() {
        return post_author;
    }

    public void setPost_author(String post_author) {
        this.post_author = post_author;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.post_title);
        dest.writeString(this.post_author);
    }

    public PostItems() {
    }

    protected PostItems(Parcel in) {
        this.post_title = in.readString();
        this.post_author = in.readString();
    }

    public static final Parcelable.Creator<PostItems> CREATOR = new Parcelable.Creator<PostItems>() {
        @Override
        public PostItems createFromParcel(Parcel source) {
            return new PostItems(source);
        }

        @Override
        public PostItems[] newArray(int size) {
            return new PostItems[size];
        }
    };
}

Part of PostList

...
private void getData(){
         Log.d(TAG, "getData called");
         final ProDialoFrag dialoFrag = ProDialoFrag.newInstance();
         dialoFrag.show(getFragmentManager(), "fragmentDialog");


         //Creating a json request
         jsonArrayRequest = new JsonArrayRequest(GET_URL,
                 new Response.Listener<JSONArray>() {
                     @Override
                     public void onResponse(JSONArray response) {
                         Log.d(TAG, "onResponse called");
                         //Dismissing the progress dialog
                         if (dialoFrag != null ) {
                             dialoFrag.dismiss();
                         }
                         //calling method to parse json array
                         parseData(response);

                     }
                 },
                 new Response.ErrorListener() {
                     @Override
                     public void onErrorResponse(VolleyError error) {
                         if (dialoFrag != null) {
                             dialoFrag.dismiss();
                         }
                         if (sthWrongAlert != null) {
                             sthWrongAlert.show();
                         }

                     }
                 }) {

         };

         //Creating request queue
         RequestQueue requestQueue = Volley.newRequestQueue(getActivity());

         //Adding request to the queue
         requestQueue.add(jsonArrayRequest);

     }

     //This method will parse json data
     private void parseData(JSONArray array){
         Log.d(TAG, "Parsing array");

         mPostItemsList.clear();


         for(int i = 0; i<array.length(); i++) {
             PostItems postItem = new PostItems();
             JSONObject jsonObject = null;
             try {
                 jsonObject = array.getJSONObject(i);

                 JSONObject postTitle = jsonObject.getJSONObject("title");
                 postItem.setPost_title(postTitle.getString("rendered"));

                 JSONObject links = jsonObject.getJSONObject("_links");
                 JSONArray authorLink = links.getJSONArray("author");
                 String authorhref = authorLink.getJSONObject(0).getString("name")



                 postItem.setPostId(jsonObject.getString("link"));
             } catch (JSONException w) {
                 w.printStackTrace();
                 //Toast.makeText(this, "Error in parsing Json", Toast.LENGTH_LONG).show();
             }

             mPostItemsList.add(postItem);

         }
         adapter.notifyItemRangeChanged(0, adapter.getItemCount());


     }

PostAdapter

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


     private static Context mContext;


     //List of posts
     private List<PostItems> mPostItems;

     private final int VIEW_ITEM = 0;
     private final int VIEW_PROG = 1;

     private int lastPosition = -1;


    public PostAdapter(List<PostItems> postItems, Context context) {
        super();

        //Getting all posts
        this.mPostItems = postItems;
        this.mContext = context;
    }


     @Override
     public int getItemViewType(int position) {
         if (isPositionItem(position))
             return VIEW_ITEM;
         return VIEW_PROG;
     }

     private boolean isPositionItem(int position) {
        return position != getItemCount()-1;
     }



     @Override
     public RecyclerView.ViewHolder  onCreateViewHolder (ViewGroup parent, int viewType) {
         if (viewType == VIEW_ITEM) {
             View v =  LayoutInflater.from(parent.getContext())
                     .inflate(R.layout.post_summ, parent, false);
             return new CardDetails(v);
         } else if (viewType == VIEW_PROG){
             View v = LayoutInflater.from(parent.getContext())
                     .inflate(R.layout.recyclerfooter, parent, false);
             return new ProgressViewHolder(v);
         }

         return null;
     }



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

         if (holder instanceof CardDetails) {
             final PostItems postList = mPostItems.get(position);

             ((CardDetails) holder).postTitle.setText(Html.fromHtml(postList.getPost_title()));
             ((CardDetails) holder).postAuthor.setText(postList.getPost_author());


         } else {
             ((ProgressViewHolder) holder).progressBar.setIndeterminate(true);
         }


     }

     @Override
     public int getItemCount(){
         //Return the number of items in the data set
         return mPostItems.size();
     }


     public class CardDetails extends RecyclerView.ViewHolder implements View.OnClickListener {
         public TextView postTitle, postAuthor;

         public CardDetails (final View postView) {
             super(postView);
             postTitle = (TextView) postView.findViewById(R.id.post_title);
             postAuthor = (TextView) postView.findViewById(R.id.post_author);
         }

     }

     public  class ProgressViewHolder extends RecyclerView.ViewHolder{
         ProgressBar progressBar;
         public ProgressViewHolder(View footerView){
             super(footerView);
             progressBar = (ProgressBar) footerView.findViewById(R.id.progress_load);
             progressBar.setVisibility(View.VISIBLE);
         }

     }


 }

My Current Solution

 private void parseData(JSONArray array){
         Log.d(TAG, "Parsing array");


         for(int i = 0; i<array.length(); i++) {
             JSONObject jsonObject;
             try {
                 jsonObject = array.getJSONObject(i);

                 JSONObject postTitle = jsonObject.getJSONObject("title");
                 String postT = postTitle.getString("rendered");
                 mPostTitle = postT;


                 JSONObject links = jsonObject.getJSONObject("_links");
                 JSONArray authorLink = links.getJSONArray("author");
                 authorhref = authorLink.getJSONObject(0).getString("href");


                 getAuthor();

             } catch (JSONException w) {
                 w.printStackTrace();
                 //Toast.makeText(this, "Error in parsing Json", Toast.LENGTH_LONG).show();
             }

         }


     }

     private void getAuthor() {
         Log.d(TAG, "getAuthor called");

         JsonObjectRequest authorRequest = new JsonObjectRequest(authorhref, null,
                 new Response.Listener<JSONObject>() {
                     @Override
                     public void onResponse(JSONObject response) {
                         Log.d(TAG, "onResponse called");
                         parseAuthor(response);
                     }
                 },
                 new Response.ErrorListener() {

                     @Override
                     public void onErrorResponse(VolleyError error) {

                     }
                 });

         authorRequest.setShouldCache(false);

         RequestQueue requestQueue = Volley.newRequestQueue(getActivity());
         requestQueue.add(authorRequest);

     }

     private void parseAuthor (JSONObject object) {
         Log.d(TAG, "Parsing author");
         PostItems postItem = new PostItems();

         try {
             String authorname = object.getString("name");
             postItem.setPost_author(authorname);
             postItem.setPost_title(mPostTitle);
         } catch (JSONException w) {
             w.printStackTrace();
         }
         mPostItemsList.add(postItem);
         adapter.notifyItemRangeChanged(0, adapter.getItemCount());
     }

The problem wih my solution is that all the posts titles are the same. To explain further, the author names are what they are supposed to be, but all the post titles are the title of the last post.

Please do have any idea how I could fix this?


After Applying kris larson’s Answer

Part of PostFragment

public class PostFragment extends Fragment{

    private List<PostItems> mPostItemsList = new ArrayList<>();
    ...
    // Nothing changed here, just added it so you will understand my code better
    ObservableRecyclerView recyclerView;
        private RecyclerView.Adapter adapter;
        LinearLayoutManager mLayoutManager;


        public PostFragment() {
            // Required empty public constructor
        }


        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            String title = getArguments().getString("title");
            // Inflate the layout for this fragment
            view = inflater.inflate(R.layout.fragment_post, container, false);
            //Initializing Views
            recyclerView = (ObservableRecyclerView) view.findViewById(R.id.post_recycler);
            recyclerView.setScrollViewCallbacks(this);
            mLayoutManager = new LinearLayoutManager(getActivity());
            recyclerView.setLayoutManager( mLayoutManager);
            ...

    //This method will get data from the web api
        private void getData(){
            Log.d(TAG, "getData called");
            final ProDialoFrag dialoFrag = ProDialoFrag.newInstance();
            dialoFrag.show(getFragmentManager(), "fragmentDialog");


            //Creating a json request
            jsonArrayRequest = new JsonArrayRequest(GET_URL,
                    new Response.Listener<JSONArray>() {
                        @Override
                        public void onResponse(JSONArray response) {
                            Log.d(TAG, "onResponse called");
                            //Dismissing the progress dialog
                            if (dialoFrag == null ) {
                                dialoFrag.dismiss();
                            }
                            //calling method to parse json array
                            parseData(response);

                        }
                    },
                    new Response.ErrorListener() {
                        @Override
                        public void onErrorResponse(VolleyError error) {
                            if (dialoFrag != null) {
                                dialoFrag.dismiss();
                            }
                            if (sthWrongAlert != null) {
                                sthWrongAlert.show();
                            }

                        }
                    }) {
                n Response.success(resp.result, entry);
                }
            };

            //Creating request queue
            RequestQueue requestQueue = Volley.newRequestQueue(getActivity());

            //Adding request to the queue
            requestQueue.add(jsonArrayRequest);

        }

        //This method will parse json data
        private void parseData(JSONArray array){
            Log.d(TAG, "Parsing array");

            for(int i = 0; i<array.length(); i++) {

                JSONObject jsonObject;
                try {
                    jsonObject = array.getJSONObject(i);

                    JSONObject postTitle = jsonObject.getJSONObject("title");
                    String title = postTitle.getString("rendered"));

                    JSONObject links = jsonObject.getJSONObject("_links");
                    JSONArray authorLink = links.getJSONArray("author");
                    String authorhref = authorLink.getJSONObject(0).getString("href");

                    PostItems postItem = new PostItems();
                    postItem.setPost_title(title);
                    postItem.setPostAuthorUrl(authorhref);
                    mPostItemsList.add(postItem);

                    if (adapter.getAuthor(authorhref) == null) {
                        getAuthor(authorhref);
                    }
                } catch (JSONException w) {
                    w.printStackTrace();
                    //Toast.makeText(this, "Error in parsing Json", Toast.LENGTH_LONG).show();
                }



            }
            adapter.setPostItems(mPostItemsList);


        }

        private void getAuthor (String authorhref) {
            Log.d(TAG, "getAuthor called");

            JsonObjectRequest authorRequest = new JsonObjectRequest(authorhref, null,
                    new Response.Listener<JSONObject>() {
                        @Override
                        public void onResponse(JSONObject response) {
                            Log.d(TAG, "onResponse called");
                            parseAuthor(response);
                        }
                    },
                    new Response.ErrorListener() {
                        @Override
                        public void onErrorResponse(VolleyError error) {
                            //Do nothing
                        }
                    });
            authorRequest.setShouldCache(false);
            RequestQueue requestQueue = Volley.newRequestQueue(getActivity());
            requestQueue.add(authorRequest);
        }
        private void parseAuthor (JSONObject object) {
            Log.d(TAG, "Parsing auhor");
            try {
                JSONObject links = object.getJSONObject("_links");
                JSONArray self = links.getJSONArray("self");
                String href = self.getJSONObject(0).getString("href");

                String authorname = object.getString("name");
                adapter.putAuthor(href, authorname);
            } catch (JSONException w) {
                w.printStackTrace();
            }
        }

}

PostAdapter

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



    private ImageLoader imageLoader;
    private static Context mContext;


    //List of posts
    private List<PostItems> mPostItems;

    //authors by url
    private Map<String, String> mAuthorMap;

    //don't forget to initialoze in adapter constructor
    mAuthorMap = new HashMap<>();

    private final int VIEW_ITEM = 0;
    private final int VIEW_PROG = 1;

    private int lastPosition = -1;

    public void setPostItems(List<PostItems> postItems) {
        mPostItems = postItems;
        notifyDataSetChanged();
    }

    public void putAuthor(String url, String name) {
        mAuthorMap.put(url, name);
        notifyDataSetChanged();
    }

    public String getAuthor(String url) {
        return mAuthorMap.get(url);
    }


   public PostAdapter(List<PostItems> postItems, Context context) {
       super();

       //Getting all posts
       this.mPostItems = postItems;
       this.mContext = context;
   }


    @Override
    public int getItemViewType(int position) {
        if (isPositionItem(position))
            return VIEW_ITEM;
        return VIEW_PROG;
    }

    private boolean isPositionItem(int position) {
       return position != getItemCount()-1;
    }



    @Override
    public RecyclerView.ViewHolder  onCreateViewHolder (ViewGroup parent, int viewType) {
        if (viewType == VIEW_ITEM) {
            View v =  LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.post_summ, parent, false);
            return new CardDetails(v);
        } else if (viewType == VIEW_PROG){
            View v = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.recyclerfooter, parent, false);
            return new ProgressViewHolder(v);
        }

        return null;
    }



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

        if (holder instanceof CardDetails) {
            final PostItems postList = mPostItems.get(position);
            ((CardDetails) holder).postTitle.setText(Html.fromHtml(postList.getPost_title()));

            String name = mAuthorMap.get(postList.getPostAuthorUrl());
            if (name != null) {
                ((CardDetails) holder).postAuthor.setText(name);
            }

        } else {
            ((ProgressViewHolder) holder).progressBar.setIndeterminate(true);
        }


    }


    @Override
    public int getItemCount(){
        //Return the number of items in the data set
        return mPostItems.size();
    }





    public class CardDetails extends RecyclerView.ViewHolder implements View.OnClickListener {
        public TextView postTitle, postAuthor;
        public ImageButton imageButton;

        public CardDetails (final View postView) {
            super(postView);
            postTitle = (TextView) postView

            .findViewById(R.id.post_title);
            postAuthor = (TextView) postView.findViewById(R.id.post_author);
        }


    }

    public  class ProgressViewHolder extends RecyclerView.ViewHolder{
        ProgressBar progressBar;
        public ProgressViewHolder(View footerView){
            super(footerView);
            progressBar = (ProgressBar) footerView.findViewById(R.id.progress_load);
            progressBar.setVisibility(View.VISIBLE);
        }

    }


}

Problems I am currently Having

  1. In PostFragment

    From line if (adapter.getAuthor(authorhref) == null) { AS is complaining that “cannot resolve method getAuthor(Java.lang.String)

    From line adapter.setPostItems(mPostItemsList); Cannot resolve meethod ‘setPostItems(java.util.List.com.example.postapp.PostItems>)’

    From line adapter.putAuthor(href, authorname); Cannot resolve method ‘putAuthor(java.lang.String)’

  2. In PostAdapter

From line mAuthorMap = new HashMap<>(); ‘Unknown class mAuthorMap’ and also Identifier expected in the position of >

Methods setPostItems, putAuthor, getAuthor all saying *Method never used.

And in parseAuthor method, I didn’t really understand what you were trying to do, it’s as if you are trying to get the "self" array; though what I wanted is the author array.

Related posts

Leave a Reply

1 comment

  1. If you were using HttpURLConnection and AsyncTask, you could make both requests in one background operation and have no problem.

    But since it looks like you are committed to using Volley, I propose that you use a two-phase approach. In phase 1 you parse the posts and save the author urls for the post. In phase 2, you add the author name to a map indexed by url.

    • Have the PostItem contain the author url instead of the author name:

      public class PostItem implements Parcelable {
          private String post_title;
          private String post_author_url;
          // also change all the getters/setters/parceling etc.
      }
      

      (I made it PostItem — singular — because it’s not a homogeneous collection of any kind.)

    • Add a Map to your adapter to contain the author names:

          /** posts, which contain author url */
          private List<PostItem> mPostItems;
      
          /** authors by url */
          private Map<String, String> mAuthorMap;
      

      don’t forget to initialize the author map in adapter constructor

      public PostAdapter(List<PostItems> postItems, Context context) {
          super();
      
          //Getting all posts
          this.mPostItems = postItems;
          this.mContext = context;
          this.mAuthorMap = new HashMap<>();
      }
      
    • When you receive the posts:

      1. Parse the post item
      2. Make a PostItem with the title and the author url
      3. Add the PostItem to the adapter
      4. Ask the adapter for the author
      5. If author not found, start a new author request

            private void parseData(JSONArray array){
        
                Log.d(TAG, "Parsing array");
        
                // Collect all the PostItems and add to adapter all at once
                List<PostItem> postItems = new ArrayList<>();
        
                for (int i = 0; i<array.length(); i++) {
                    JSONObject jsonObject;
                    try {
                        jsonObject = array.getJSONObject(i);
        
                        JSONObject postTitle = jsonObject.getJSONObject("title");
                        String title = postTitle.getString("rendered");
        
                        JSONObject links = jsonObject.getJSONObject("_links");
                        JSONArray authorLink = links.getJSONArray("author");
                        String authorhref = authorLink.getJSONObject(0).getString("href");
        
                        PostItem postItem = new PostItem();
                        postItem.setPostTitle(title);
                        postItem.setPostAuthorUrl(authorhref);
                        postItems.add(postItem);
        
                        if (mAdapter.getAuthor(authorhref) == null) {
                            getAuthor(authorhref);
                        }
        
                    } catch (JSONException w) {
                        w.printStackTrace();
                        //Toast.makeText(this, "Error in parsing Json", Toast.LENGTH_LONG).show();
                    }
                }
        
                mAdapter.setPostItems(postItems);
            }
        
    • Notice I changed your getAuthor method to take a parameter (and not use a member variable):

              private void getAuthor(String authorhref) {
                  ...
      
    • When you receive the author, add it to the adapter

              private void parseAuthor (JSONObject object) {
      
                  Log.d(TAG, "Parsing author");
                  try {
                      JSONObject links = jsonObject.getJSONObject("_links");
                      JSONArray self = links.getJSONArray("self");
                      String href = authorLink.getJSONObject(0).getString("href");
      
                      String authorname = object.getString("name");
                      mAdapter.putAuthor(href, name);
      
                  } catch (JSONException w) {
                      w.printStackTrace();
                  }
      
             }
      
    • Now here are the new adapter methods:

          public void setPostItems(List<PostItem> postItems) {
              mPostItems = postItems;
              notifyDataSetChanged();
          }
      
          public void putAuthor(String url, String name) {
              mAuthorMap.put(url, name);
              notifyDataSetChanged();
          }
      
          public String getAuthor(String url) {
              return mAuthorMap.get(url);
          }
      
    • And onBindViewHolder is where it all comes together:

          @Override
          public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
      
              if (holder instanceof CardDetails) {
                  final PostItem postItem = mPostItems.get(position);
                  ((CardDetails) holder).postTitle.setText(Html.fromHtml(postItem.getPostTitle()));
      
                  String name = mAuthorMap.get(postItem.getPostAuthorUrl());
      
                  if (name != null) {
                      ((CardDetails) holder).postAuthor.setText(name);
                  }
                  // don't worry if author name is null, when it's retrieved
                  // the adapter will be notified to refresh the list
      
              } else {
                  ((ProgressViewHolder)  holder).progressBar.setIndeterminate(true);
              }
          }
      

    EDIT: Different way to get the author url without having to parse author JSON -> _links -> self[0] -> href

            // notice that authorhref is final
            private void getAuthor (final String authorhref) {
                Log.d(TAG, "getAuthor called");
    
                JsonObjectRequest authorRequest = new JsonObjectRequest(authorhref, null,
                    new Response.Listener<JSONObject>() {
                        @Override
                        public void onResponse(JSONObject response) {
                            Log.d(TAG, "onResponse called");
                            parseAuthor(authorhref, response);  // pass authorhref with response
                        }
                    },
                    new Response.ErrorListener() {
                        @Override
                        public void onErrorResponse(VolleyError error) {
                            //Do nothing
                        }
                    });
                    authorRequest.setShouldCache(false);
                    RequestQueue requestQueue = Volley.newRequestQueue(getActivity());
                    requestQueue.add(authorRequest);
                }
    
                private void parseAuthor (String authorhref, JSONObject object) {
    
                    Log.d(TAG, "Parsing author");
                    try {
                        String authorname = object.getString("name");
                        mAdapter.putAuthor(authorhref, name);
    
                    } catch (JSONException w) {
                        w.printStackTrace();
                    }
    
                }