Nested Recycler Adapter Items going into the wrong Recycler Views - android

On my app, I have a Recyler View with multiple recycler views inside. The inner recycler views are inserted dynamically. The issue Im having is that some items from some inner recycler views are going to other inner recycler views where there should be no items, like in the image below.
The top recycler view should not have those items while the bottom one is correct. I noticed that the items always glitch on the same recycler views, and after debugging I also noticed that on the glitched views, it doesnt even enter the sub adapter which makes it even weirder.
I should also mention that the sub recycler views are inserted based on volley requests. I make a request to an API and it generates the items. I have also checked and the API is giving the right response.
Fragment code (where the main recycler view is called):
RequestQueue requestQueue;
String URL;
RecyclerView catList;
CategoriesMainRecycleAdapter adapter;
List<String> cats;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_categories, container, false);
catList = v.findViewById(R.id.crv_main_categories);
cats = new ArrayList<>();
URL = /*Removed this part for privacy reasons*/;
Submit();
// Inflate the layout for this fragment
return v;
}
private void Submit()
{
requestQueue = Volley.newRequestQueue(getActivity());
StringRequest stringRequest = new StringRequest(Request.Method.GET, URL, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONArray jsonArray = new JSONArray(response);
for (int i = 0; i < jsonArray.length(); i++)
{
JSONObject cat = jsonArray.getJSONObject(i);
String a;
a = cat.getString("mCategoryName");
cats.add(a);
}
if (getActivity()!=null) {
adapter = new CategoriesMainRecycleAdapter(getActivity(), cats, (String) getText(R.string.website_link));
catList.setLayoutManager(new LinearLayoutManager(getActivity()));
catList.setAdapter(adapter);
}
} catch (JSONException e) {
Toast.makeText(getContext(), R.string.login_communication_error, Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getActivity(), R.string.login_communication_error, Toast.LENGTH_SHORT).show();
error.printStackTrace();
}
});
requestQueue.add(stringRequest);
}
Main Recycler Adapter Code (this is where the sub adapter are called):
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.title.setText(capitalizeLetters(mCats.get(position)));
holder.viewAll.setImageResource(R.drawable.ic_baseline_arrow_forward_24_black);
holder.lbl_error.setText(R.string.no_anime_with_category_error);
holder.lbl_error.setVisibility(View.INVISIBLE);
holder.viewAll.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
v.startAnimation(AnimationUtils.loadAnimation(mContext, R.anim.image_click));
Intent i = new Intent(mContext, anime_category.class);
i.putExtra("Category", mCats.get(position));
mContext.startActivity(i);
}
}
);
//Start the other recycler views
URL = /*Removed for privacy reasons*/;
String data = "{"+
"\"mCategoryName\":" + "\"" + mCats.get(position) + "\"" +
"}";
Submit(data, holder);
}
private void Submit(String data, ViewHolder holder)
{
final String savedata= data;
requestQueue = Volley.newRequestQueue(Objects.requireNonNull(mContext));
StringRequest stringRequest = new StringRequest(Request.Method.POST, URL, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
holder.lbl_error.setVisibility(View.INVISIBLE);
List<anime_class> animes = new ArrayList<>();
JSONArray jsonArray = new JSONArray(response);
for (int i = 0; i < jsonArray.length(); i++)
{
JSONObject anime = jsonArray.getJSONObject(i);
anime_class a = new anime_class();
a.setmNameEN(anime.getString("mNameEN"));
a.setmNameJP(anime.getString("mNameJP"));
a.setmDescription(anime.getString("mDescription"));
a.setmThumbnail(anime.getString("mThumbnail"));
a.setmEpisodeCount(anime.getInt("mEpisodeCount"));
a.setmOnGoing(anime.getBoolean("mOnGoing"));
//Add Categories
List<String> cats = new ArrayList<>();
JSONArray catArray = anime.getJSONArray("mCategories");
for (int i2 = 0; i2 < catArray.length(); i2++)
{
cats.add(catArray.get(i2).toString());
}
a.setmCategories(cats);
animes.add(a);
}
if (mContext!=null) {
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(
holder.rcv.getContext(),
LinearLayoutManager.HORIZONTAL,
false
);
linearLayoutManager.setInitialPrefetchItemCount(animes.size());
CategoriesSubRecycleAdapter adapter = new CategoriesSubRecycleAdapter(mContext, animes);
holder.rcv.setLayoutManager(linearLayoutManager);
holder.rcv.setAdapter(adapter);
holder.rcv.setRecycledViewPool(catAnime);
}
} catch (JSONException e) {
Toast.makeText(mContext, R.string.login_communication_error, Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
if(error.networkResponse.statusCode == 404)
{
holder.lbl_error.setVisibility(View.VISIBLE);
}
else
Toast.makeText(mContext, R.string.login_communication_error, Toast.LENGTH_SHORT).show();
error.printStackTrace();
}
}) {
#Override
public String getBodyContentType() {
return "application/json; charset=utf-8";
}
#Override
public byte[] getBody() throws AuthFailureError {
return savedata == null ? null : savedata.getBytes(StandardCharsets.UTF_8);
}
};
requestQueue.add(stringRequest);
}
Sub recycler adapter (this part seems to work fine based on some debugging I did):
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.title.setText(capitalizeLetters(mAnime.get(position).getmNameEN()));
Glide.with(mContext).load(mAnime.get(position).getmThumbnail()).into(holder.thumbnail);
holder.crv_.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(mContext, anime_page.class);
i.putExtra("mNameEN", mAnime.get(position).getmNameEN());
i.putExtra("mThumbnail", mAnime.get(position).getmThumbnail());
mContext.startActivity(i);
}
}
);
}

I found a trick that fixes the problem, but I dont believe its very optimized. On the Main Recycler Adapter, when I call the Submit method to get the data from the request, on the onErrorResponse I add 0 items, by creating an empty List and giving it to the adapter.
#Override
public void onErrorResponse(VolleyError error) {
if(error.networkResponse.statusCode == 404)
{
List<anime_class> animes = new ArrayList<>();
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(
holder.rcv.getContext(),
LinearLayoutManager.HORIZONTAL,
false
);
linearLayoutManager.setInitialPrefetchItemCount(animes.size());
CategoriesSubRecycleAdapter adapter = new CategoriesSubRecycleAdapter(mContext, animes);
holder.rcv.setLayoutManager(linearLayoutManager);
holder.rcv.setAdapter(adapter);
holder.rcv.getRecycledViewPool().clear();
holder.rcv.setRecycledViewPool(catAnime);
holder.rcv.setNestedScrollingEnabled(false);
adapter.notifyDataSetChanged();
holder.lbl_error.setVisibility(View.VISIBLE);
}
else
Toast.makeText(mContext, R.string.login_communication_error, Toast.LENGTH_SHORT).show();
error.printStackTrace();

Related

How to refresh recyclerView after changing data

I am working on developing an application that contains (recyclerView ) display member responses.I have a problem after a member posts a new comment the (recyclerView ) is not updated in real time.
How can I update the data (recyclerView ) after entering new data without the user exiting or closing the application؟
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{
private List<List_Data>list_data;
public MyAdapter(List<List_Data> list_data) {
this.list_data = list_data;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.list_data,parent,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
List_Data listData=list_data.get(position);
holder.txtname.setText(listData.gettext());
holder.txtmovie.setText(listData.getmovie_id());
}
#Override
public int getItemCount() {
return list_data.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
private TextView txtname,txtmovie,ImageView;
public ViewHolder(View itemView) {
super(itemView);
txtname=(TextView)itemView.findViewById(R.id.txt_name);
txtmovie=(TextView)itemView.findViewById(R.id.txt_moviename);
}
}
}
public class StatusFragment extends Fragment {
Button btn_send_comment;
EditText ETXT_comment;
String id;
private List<List_Data> list;
private RecyclerView rvy;
private MyAdapter adapter;
ImageView btn_add_comments;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setHasOptionsMenu(true);
View rootView = inflater.inflate(R.layout.status, container, false);
ETXT_comment = (EditText)rootView.findViewById(R.id.ETXT_comment);
btn_add_comments = (ImageView) rootView.findViewById(R.id.btn_add_comments);
btn_send_comment = (Button) rootView.findViewById(R.id.btn_send_comment);
Intent i = getActivity().getIntent();
final String movie_id = i.getStringExtra("id");
rvy=(RecyclerView)rootView.findViewById(R.id.recyclerview);
rvy.setHasFixedSize(true);
rvy.setLayoutManager(new LinearLayoutManager(getActivity().getApplicationContext()));
list=new ArrayList<>();
adapter=new MyAdapter(list);
getComment(movie_id);
//----------------Send Commant
btn_send_comment.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final String comment_text = ETXT_comment.getText().toString().trim();
if (comment_text.equals("")) {
} else {
//
final String REGISTER_URL = "http://0000000/Comment.php";
StringRequest stringRequest = new StringRequest(Request.Method.POST, REGISTER_URL,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
// getComment(movie_id);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getActivity().getApplicationContext(), error.toString(), Toast.LENGTH_LONG).show();
}
}) {
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
params.put("id", id);
params.put("comment", comment_text);
return params;
}
};
RequestQueue requestQueue = (RequestQueue) Volley.newRequestQueue(getActivity().getApplicationContext());
requestQueue.add(stringRequest);
}
}
});
//--------------------
return rootView;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
private void getComment(String id){
final String HI ="http://0000000/Cm.php?id=" + id ;
StringRequest stringRequest=new StringRequest(Request.Method.GET, HI, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject jsonObject=new JSONObject(response);
JSONArray array=jsonObject.getJSONArray("info");
for (int i=0; i<array.length(); i++ ){
JSONObject ob=array.getJSONObject(i);
List_Data listD=new List_Data(ob.getString("comment")
,ob.getString("name"));
list.add(listD);
// adapter.notifyItemRangeChanged(0, list_data.size());
// rv.removeAllViews();
}
rvy.setAdapter(adapter);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
RequestQueue requestQueue = Volley.newRequestQueue(getActivity().getApplicationContext());
requestQueue.add(stringRequest);
}
}
Also whene I put getComment(movie_id); into onResponse it's work but there are other problem it's show data Repeats in two times For each comment from user.
Did you try to add new comment into your list and then call the statement
adapter.notifyDataSetChanged()
Move rvy.setAdapter(adapter) from getComment() to onViewCreated()
Clear the list at the start of your getComment() method, add this line:
list.clear()
In your code, you appended the same items to this instance of List when you call .add(), hence, repeated elements appear.
After list.add(listD), call adapter.notifyDataSetChanged()
When you return a new comment, you didn't add the RecyclerView adapter list with the new comment. What you just did is updating the fragment list with the new comment, and the adapter has no idea about this list update.
So, modify you adapter to accept a new comment method and update the list with just the new inserted row using notifyItemInserted():
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{
private List<List_Data>list_data;
public MyAdapter(List<List_Data> list_data) {
this.list_data = list_data;
}
public addComment(List_Data comment) {
this.list_data.add(comment);
notifyItemInserted(list_data.size() - 1); // Updating adapter list
}
// ... rest of code
}
And in your getComment() use the new added adapter method when you get the response.
Notice the change in // <<<<<<<<<<<<<<<< Updating adapter list
private void getComment(String id){
final String HI ="http://0000000/Cm.php?id=" + id ;
StringRequest stringRequest=new StringRequest(Request.Method.GET, HI, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject jsonObject=new JSONObject(response);
JSONArray array=jsonObject.getJSONArray("info");
for (int i=0; i<array.length(); i++ ){
JSONObject ob=array.getJSONObject(i);
List_Data listD = new List_Data(ob.getString("comment")
,ob.getString("name"));
list.add(listD);
adapter.addComment(listD); // <<<<<<<<<<<<<<<< Updating adapter list
// rv.removeAllViews();
}
rvy.setAdapter(adapter);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
RequestQueue requestQueue = Volley.newRequestQueue(getActivity().getApplicationContext());
requestQueue.add(stringRequest);
}
finally don't forget to uncomment the usage of the getComment() within the btn_send_comment button listener.

How to update a recylerview elements inside a fragment whose data or property is changed (Room Database) from other activity

This is my code so far.
Fragment to which recylerview is attached.
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mRestaurantLandingPage = getActivity().findViewById(R.id.restaurant_activity);
// mRestaurantMenuRecyclerView = view.findViewById(R.id.restaurant_dish_item_recyler_view);
isAvailable = foodItemViewModel.getRestaurantId();
mRestaurantMenuRecyclerView = view.findViewById(R.id.restaurant_dish_recyler_view);
mRestaurantMenuRecyclerView.setHasFixedSize(true);
mRestaurantMenuRecyclerView.setLayoutManager(new LinearLayoutManager(getContext(),
LinearLayoutManager.VERTICAL, false));
if (!(isAvailable == mRestaurantId)) {
//InsertFoodIAsyncTask insertFoodIAsyncTask = new InsertFoodIAsyncTask();
//insertFoodIAsyncTask.execute(mRestaurantId);
insertFoodItems(mRestaurantId);
} else {
progressDialog.show();
mCategory = foodItemViewModel.getFoodCategories();
for (String category : mCategory) {
foodItems = new ArrayList<>();
foodItems.addAll(foodItemViewModel.getFoodByCategory(category));
RestaurantMenuCategoryModel menuCategoryModel = new RestaurantMenuCategoryModel(category, foodItems);
menuCategoryModels.add(menuCategoryModel);
mRestaurantMenuRecyclerView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
restaurantMenuCategoryAdapter = new RestaurantMenuCategoryAdapter(getContext(), menuCategoryModels,
mRestaurantLandingPage, foodItemViewModel);
mRestaurantMenuRecyclerView.setAdapter(restaurantMenuCategoryAdapter);
restaurantMenuCategoryAdapter.notifyDataSetChanged();
}
progressDialog.dismiss();
}
foodItemViewModel.getAllLiveFood().observeForever(new Observer<List<FoodItem>>() {
#Override
public void onChanged(#Nullable List<FoodItem> foodItemList) {
}
});
}
private void insertFoodItems(final int restaurantid) {
String mUrl = mApiUrl + "getRestaurantMenu?restaurantId=" + restaurantid;
Log.d("Inside Database ", "from Async Hope it works");
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(
mUrl,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
Log.d(TAG, "response length" + response.length());
for (int i = 0; i < response.length(); i++) {
try {
updateRoom Database
} catch (JSONException e) {
e.printStackTrace();
}
}upDateUI();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("JSON Response", error.toString());
}
});
RequestController.getInstance().addToRequestQueue(jsonArrayRequest);
}
private void upDateUI() {
mCategory = foodItemViewModel.getFoodCategories();
for (String category : mCategory) {
foodItems = new ArrayList<>();
foodItems.addAll(foodItemViewModel.getFoodByCategory(category));
RestaurantMenuCategoryModel menuCategoryModel = new RestaurantMenuCategoryModel(category, foodItems);
menuCategoryModels.add(menuCategoryModel);
mRestaurantMenuRecyclerView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
restaurantMenuCategoryAdapter = new RestaurantMenuCategoryAdapter(getContext(), menuCategoryModels,
mRestaurantLandingPage, foodItemViewModel);
mRestaurantMenuRecyclerView.setAdapter(restaurantMenuCategoryAdapter);
restaurantMenuCategoryAdapter.notifyDataSetChanged();
progressDialog.dismiss();
}
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup
container, #Nullable Bundle savedInstanceState) {
RestaurantMainActivity mRestaurantMainActivity = (RestaurantMainActivity) getActivity();
mQueryData = new ArrayList();
mQueryData = mRestaurantMainActivity.getIntentDataForFragments();
mRestaurantId = Integer.parseInt(mQueryData.get(0).toString());
foodItemViewModel = ViewModelProviders.of(this).get(FoodItemViewModel.class);
progressDialog = new ProgressDialog(getActivity());
view = inflater.inflate(R.layout.restaurant_menu_fragment, container, false);
return view;
}
Recyclerview where user can increase or decrease the food count.
holder.mAddToCart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
currentItem.setQuantityincart(1);
currentItem.setFoodincart(1);
foodItemViewModel.addFoodToCart(currentItem);
holder.mAddToCart.setVisibility(View.GONE);
holder.mAddButtonQuantityLinearLayout.setVisibility(View.VISIBLE);
holder.mFoodQuantityTextView.setText(String.valueOf(currentItem.getQuantityincart()));
showViewCart();
}
});
holder.mDecreaseQuantityButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
currentItem.setQuantityincart(currentItem.getQuantityincart() - 1);
if (currentItem.getQuantityincart() < 1) {
holder.mAddToCart.setVisibility(View.VISIBLE);
holder.mAddButtonQuantityLinearLayout.setVisibility(View.GONE);
currentItem.setFoodincart(0);
foodItemViewModel.decreaseFoodQuantity(currentItem);
}
holder.mFoodQuantityTextView.setText(String.valueOf(currentItem.getQuantityincart()));
foodItemViewModel.decreaseFoodQuantity(currentItem);
showViewCart();
}
});
holder.mIncreaseQuantityButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(mContext, "Before Decrease Click Current Food Item Count " + currentItem.getQuantityincart(), Toast.LENGTH_SHORT).show();
currentItem.setQuantityincart(currentItem.getQuantityincart() + 1);
foodItemViewModel.increaseFoodQuantity(currentItem);
holder.mFoodQuantityTextView.setText(String.valueOf(currentItem.getQuantityincart()));
Toast.makeText(mContext, "Before Decrease Click Current Food Item Count " + currentItem.getQuantityincart(), Toast.LENGTH_LONG).show();
showViewCart();
}
});
private void showViewCart() {
mSnackbar = Snackbar.make(mRestaurantLandingPage, "Total Cost ₹ " + foodItemViewModel.getTotalPrice(), Snackbar.LENGTH_INDEFINITE);
mSnackbar.getView().setBackgroundColor(ContextCompat.getColor(mContext, R.color.colorPrimary));
mSnackbar.setActionTextColor(mContext.getResources().getColor(R.color.colorBackground));
mSnackbar.setAction("View Cart", new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent mCartIntent = new Intent(mContext, CartItemsActivity.class);
mContext.startActivity(mCartIntent);
}
});
mSnackbar.show();
}`enter code here`
When User Clicks on snackbar user is routed to CartActivity where user can remove the item or increase or decrease the item which is passed.
Currently when User updates the value like increasing or decreasing or removing the food item from cart at that point in time I update the Room dB.
Next if user clicks on back button User is routed to Activity which holds the Fragment and the related recylerview but the recyler view still shows the old data like the quantity is not reset though in Db it is updated (Room DB).
I am not sure how exactly use Room DB live data and mutablelivedata in this scenario. Thanks in Advance a solution or guidance will be helpful

pull refresh error keep adding every time i pull

I trying to create a pull refresh.
every time I pull it.
Here's my code:
public class LatestGradeFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener{
List<ListGradeData> sectionList;
RecyclerView recyclerView;
SwipeRefreshLayout mSwipeRefreshLayout;
public static LatestGradeFragment newInstance() {
return new LatestGradeFragment();
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_latest_grade, container, false);
//RecyclerView+CardView for section
recyclerView = (RecyclerView) rootView.findViewById(R.id.display_recyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
sectionList = new ArrayList<>();
mSwipeRefreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.swipeRefreshSection);
mSwipeRefreshLayout.setOnRefreshListener(this);
mSwipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary,
android.R.color.holo_green_dark,
android.R.color.holo_orange_dark,
android.R.color.holo_blue_dark);
mSwipeRefreshLayout.post(new Runnable() {
#Override
public void run() {
mSwipeRefreshLayout.setRefreshing(true);
// Fetching data from server
loadSection();
}
});
return rootView;
}
#Override
public void onRefresh() {
loadSection();
}
private void loadSection() {
mSwipeRefreshLayout.setRefreshing(true);
StringRequest stringRequest = new StringRequest(Request.Method.GET, Constants.USER_GRADE,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
//converting the string to json array object
JSONArray array = new JSONArray(response);
//traversing through all the object
for (int i = 0; i < array.length(); i++) {
//getting product object from json array
JSONObject sections = array.getJSONObject(i);
//adding the product to product list
sectionList.add(new ListGradeData(
sections.getInt("id"),
sections.getString("section"),
sections.getString("level"),
sections.getString("schoolyear")
));
}
//creating adapter object and setting it to recyclerview
LatestGradeAdapter adapter = new LatestGradeAdapter(getActivity(), sectionList);
recyclerView.setAdapter(adapter);
} catch (JSONException e) {
e.printStackTrace();
}
// Stopping swipe refresh
mSwipeRefreshLayout.setRefreshing(false);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// Stopping swipe refresh
mSwipeRefreshLayout.setRefreshing(false);
}
});
//adding our stringrequest to queue
Volley.newRequestQueue(getActivity().getApplicationContext()).add(stringRequest);
}
#Override
public String toString() {
return "LatestGradeFragment ";
}
}
I'm new in android/java could anyone help me.
Inside respone of api you have to clear list first, so it will never repeat data. Your code inside response inside try block should be:
if(sectionList!=null) {
sectionlist.clear();
}
remove this part, its unnecessary
mSwipeRefreshLayout.post(new Runnable() {
#Override
public void run() {
mSwipeRefreshLayout.setRefreshing(true);
// Fetching data from server
loadSection();
}
});
and you should create LatestGradeAdapter as globe variable, just notify data change whenever you get new data from server

int android.support.v7.widget.GridLayoutManager.getItemCount()' on a null object reference

here getItemCount() not null, but here getlayoutmanager is null. plz help me to solved this. i'm trying to loadmore data when user scroll down recyclerview at end of scrolling load another data so on. This Error occurred in adapter.
here getLayoutManager() is get null:
final GridLayoutManager gridLayoutManager = (GridLayoutManager) recyclerView.getLayoutManager();
My Adapter code:
public class ImageAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context mCtx;
private ImageView link;
private boolean isLoading;
private List<Image> imageList;
private int visibleThreshold = 5;
private final int VIEW_TYPE_ITEM = 0;
private final int VIEW_TYPE_LOADING = 1;
private int lastVisibleItem, totalItemCount;
private OnLoadMoreListener onLoadMoreListener;
public ImageAdapter(RecyclerView recyclerView, List<Image> imageList, Context mCtx) {
this.imageList = imageList;
this.mCtx = mCtx;
final GridLayoutManager gridLayoutManager = (GridLayoutManager) recyclerView.getLayoutManager();
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
Log.d(TAG, "Tj_getItemCount" + getItemCount());
Log.d(TAG, "Tj_linearLayoutManager" + gridLayoutManager);
totalItemCount = gridLayoutManager.getItemCount();
lastVisibleItem = gridLayoutManager.findLastVisibleItemPosition();
if (!isLoading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
if (onLoadMoreListener != null) {
onLoadMoreListener.onLoadMore();
}
isLoading = true;
}
}
});
}
public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
this.onLoadMoreListener = mOnLoadMoreListener;
}
#Override
public int getItemViewType(int position) {
return imageList.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_ITEM) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View v = inflater.inflate(R.layout.list_items, parent, false);
ViewHolder vh = new ViewHolder(v);
return vh;
} else if (viewType == VIEW_TYPE_LOADING) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_loading, parent, false);
LoadingViewHolder vh1 = new LoadingViewHolder(view);
return vh1;
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
if (holder instanceof ViewHolder) {
final Image image = imageList.get(position);
final String imgUrl = image.getThumb();
link.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(v.getContext(), ViewImage.class);
intent.putExtra("URL", imgUrl);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
v.getContext().startActivity(intent);
}
});
Glide.with(mCtx).load(imgUrl).into(link);
} else if (holder instanceof LoadingViewHolder) {
LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder;
loadingViewHolder.progressBar.setIndeterminate(true);
}
}
#Override
public int getItemCount() {
return imageList == null ? 0 : imageList.size();
}
public void setLoaded() {
isLoading = false;
}
private class LoadingViewHolder extends RecyclerView.ViewHolder {
public ProgressBar progressBar;
LoadingViewHolder(View view) {
super(view);
progressBar = view.findViewById(R.id.progressBar1);
}
}
class ViewHolder extends RecyclerView.ViewHolder {
ViewHolder(View v) {
super(v);
link = v.findViewById(R.id.link);
}
}
}
My Activity code:
public class MainActivity extends AppCompatActivity {
//the URL having the json data https://api.unsplash.com/search/photos?query=canada&client_id=8b0a3f8ddb23f80f16303601c12664119e27c2d26a6fc7b43bcba68d5c35f73c
// private static final String JSON_URL = "https://api.unsplash.com/photos/random?count=25&client_id=8b0a3f8ddb23f80f16303601c12664119e27c2d26a6fc7b43bcba68d5c35f73c";
// private static final String JSON_URL = "https://api.unsplash.com/photos/?client_id=8b0a3f8ddb23f80f16303601c12664119e27c2d26a6fc7b43bcba68d5c35f73c";
int i = 2;
Image hero;
String query;
List<Image> imageList;
RecyclerView listView;
private static String JSON_URL;
private static final String TAG = "Tj";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
//initializing listview and hero list
listView = findViewById(R.id.listView);
imageList = new ArrayList<>();
Intent intent = getIntent();
query = intent.getStringExtra("category");
JSON_URL = "https://api.unsplash.com/search/photos?query=" + query + "&client_id=8b0a3f8ddb23f80f16303601c12664119e27c2d26a6fc7b43bcba68d5c35f73c&page=1";
Log.d(TAG, "Query" + JSON_URL);
loadHeroList();
}
private void loadHeroList() {
//getting the progressbar
final ProgressBar progressBar = findViewById(R.id.progressBar);
//making the progressbar visible
progressBar.setVisibility(View.VISIBLE);
//creating a string request to send request to the url
StringRequest jsonArrayRequest = new StringRequest(Request.Method.GET, JSON_URL,
new Response.Listener<String>() {
// JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(
// Request.Method.GET,
// JSON_URL,
// null,
// new Response.Listener<JSONArray>() {
#Override
public void onResponse(String response) {
//hiding the progressbar after completion
progressBar.setVisibility(View.INVISIBLE);
try {
//getting the whole json object from the response
JSONObject obj = new JSONObject(response);
//we have the array named hero inside the object
//so here we are getting that json array
JSONArray heroArray = obj.getJSONArray("results");
//now looping through all the elements of the json array
for (int i = 0; i < heroArray.length(); i++) {
//getting the json object of the particular index inside the array
JSONObject jsonObject = heroArray.getJSONObject(i);
JSONObject jsonObject1 = jsonObject.getJSONObject("urls");
//creating a hero object and giving them the values from json object
hero = new Image(jsonObject.getString("id"),
jsonObject.getString("color"),
jsonObject1.getString("full"));
//adding the hero to herolist
imageList.add(hero);
}
//creating custom adapter object
final ImageAdapter adapter = new ImageAdapter(listView, imageList, getApplicationContext());
listView.setHasFixedSize(true);
// use a grid layout manager
listView.setLayoutManager(new GridLayoutManager(MainActivity.this, 2));
//adding the adapter to listview
listView.setAdapter(adapter);
adapter.setOnLoadMoreListener(new OnLoadMoreListener() {
#Override
public void onLoadMore() {
if (imageList.size() <= 20) {
imageList.add(null);
adapter.notifyItemInserted(imageList.size() - 1);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
imageList.remove(imageList.size() - 1);
adapter.notifyItemRemoved(imageList.size());
JSON_URL = "https://api.unsplash.com/search/photos?query=" + query + "&client_id=8b0a3f8ddb23f80f16303601c12664119e27c2d26a6fc7b43bcba68d5c35f73c&page=" + i;
Log.d(TAG, "QueryLoadMore" + JSON_URL);
i++;
StringRequest jsonArrayRequest = new StringRequest(Request.Method.GET, JSON_URL,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
//hiding the progressbar after completion
progressBar.setVisibility(View.INVISIBLE);
try {
//getting the whole json object from the response
JSONObject obj = new JSONObject(response);
//we have the array named hero inside the object
//so here we are getting that json array
JSONArray heroArray = obj.getJSONArray("results");
//now looping through all the elements of the json array
for (int i = 0; i < heroArray.length(); i++) {
//getting the json object of the particular index inside the array
JSONObject jsonObject = heroArray.getJSONObject(i);
JSONObject jsonObject1 = jsonObject.getJSONObject("urls");
//creating a hero object and giving them the values from json object
hero = new Image(jsonObject.getString("id"),
jsonObject.getString("color"),
jsonObject1.getString("full"));
//adding the hero to herolist
imageList.add(hero);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//displaying the error in toast if occurrs
Toast.makeText(getApplicationContext(), error.getMessage(), Toast.LENGTH_SHORT).show();
}
});
//creating a request queue
RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this);
//adding the string request to request queue
requestQueue.add(jsonArrayRequest);
// imageList.add(hero);
// }
adapter.notifyDataSetChanged();
adapter.setLoaded();
}
}, 5000);
} else {
Toast.makeText(MainActivity.this, "Loading data completed", Toast.LENGTH_SHORT).show();
}
}
});
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//displaying the error in toast if occurrs
Toast.makeText(getApplicationContext(), error.getMessage(), Toast.LENGTH_SHORT).show();
}
});
//creating a request queue
RequestQueue requestQueue = Volley.newRequestQueue(this);
//adding the string request to request queue
requestQueue.add(jsonArrayRequest);
}
}
You never set any kind of LayoutManager to your listView.
You must set the layout manager before creating your custom adapter object.
You can set it by calling: recyclerView.setLayoutManager(new GridLayoutManager(this, numberOfColumns)); Then you are able to get it later in your ImageAdapter class.

Parsing JSON news in Android

I am trying to display news received from a json data source. But, I am getting an error when I try to parse the data.
The json data looks something like this:
click here to view
Here is the class I wrote for parsing :
public class FragmentUniversityNews extends Fragment {
private String TAG = FragmentUniversityNews.class.getSimpleName();
private static final String endpoint = "https://api.myjson.com/bins/18smd";
private static final String endpoint_final = "http://srm-news-bot.herokuapp.com";
private SwipeRefreshLayout swipeRefreshLayout;
private SimpleStringRecyclerViewAdapter mAdapter;
private JsonObjectRequest req;
String[] titles = new String[15];
String[] snips = new String[15];
String[] links = new String[15];
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
RecyclerView recyclerView;
View rootView = inflater.inflate(R.layout.fragment_university_news, container, false);
//((ActivityMain) getActivity()).showFloatingActionButton();
recyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_view_university);
swipeRefreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.swipe_refresh_layout);
swipeRefreshLayout.setColorSchemeResources(R.color.red500, R.color.black, R.color.google_blue_900);
mAdapter = new SimpleStringRecyclerViewAdapter(getContext(), titles, snips, links);
// Calling another function which has the details
setupRecyclerView(recyclerView);
// Make it look like something is happening
swipeRefreshLayout.setRefreshing(true);
// Make the request!
makeJSONRequest();
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
// onRefresh action here
swipeRefreshLayout.setRefreshing(true);
makeJSONRequest();
}
});
return rootView;
}
private void setupRecyclerView(RecyclerView recyclerView) {
recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext()));
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(mAdapter);
}
public void makeJSONRequest() {
req = new JsonObjectRequest(endpoint_final,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d(TAG, response.toString());
// Getting JSON Array node
JSONArray newsItems = response.getJSONArray("newsItems");
// UI
try {
for (int j = 0; j < newsItems.length(); j++) {
JSONObject newsItem = newsItems.getJSONObject(j);
titles[j] = newsItem.getString("title");
snips[j] = newsItem.getString("snip");
links[j] = newsItem.getString("link");
}
swipeRefreshLayout.setRefreshing(false);
} catch (JSONException e) {
Log.e(TAG, "Json parsing error: " + e.getMessage());
Toast.makeText(getContext(), "JSON Parsing error", Toast.LENGTH_LONG).show();
} mAdapter.notifyDataSetChanged();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG, "Error: " + error.getMessage());
Toast.makeText(getContext(), "Error Receiving News", Toast.LENGTH_LONG).show();
}
});
// Adding request to request queue
InitializeVolley.getInstance().addToRequestQueue(req);
}
public static class SimpleStringRecyclerViewAdapter extends RecyclerView.Adapter<SimpleStringRecyclerViewAdapter.ViewHolder> {
private String[] mTitles, mSnips, mLinks;
private Context mContext;
public static class ViewHolder extends RecyclerView.ViewHolder {
public final View mView;
public final TextView mTextViewTitle, mTextViewSnip;
public ViewHolder(View view) {
super(view);
mView = view;
mTextViewTitle = (TextView) view.findViewById(R.id.univ_news_title);
mTextViewSnip = (TextView) view.findViewById(R.id.univ_news_snip);
}
}
// Constructor
public SimpleStringRecyclerViewAdapter(Context context, String[] Titles, String[] Snips, String[] Links) {
mContext = context;
mTitles = Titles;
mSnips = Snips;
mLinks = Links;
}
public String getTitleAt(int position) {
return mTitles[position];
}
public String getSnipAt(int position) {
return mSnips[position];
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.card_view_univ, parent, false);
return new ViewHolder(itemView);
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
holder.mTextViewTitle.setText(getTitleAt(position));
holder.mTextViewSnip.setText(getSnipAt(position));
holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//startScan();
Context context = v.getContext();
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(mLinks[holder.getAdapterPosition()]));
context.startActivity(intent);
}
});
}
#Override
public int getItemCount() {
return mTitles.length;
}
}
}
The error I am getting in Android Studio is at the line "JSONArray newsItems = response.getJSONArray("newsItems");",
It's saying
Unhandled exception:org.json.JSONException
When I move JSONArray newsItems = response.getJSONArray("newsItems"); in "try" block, it says
`Cannot resolve constructor 'JsonObjectRequest(java.lang.String, anonymous com.android.volley.Response.Listener<org.json.JSONObject>, anonymous com.android.volley.Response.ErrorListener)'`
Isolating just the parsing part out of your code I couldn't reproduce the error, here is my code:
String jsonStr = "";//TODO insert JSON sample from link
JSONObject jsonObj = null;
try {
jsonObj = new JSONObject(jsonStr);
JSONArray newsItems = jsonObj.getJSONArray("newsItems");
for (int j = 0; j < newsItems.length(); j++) {
JSONObject newsItem = newsItems.getJSONObject(j);
Log.d(TAG,
"Title: " +newsItem.getString("title") +
"\nSnip: " + newsItem.getString("snip") +
"\nLink: " +newsItem.getString("link")
);
}
} catch (JSONException e) {
e.printStackTrace();
}
There is either an error while retrieving the content directly as a JSONObject, or anything unrelated to the JSON parsing.
To help you out further it would be great to have an errorlog, as mentioned by Kris Roofe already.
I solved my problem by adding "null" in the JSONObjectRequest function. I didn't understand why.
public void makeJSONRequest() {
req = new JsonObjectRequest(endpoint_final, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d(TAG, response.toString());

Categories

Resources