How to store checkbox statuses after I exit app? - java

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);
}

Related

Android Studio Firebase DataChange Async and Bundle Issue (Java)

I have been getting certain issues with the onDataChange method when I am calling from Firebase Realtime Database. These issues would include data disappearing outside of the DataChange method. I tried a solution from this link,
How to return DataSnapshot value as a result of a method?, it has worked, however, when I tried passing it to a fragment bundle within the callback method, it says the values are null and there isn't any data in it. Is there any workaround for this problem that I am facing? Help is really appreciated, thanks!
import edu.ntu.ssp4_rzdns_outhink.R;
import edu.ntu.ssp4_rzdns_outhink.modals.Attraction;
public class MostPopularRecyclerViewAdapter extends RecyclerView.Adapter<MostPopularRecyclerViewAdapter.ViewHolder>{
private static final String TAG = "MostPopularRecyclerViewAdapter";
private static final String SHARED_PREFS = "attractionsFile";
private ArrayList<Attraction> pops;
private Attraction attraction;
private Context mContext;
private FragmentManager fm;
private Bundle bundle;
SharedPreferences.Editor editor;
SharedPreferences attractionFile;
public MostPopularRecyclerViewAdapter(ArrayList<Attraction> pops, Context mContext, FragmentManager fm, Bundle bundle) {
this.pops = pops;
this.mContext = mContext;
this.fm = fm;
this.bundle = bundle;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
Log.d(TAG, "OnCreateViewHolder Called");
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_more_list, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
Log.d(TAG, "onBindViewHolder Called");
Glide.with(mContext).asBitmap().load(pops.get(position).photo_url).into(holder.attractionImage);
holder.locationName.setText(pops.get(position).att_name);
holder.locationRating.setText(pops.get(position).att_rating.toString());
holder.locationAddress.setText(pops.get(position).att_address);
holder.parentLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String attraction_id = pops.get(holder.getBindingAdapterPosition()).id;
readData(new FirebaseCallback() {
#Override
public void onCallBack(Attraction attr) {
bundle.putString("attid", attr.id);
bundle.putString("name", attr.att_name);
bundle.putString("address", attr.att_address);
bundle.putString("desc", attr.att_desc);
bundle.putDouble("rating", attr.att_rating);
bundle.putString("url", attr.att_url);
bundle.putSerializable("ophrs", attr.att_op_hr);
bundle.putSerializable("adminrate",attr.att_admin_rate);
bundle.putString("photo_url", attr.photo_url);
}
},attraction_id);
}
});
}
#Override
public int getItemCount() {
return pops.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder{
ImageView attractionImage;
TextView locationName;
TextView locationAddress;
TextView locationRating;
RelativeLayout parentLayout;
public ViewHolder(#NonNull View itemView){
super(itemView);
attractionImage = itemView.findViewById(R.id.viewmoreImage);
locationName = itemView.findViewById(R.id.viewmoreName);
locationAddress = itemView.findViewById(R.id.viewmoreLocation);
locationRating = itemView.findViewById(R.id.viewmoreRating);
parentLayout = itemView.findViewById(R.id.parent_layout_view_more);
}
}
private void readData(FirebaseCallback firebaseCallback, String attrId){
Query query = FirebaseDatabase.getInstance().getReference("attractions");
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if (!snapshot.exists()) {
System.out.println("Attraction Does Not Exist");
} else {
for (DataSnapshot attr : snapshot.getChildren()) {
if (attr.getKey().equals(attrId)) {
attraction = attr.getValue(Attraction.class);
attraction.setId(attr.getKey());
}
}
firebaseCallback.onCallBack(attraction);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
private interface FirebaseCallback{
void onCallBack(Attraction attraction);
}
}
According to your last comment:
When I try to put these variables in the bundle, it’ll just disappear and become null.
Please note that this is the expected behavior. There are multiple inconsistencies in your code. First of all, that's not how you should handle the click event in your adapter class. Attaching a click listener to each element you display, isn't a feasible solution. You should create an interface for that as you can see in this repo.
Now, each time you click a particular element in your RecyclerView, you call the readData() method. When you receive the data, you add that data to the Bundle. The problem is that the operation that is opening the new fragment is happening faster than you get the data from the database. That's the reason why you are getting null.
To solve this, you either navigate to the next fragment, only when the data is available or you can make another call, right from the second fragment.

Saving State of RecyclerView Checkbox

I'm a bit new to Android development.
I was wondering how I can save state of checkboxes in a RecyclerView. I know there are existing solutions for this, but I have a list of items in another RecyclerView that uses the same set of checkboxes. When you click an item, it should show all checkboxes and check those previously checked checkboxes for that item.
I have seen posts using SharedPreferences to save the state but I have different checkboxes states for different item click in another RecyclerView and I do not know how to save these different states.
This is the Adapter class for the list of checkboxes named CurrentAddonAdapter.java:
public class CurrentAddonAdapter extends RecyclerView.Adapter<CurrentAddonAdapter.ViewHolder17> {
private Context context;
private ArrayList items3,price3;
private List<AddonList> addonlist1;
private OnItemClickListener17 mOnItemClickListener17;
CurrentAddonAdapter(Context context, ArrayList items3, ArrayList price3,List addonlist1,OnItemClickListener17 onItemClickListener17){
this.context = context;
this.items3 = items3;
this.price3 = price3;
this.addonlist1 = addonlist1;
this.mOnItemClickListener17 = onItemClickListener17;
}
#NonNull
#Override
public ViewHolder17 onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(context);
View view = layoutInflater.inflate(R.layout.addoncard,parent,false);
return new ViewHolder17(view,mOnItemClickListener17);
}
private SparseBooleanArray selecteditems = new SparseBooleanArray();
#Override
public void onBindViewHolder(#NonNull final CurrentAddonAdapter.ViewHolder17 holder, int position) {
holder.item1.setText(String.valueOf(items3.get(position)));
holder.price1.setText(String.valueOf(price3.get(position)));
final AddonList currentaddon = addonlist1.get(position);
holder.item1.setChecked(selecteditems.get(position));
holder.item1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(holder.item1.isChecked()){
holder.item1.setChecked(true);
mOnItemClickListener17.onItemCheck(currentaddon);
}
else{
holder.item1.setChecked(false);
mOnItemClickListener17.onItemUncheck(currentaddon);
}
}
});
}
#Override
public int getItemCount() {
return items3.size();
}
public class ViewHolder17 extends RecyclerView.ViewHolder implements View.OnClickListener{
TextView price1;
CheckBox item1;
OnItemClickListener17 onItemClickListener17;
public ViewHolder17(#NonNull View itemView, final OnItemClickListener17 onItemClickListener17) {
super(itemView);
item1 = itemView.findViewById(R.id.addoncheck);
price1 = itemView.findViewById(R.id.priceadd);
this.onItemClickListener17 = onItemClickListener17;
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
onItemClickListener17.onItemClick7(getAdapterPosition());
}
}
public interface OnItemClickListener17{
void onItemClick7(int position);
void onItemCheck(AddonList addonList);
void onItemUncheck(AddonList addonList);
}
}
This is the code for the item click. It shows a dialog box with the list of all checkboxes with CardView elements array named items3 and price3
Cursor viewaddon = db.viewalladdon();
while(viewaddon.moveToNext()){
items3.add(viewaddon.getString(2));
price3.add(viewaddon.getString(3));
addonlist1.add(new AddonList(viewaddon.getString(2)));
}
addrecycler.setHasFixedSize(true);
currentAddonAdapter = new CurrentAddonAdapter(getActivity(),items3,price3,addonlist1,this);
addrecycler.setAdapter(currentAddonAdapter);
addrecycler.setLayoutManager(new LinearLayoutManager(getActivity()));
Please, help. I've been trying to find a solution for weeks and I still can't find one. I just really need this for school.

How to change an image in RecyclerView locally using drawable

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.

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