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
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:
PostItem
with the title and the author url PostItem
to the adapter 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();
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.