How to change an image in RecyclerView locally using drawable - java

I'm trying to change the image in a RecyclerView with a local drawable image. So in the project the RecyclerView is getting data from a local database, when a boolean column gets true, it should change into a tick. My item view looks like this.
And when the column is true, that clock symbol changes to tick. Here is the code which I tried:
My Adapter code:
public class HawbListAdapter extends RecyclerView.Adapter<HawbListAdapter.MyViewHolder> {
private Context context;
private ArrayList<HawbLists> hawbLists;
private DatabaseHelper mDatabaseHelper;
public HawbListAdapter(Context context, ArrayList<HawbLists> hawbLists) {
this.context = context;
this.hawbLists = hawbLists;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.hawb_list, parent, false);
return new MyViewHolder(v);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
holder.Hcode.setText(hawbLists.get(position).getHawbCode());
holder.name.setText(hawbLists.get(position).getName());
if (hawbLists.get(position).isTick()) {
holder.timeImage.setImageResource(R.drawable.ic_right);
}
//Picasso.get().load(hawbLists.get(position).isTick()).into(holder.timeImage);
//holder.timeImage.setImageResource(R.drawable.ic_right);
}
#Override
public int getItemCount() {
return hawbLists.size();
}
public static class MyViewHolder extends RecyclerView.ViewHolder {
private TextView Hcode;
private TextView name;
private ImageView timeImage;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
Hcode = itemView.findViewById(R.id.hawbCode12345);
name = itemView.findViewById(R.id.name_hawb_list);
timeImage = itemView.findViewById(R.id.timeImage);
}
}
}
even when I'm using this
if (hawbLists.get(position).isTick()) {
holder.timeImage.setImageResource(R.drawable.ic_right);
}
and one of the items is true, it is still showing the same clock (wait) symbol, but If I use this:
if (!hawbLists.get(position).isTick()) {
holder.timeImage.setImageResource(R.drawable.ic_right);
}
then all of them regardless of true or false turn into tick mark. Unable to figure out where I'm doing it wrong.

Try this:
if (hawbLists.get(position).isTick()){
holder.timeImage.setImageResource(R.drawable.ic_right);
} else {
holder.timeImage.setImageResource(R.drawable.ic_not_ticked);
}
Do you know about the concept of recycling? Look at your list in the device and see how many rows you have! Now add up one (as swap view) and it's all the views you have. It means no matter how many entries you have (hawbLists.size()), all of them are created/recycled when you scroll. So you have to consider all the possible cases of your item children. Because otherwise a recycled view won't change the view state and likely will show irrelevant behavior.

Related

Pass data from recyclerView to another in fragment

I want to pass data from recyclerview to another both in fragment, first adapter
for display item, and second adapter for basket fragment that want to put selected item in.
Adapter I want to take data from:
public class FruitItemAdapter extends RecyclerView.Adapter<FruitItemAdapter.viewHolder> {
ArrayList<FruitItem> fruitItems = new ArrayList<>();
private Context context;
public FruitItemAdapter(ArrayList<FruitItem> fruitItems, Context context) {
this.fruitItems = fruitItems;
this.context = context;
notifyDataSetChanged();
}
public FruitItemAdapter() {
}
#NonNull
#Override
public viewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view =
LayoutInflater.from(parent.getContext()).inflate(R.layout.fruits_item,parent,false);
viewHolder viewHolder = new viewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull viewHolder holder, int position) {
final FruitItem data_position = fruitItems.get(position);
holder.fruit_img.setImageResource(fruitItems.get(position).getFruit_img());
holder.fruit_name.setText(fruitItems.get(position).getFruit_name());
holder.fruit_price.setText(fruitItems.get(position).getFruit_price());
}
#Override
public int getItemCount() {
return fruitItems.size();
}
public void setfruitItem(ArrayList<FruitItem> fruitItems) {
this.fruitItems = fruitItems;
}
public static class viewHolder extends RecyclerView.ViewHolder {
private ImageView fruit_img;
private TextView fruit_price, fruit_name;
public viewHolder(#NonNull View itemView) {
super(itemView);
fruit_img = itemView.findViewById(R.id.fruit_img);
fruit_price = itemView.findViewById(R.id.fruit_price);
fruit_name = itemView.findViewById(R.id.fruit_name)
}
}
}
this is adapter for basket fragment that I want to put the data in
public class Basket_Adapter extends RecyclerView.Adapter<Basket_Adapter.viewHolder> {
private Context context;
ArrayList<FruitItem> fruitItems = new ArrayList<>();
public Basket_Adapter(Context context, ArrayList<FruitItem> fruitItems) {
this.context = context;
this.fruitItems = fruitItems;
notifyDataSetChanged();
}
public Basket_Adapter(){
}
#NonNull
#Override
public Basket_Adapter.viewHolder onCreateViewHolder(#NonNull ViewGroup parent, int
viewType) {
View view=LayoutInflater.from(parent.getContext()).inflate(R.layout.fruits_item,parent,false);
viewHolder viewHolder = new viewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull Basket_Adapter.viewHolder holder, int position) {
holder.fruit_img.setImageResource(fruitItems.get(position).getFruit_img());
holder.fruit_name.setText(fruitItems.get(position).getFruit_name());
holder.fruit_price.setText(fruitItems.get(position).getFruit_price());
}
#Override
public int getItemCount() {
return fruitItems.size();
}
public void setfruitItem(ArrayList<FruitItem> fruitItems) {
this.fruitItems = fruitItems;
}
public class viewHolder extends RecyclerView.ViewHolder {
private ImageView fruit_img;
private TextView fruit_name;
private TextView fruit_price;
public viewHolder(#NonNull View itemView) {
super(itemView);
fruit_img = itemView.findViewById(R.id.fruit_img);
fruit_name = itemView.findViewById(R.id.fruit_name);
fruit_price = itemView.findViewById(R.id.fruit_price);
}
}
Now, what I can use to pass data between them.
You can achieve this by using the delegation pattern. Basically you create an interface relative to the first adapter (you can put it inside the adapter class or outside depending on your coding style) and you require it as an argument inside the adapter constructor like this:
public class FruitItemAdapter extends RecyclerView.Adapter<FruitItemAdapter.viewHolder> {
private Delegate delegate;
ArrayList<FruitItem> fruitItems = new ArrayList<>();
private Context context;
public FruitItemAdapter(Delegate delegate, ArrayList<FruitItem> fruitItems, Context context) {
this.delegate = delegate;
this.fruitItems = fruitItems;
this.context = context;
notifyDataSetChanged();
}
...
interface Delegate {
public void passItem(FruitItem item);
}
}
As you can see the interface has the method you need, but there's no implementation yet.
In this class you can just pretend that your delegate works and do the magic for you, for example by setting a click listener on the root view of your item in onBindViewHolder that will call delegate.passItem(fruitItems.get(position)) on each click.
Let's move on to the fragment.
Here is the key part. The fragment must implement the interface we just created by overriding its methods. Like so:
class ExampleFragment extends Fragment implements FruitItemAdapter.Delegate {
...
#Override
public void passItem(FruitItem item) {
// here you pass the item in a list inside
// the shared preferences.
}
}
For your case the best way is to store your items in a database or in the shared preferences. We go with the shared preferences because is simpler, but keep in mind that shared preferences have limited memory capacity and you should use a database like Room instead.
Inside the override method you pass your item to a list stored in the shared preferences. Since your item is not a primitive object i suggest you to look at this answer that show how to store complex object as a string:
https://stackoverflow.com/a/18463758/18740763.
In your case the object that needs to be serialized is an Array or a List of objects.
Every time you need to put a new object in the list you need to follow these steps:
get the list from shared preferences
deserialize it
add the new item
serialize it again
put it back in the shared preferences under the same key
If you stored your items correctly now you should be able to access the shared list in every fragment or activity of your application. So simply access your list from the fragment that implements the second adapter, deserialize it, just addAll() the items the the adapter list and notifyDataSetChanged().

Displaying User Images to CardView from Firebase using Picasso Not Working

I am trying to display images from my Firebase storage and realtime database to a CardView in my Android application. I have saved the images to the Firebase Storage and as a Url node under the specific user (dog). The CardView displays the dogs registered under each owner and each dog has its own profile picture essentially.. which I would like to display on the UI.
I am using Picasso as it was used within the tutorial I found, and seemed to be working, however it is trying to find 'context' within my DogUserAdapter, which is returning null. I wasn't previously using Context context as I am utilising a callback function instead on this particular CardView. What else can I use here to display the image from the database?
DogUserAdapter
public class DogUserAdapter extends FirebaseRecyclerAdapter<Dog, DogUserAdapter.DogViewHolder> {
private DogCallback dogCallback;
private Context context;
public DogUserAdapter(#NonNull FirebaseRecyclerOptions<Dog> options, #NonNull final DogCallback dogCallback) {
super(options);
this.dogCallback = dogCallback;
this.context = context;
}
#Override
protected void onBindViewHolder(#NonNull DogViewHolder holder, int position, #NonNull Dog model) {
holder.dogName.setText(model.getName());
Picasso.with(context)
.load(model.getImageUrl())
.into(holder.dogImage);
holder.cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dogCallback.onCardViewClick(model);
}
});
}
#NonNull
#Override
public DogViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.dog, parent, false);
return new DogUserAdapter.DogViewHolder(view);
}
public class DogViewHolder extends RecyclerView.ViewHolder {
TextView dogName;
ImageView dogImage;
CardView cardView;
public DogViewHolder(#NonNull View itemView) {
super(itemView);
dogName = itemView.findViewById(R.id.dogName);
dogImage = itemView.findViewById(R.id.dogImage);
cardView = itemView.findViewById(R.id.card_view_dog);
}
}
public interface DogCallback{
void onCardViewClick(final Dog dog);
}
}
CardView
Firebase Hierarchy
Patrick is right. You do not need context for picasso
Picasso.get().load(url).into(imageView);

How to store checkbox statuses after I exit app?

I have tab layout (3 fragments) with recyclerview and checkboxes for every fragment. I set up onClickListener, but after I exit my app, checkbox statuses are reseted. I tried some solutions I found online some solutions (about shared preferences) but neither work for me. Maybe I implement it wrong. Can you help me ?
Also if need, I can share with you my Fragment file.
recyclerview java:
public class RecyclerViewAdapter extends RecyclerView.Adapter <RecyclerViewAdapter.MyViewHolder>{
Context mContext;
List<RecTab1> mData;
public RecyclerViewAdapter(Context mContext, List<RecTab1> mData) {
this.mContext = mContext;
this.mData = mData;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v ;
v = LayoutInflater.from(mContext).inflate(R.layout.item_tab1,parent,false);
MyViewHolder vHolder = new MyViewHolder(v);
return vHolder;
}
#Override
public void onBindViewHolder(#NonNull final MyViewHolder holder, int position) {
holder.tv_name.setText(mData.get(position).getName());
holder.tv_subName.setText(mData.get(position).getSubName());
holder.cb_checkbox.setChecked(mData.get(position).getSelected());
holder.cb_checkbox.setTag(position);
holder.cb_checkbox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Integer pos = (Integer) holder.cb_checkbox.getTag();
Toast.makeText(mContext, mData.get(pos).getName() + " clicked!", Toast.LENGTH_LONG).show();
if (mData.get(pos).getSelected()) {
mData.get(pos).setSelected(false);
} else {
mData.get(pos).setSelected(true);
}
}
});
}
#Override
public int getItemCount() {
return mData.size();
}
public static class MyViewHolder extends RecyclerView.ViewHolder{
private TextView tv_name;
private TextView tv_subName;
private CheckBox cb_checkbox;
public MyViewHolder (View itemView){
super (itemView);
tv_name = (TextView) itemView.findViewById(R.id.Item1Name);
tv_subName = (TextView) itemView.findViewById(R.id.Item1SubName);
cb_checkbox = (CheckBox) itemView.findViewById(R.id.CheckboxID);
}
}
}
item java:
public class RecTab1 {
private String Name;
private String SubName;
private boolean isSelected;
public RecTab1(){
}
public RecTab1 (String name, String subName){
Name = name;
SubName = subName;
}
public String getName() {
return Name;
}
public String getSubName() {
return SubName;
}
public void setName(String name) {
Name = name;
}
public void setSubName(String subName) {
SubName = subName;
}
public boolean getSelected() {
return isSelected;
}
public void setSelected(boolean selected) {
isSelected = selected;
}
}
There are basically 2 kinds of persistence:
Temporary persistence (Scope: can be only used inside Activity/Fragment)
Long-term persistence (Scope: goes beyond the lifecycle of Activity/Fragment)
I think, you implemented first technique by creating Rect1 object somewhere(I assumed you did not save them in the database as I did not see those lines of code) and later trying to access the values when needed elsewhere. But, those variables will be destroyed and recreated later on destroying and recreating of the fragment when you would switch between tabs in your TabLayout.
What you need is the second one.
There are many versions of this kind of persistence as :
- SharedPreferences
- Sqlite Database
- Online Database such as Firebase
For eg: In your case, if you have few numbers of tabs which again has few numbers of information to persist then, you can use SharedPreferences. If there is larger number of tabs and in turn larger number of information to persist then, using Sqlite Database is better. See this link about using Room to save data in Sqlite
Now using SharedPreferences, you can save the checked state of the CheckBox into the preference file in the onCheckChangedListener method as:
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(mContext).inflate(R.layout.item_tab1, parent, false);
Checkbox cb_checkbox = v.findViewById(R.id.CheckboxID);
cb_checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mContext.getSharedPreferences("com.example.yourapp.SAVED_STATE", Context.MODE_PRIVATE)
.edit()
.putBoolean("cb_checkbox", isChecked)
.apply();
}
});
I set the onCheckChangedListener in the onCreateViewHolder because mContext was available. You could have also done in inside the MyViewHolder class passing the Context object in the constructor of MyViewHolder.It is NOT recommended to set listener in onBindViewHolder() because it is called multiple times during binding so, there would be recurrent setting of listener even for those cb_checkbox in the MyViewHolder object whose listeners are already set.
Now, to retrieve the checked state of the cb_checkbox, we will see in our SharedPreferences to find information if it is saved previously as :
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
// your other binding code
// code for binding previous state of the checkbox if is saved otherwise false as a default
boolean checkedState = mContext.getSharedPreferences("com.example.yourapp.SAVED_STATE", MODE_PRIVATE)
.getBoolean("cb_checkbox", false);
holder.cb_checkbox.setChecked(checkedState);
}

Removing an item from a nested RecyclerView

I've been duelling with this problem for a good few hours now. I have a nested RecyclerView (i.e. a RecyclerView that encompasses an inner Recycler view). Both the parent and child recycler view's are dynamic. The problem I encounter is that I cannot find a way to correctly notify the child (inner) recycler view when a CRUD, in particular a delete, occurs. At first it works ok, but then I get all sorts of random errors from "You must be a direct descend view" or getAdapterPosition returning -1 or just simply incorrect positions. I think my implementation is pretty standard so I ask what is the correct way to notify the inner recycler view.
I am pretty close to returning to my former implementation which involved an array of fragments each containing a recycling view, but I question about the performance of such design. My code is as follows:
Parent RecyclerView
public class RecipeRecyclerAdapter extends RecyclerView.Adapter<RecipeRecyclerAdapter.ViewHolder>
{
public interface OnRecipeRecyclerListener
{
//--------------------------- Proxy methods for OnDishRecyclerListener -----------------
void renameDish(int DishPosition, int RecipePosition);
void deleteDish(int DishPosition, int RecipePosition);
//--------------------------- OnRecipeRecyclerListener methods ----------------------------
void deleteRecipe(int RecipePosition);
void renameRecipe(int RecipePosition);
}
//Recycler Pool and tools
private RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();
//Recycler Parameters
private ArrayList<Recipe> allRecipes;
private Context context;
//Listener
#Setter
private OnRecipeRecyclerListener onRecipeRecyclerListener;
public RecipeRecyclerAdapter(Context context, ArrayList<Recipe> allRecipes)
{
this.allRecipes = allRecipes;
this.context = context;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType)
{
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_Recipe, parent, false);
return new RecipeRecyclerAdapter.ViewHolder(view, onRecipeRecyclerListener, context);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position)
{
Recipe Recipe = allRecipes.get(position);
holder.RecipeName.setText(Utils.colourFirstLetter(context, Recipe.getRecipeName(), R.color.progressFxBar));
holder.RecipeDate.setText(Utils.getDate(Recipe.getTimestamp()));
// Create layout manager with initial prefetch item count
LinearLayoutManager layoutManager = new LinearLayoutManager(
holder.DishsRecycler.getContext(),
LinearLayoutManager.VERTICAL,
false
);
layoutManager.setInitialPrefetchItemCount(Recipe.getDishs().size());
DishRecyclerAdapter DishsRecyclerAdapter = new DishRecyclerAdapter(Recipe.getDishs(), holder, context);
holder.DishsRecycler.setLayoutManager(layoutManager);
holder.DishsRecycler.setAdapter(DishsRecyclerAdapter);
holder.DishsRecycler.setRecycledViewPool(viewPool);
}
#Override
public int getItemCount()
{
return allRecipes.size();
}
static class ViewHolder extends RecyclerView.ViewHolder implements DishRecyclerAdapter.OnDishRecyclerListener
private OnRecipeRecyclerListener onRecipeRecyclerListener;
private Context context;
TextView RecipeName, RecipeDate;
ImageView addDish;
//The Dishs Recycler
RecyclerView DishsRecycler;
public ViewHolder(#NonNull View itemView, OnRecipeRecyclerListener onRecipeRecyclerListener, Context context)
{
super(itemView);
this.onRecipeRecyclerListener = onRecipeRecyclerListener;
this.context = context;
RecipeName = itemView.findViewById(R.id.RecipeName);
RecipeDate = itemView.findViewById(R.id.RecipeDate);
addDish = itemView.findViewById(R.id.addDish);
DishsRecycler = itemView.findViewById(R.id.DishsRecyclerView);
loadListeners(itemView);
}
private void loadListeners(#NonNull View initView)
{
RecipeName.setOnClickListener(v ->
{
PopupMenu popup = new PopupMenu(context, v);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.Recipe_floating_menu, popup.getMenu());
popup.show();
popup.setOnMenuItemClickListener(item ->
{
switch (item.getItemId())
{
case R.id.menuDeleteRecipe:
onRecipeRecyclerListener.deleteRecipe(getAdapterPosition());
return true;
case R.id.menuRenameRecipe:
onRecipeRecyclerListener.renameRecipe(getAdapterPosition());
return true;
case R.id.menuRecipeProps:
onRecipeRecyclerListener.RecipeProps(getAdapterPosition());
return true;
default:
return false;
}
});
});
addDish.setOnClickListener(v ->
{
onRecipeRecyclerListener.addDish(getAdapterPosition());
});
}
//******************************* OnDishRecyclerListener *******************************
#Override
public void renameDish(int position)
{
onRecipeRecyclerListener.renameDish(position, getAdapterPosition());
}
#Override
public void deleteDish(int position)
{
onRecipeRecyclerListener.deleteDish(position, getAdapterPosition());
}
}
}
Child (inner) RecyclerView
public class DishRecyclerAdapter extends RecyclerView.Adapter<DishRecyclerAdapter.ViewHolder>
{
public interface OnDishRecyclerListener
{
void renameDish(int position);
void deleteDish(int position);
}
private OnDishRecyclerListener onDishRecyclerListener;
private ArrayList<Dish> allDishs;
private Context context;
public DishRecyclerAdapter(ArrayList<Dish> allDishs, OnDishRecyclerListener onDishRecyclerListener, Context context)
{
this.onDishRecyclerListener = onDishRecyclerListener;
this.allDishs = allDishs;
this.context = context;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType)
{
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_Dishs, parent, false);
return new ViewHolder(context, view, onDishRecyclerListener);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position)
{
Dish Dish = allDishs.get(position);
holder.DishName.setText(Dish.getDishName());
}
#Override
public int getItemCount()
{
return allDishs.size();
}
public class ViewHolder extends RecyclerView.ViewHolder
{
private Context context;
TextView DishName; //plus a bunch of other Views I just removed for the sake of simplicity
OnDishRecyclerListener onDishRecyclerListener;
public ViewHolder(Context context, #NonNull View itemView, OnDishRecyclerListener onDishRecyclerListener)
{
super(itemView);
this.context = context;
DishName = itemView.findViewById(R.id.DishName);
this.onDishRecyclerListener = onDishRecyclerListener;
loadListeners(itemView);
}
private void loadListeners(#NonNull View v)
{
//Rename an Dish
DishName.setOnClickListener(view ->
{
PopupMenu popup = new PopupMenu(context, v);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.Dish_floating_menu, popup.getMenu());
popup.show();
popup.setOnMenuItemClickListener(item ->
{
switch (item.getItemId())
{
case R.id.menuDeleteDish:
onDishRecyclerListener.deleteDish(getAdapterPosition());
return true;
case R.id.menuRenameDish:
onDishRecyclerListener.renameDish(getAdapterPosition());
return true;
case R.id.menuDishProps:
return true;
default:
return false;
}
});
});
}
}
}
An extraction of the fragment calling the parent recycler view:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_Recipe_panel, container, false);
recyclerRecipe = view.findViewById(R.id.RecipeRecyclerView);
SimpleItemAnimator simpleItemAnimator = (SimpleItemAnimator) recyclerRecipe.getItemAnimator();
if(simpleItemAnimator !=null)
{
simpleItemAnimator.setSupportsChangeAnimations(true);
}
RecipeAdapter = new RecipeRecyclerAdapter(getContext(), allRecipes);
RecipeAdapter.setOnRecipeRecyclerListener(this);
//recyclerRecipe.setHasFixedSize(true);
recyclerRecipe.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerRecipe.setAdapter(RecipeAdapter);
return view;
}
public void createRecipe(String RecipeName)
{
Recipe Recipe = new Recipe(RecipeName, getContext());
allRecipes.add(0,Recipe);
RecipeAdapter.notifyItemInserted(0);
}
#Override
public void deleteRecipe(int RecipePosition)
{
allRecipes.remove(RecipePosition);
RecipeAdapter.notifyItemRemoved(RecipePosition);
}
#Override
public void addDish(int RecipePosition)
{
allRecipes.get(RecipePosition).getDishs().add(new Dish(DishName));
RecipeAdapter.notifyItemChanged(RecipePosition);
}
#Override
public void deleteDish(int DishPosition, int RecipePosition)
{
Recipe Recipe = allRecipes.get(RecipePosition);
Dish Dish = Recipe.getDishs().get(DishPosition);
Dish.getTimer().destroyTimer();
Recipe.getDishs().remove(DishPosition);
RecipeAdapter.notifyItemChanged(RecipePosition);
}
I figured out what the problem was (after LOADS OF HOURS). I needed to notify first the parent recycler and then the child recycler in that order.
//adding an item to the inner list
recipeAdapter.notifyItemChanged(recipePosition);
dishsRecycler.getAdapter().notifyItemInserted(recipe.getDishs().size()-1);
//deleting an inner list item
recipeAdapter.notifyItemChanged(recipePosition);
dishsRecycler.getAdapter().notifyItemRemoved()
However the biggest culprit was having a common recyclerPool for all the inner recyclerviews, so removed this line from the code
//REMOVED THESE LINES
private RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();
holder.DishsRecycler.setRecycledViewPool(viewPool);
Also, I refrained from using notifyDataSet() as that for some reason throws NO_POSITION (-1).
I'm implementing a similar case.
I have 2 RecyclerViews, one nested. Where you can delete items either from nested or parent RecyclerView.
It guess you must update Recyclers every time an item changed or removed.
For comprehension I read this article first:
https://medium.com/android-news/recyclerview-optimisations-a4b141dd433d
And I agree answer by Ken John, when he said you need to notify RecyclerView updates first to parent then to nested; otherwise you get an error and your app will crash.
However, other important thing is how to do the notification updates.
For the nested RecyclerView, I used
// for items updated
notifyItemChanged(position);
// for items deleted
notifyItemRemoved(position);
but the mentioned above not working fine for parent RecyclerView, really I'm not sure why, but I solved as follow:
// for items updated
notifyItemChanged(position);
// for items deleted
notifyItemRemoved(position); // this line does not work for me
notifyDataSetChanged(); // it works fine
The last instruction spend a more bit of time, but works fine.
Note: I don't know yet why notifyItemRemoved(position) doesn't work for parent, and I have call notifyDataSetChanged()

RecyclerView Adapter highlight clicked or current item

As I'm new to android, I'm struggling to highlight Recyclerview clicked or current item. I have tried some workarounds but nothing helps. Basically I want to highlight selected item even after it is coming back from respective Fragment. Please check my code and help me to get done. Thanks.
public class ContentaAdapter extends RecyclerView.Adapter<ContentaAdapter.MyViewHolder> {
Context context;
ArrayList<String> ItemTitle;
ArrayList<String> ItemSource;
public ContentaAdapter(Context context, ArrayList<String> ItemTitle, ArrayList<String> ItemSource) {
this.context = context;
this.ItemTitle = ItemTitle;
this.ItemSource = ItemSource;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.home_items_layout, parent, false);
MyViewHolder vh = new MyViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
holder.ItemTitle.setText(ItemTitle.get(position));
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Fragment contentdisplay = new ViewContentFragment();
Bundle bundle=new Bundle();
bundle.putStringArrayList("ItemTitle",ItemTitle);
bundle.putStringArrayList("ItemSource",ItemSource);
bundle.putInt("position",position);
bundle.putInt("ItemCounts",ItemTitle.size());
contentdisplay.setArguments(bundle);
((MainActivity)context).replaceFragment(contentdisplay);
}
});
}
#Override
public int getItemCount() {
return ItemTitle.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView ItemTitle;
public MyViewHolder(View itemView) {
super(itemView);
ItemTitle = (TextView) itemView.findViewById(R.id.item_title);
}
}
}
you need to to add isSelected state in to your list item data model and change it onClick.
And when you know state you can change background in ViewHolder
if (isSelected) {
// set selected background here
} else {
// set not selected background here
}
And instead of keeping two lists in adapter you should create one with model ArrayList<DataModel> similar to this:
class DataModel {
String ItemTitle;
String ItemSource;
Boolean isSelected;
}
also you shouldn't pass both list to other fragment, instead take only what you need, for example yourList.get(position);

Categories