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
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
-
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)’ -
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.
If you were using
HttpURLConnection
andAsyncTask
, 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:(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:don’t forget to initialize the author map in adapter constructor
When you receive the posts:
PostItem
with the title and the author urlPostItem
to the adapterIf author not found, start a new author request
Notice I changed your
getAuthor
method to take a parameter (and not use a member variable):When you receive the author, add it to the adapter
Now here are the new adapter methods:
And
onBindViewHolder
is where it all comes together:EDIT: Different way to get the author url without having to parse author JSON -> _links -> self[0] -> href