[英]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. 我正在练习为wordpress博客构建一个android应用程序,而我基本上想要做的是fetech帖子标题及其作者。 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 这是json https://hmn.md/wp-json/wp/v2/posts的链接
This are my codes 这是我的密码
PostItems 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 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 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 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 在PostFragment中
From line if (adapter.getAuthor(authorhref) == null) {
AS is complaining that "cannot resolve method getAuthor(Java.lang.String) 从行开始,
if (adapter.getAuthor(authorhref) == null) {
AS抱怨“无法解析方法getAuthor(Java.lang.String)
From line adapter.setPostItems(mPostItemsList);
从
adapter.setPostItems(mPostItemsList);
行adapter.setPostItems(mPostItemsList);
Cannot resolve meethod 'setPostItems(java.util.List.com.example.postapp.PostItems>)' 无法解析method'setPostItems(java.util.List.com.example.postapp.PostItems>)'
From line adapter.putAuthor(href, authorname);
从
adapter.putAuthor(href, authorname);
Cannot resolve method 'putAuthor(java.lang.String)' 无法解析方法'putAuthor(java.lang.String)'
In PostAdapter 在PostAdapter中
From line mAuthorMap = new HashMap<>();
从
mAuthorMap = new HashMap<>();
'Unknown class mAuthorMap' and also Identifier expected
in the position of >
“未知类mAuthorMap”,以及在
>
位置中应有的 Identifier expected
Methods setPostItems
, putAuthor
, getAuthor
all saying *Method never used. 方法
setPostItems
, putAuthor
和getAuthor
都说*方法从未使用过。
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; 在
parseAuthor
方法中,我并不太了解您要执行的操作,就好像您要获取"self"
数组一样。 though what I wanted is the author array. 虽然我想要的是author数组。
If you were using HttpURLConnection
and AsyncTask
, you could make both requests in one background operation and have no problem. 如果您使用的是
HttpURLConnection
和AsyncTask
,则可以在一个后台操作中发出两个请求,并且没有问题。
But since it looks like you are committed to using Volley, I propose that you use a two-phase approach. 但是,由于您似乎决心使用Volley,因此我建议您使用两阶段方法。 In phase 1 you parse the posts and save the author urls for the post.
在阶段1中,您分析帖子并保存帖子的作者url。 In phase 2, you add the author name to a map indexed by url.
在阶段2中,您将作者姓名添加到由url索引的地图中。
Have the PostItem
contain the author url instead of the author name: 让
PostItem
包含作者网址而不是作者名称:
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.) (我将其设为PostItem(单数),因为它不是任何种类的同质集合。)
Add a Map
to your adapter to contain the author names: 将
Map
添加到适配器以包含作者名称:
/** 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
PostItem
to the adapter PostItem
添加到适配器 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): 注意,我将您的
getAuthor
方法更改为采用一个参数(而不使用成员变量):
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: onBindViewHolder
就是它们的结合之处:
@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 编辑:以多种方式获取作者网址,而无需解析作者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();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.