I am getting a very strange bug in my application. To make it more clear I will create a similar example with minus code.
I am reading objects from Firebase Realtime Database with an addListenerForSingleValueEvent. While I am reading the objects, I am stored them in an Array that I passed to an Adapter in a Recycleview. At this point, I can say, after debugging, that all seems to work correctly.
Then in the Adapter, I have a code similar to this:
public class AdapterObject extends RecyclerView.Adapter<AdapterObject.ViewHolder> {
ArrayList<Object> objectList;
Context mContext;
public AdapterObject (Context context, ArrayList<Object> objectList){
this.mContext = context;
this.objectList = objectList;
}
#NonNull
#Override
public AdapterObject.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.object_grid_layout, parent,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull AdapterObject.ViewHolder holder, int position) {
Object o = objectList.get(position);
Log.d("TAG", o.getAtribute());
if (o.getAtribute().equals("A")){
holder.atribute.setVisibility(View.VISIBLE);
}
#Override
public int getItemCount() {
return objectList.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
TextView atribute;
boolean favorite;
String descuento, precioOriginal;
public ViewHolder(#NonNull View itemView) {
super(itemView);
atribute = itemView.findViewById(R.id.atribute);
}
}
}
As you can see in the code if the current object has the attribute value == "A", then his Textview is displayed, otherwise, the Textview remains hidden.
All seems correct when I debug it because the objects and their attribute corresponds to the Database, but when I deploy the application in the Android simulator and I start going up and down on the Recycleview, the holders start to display the Textviews although the console debugs seems correct...
Is this normal in RecycleViews? How can I fix that? I have found this, do you think it has any relation?
This is an extract from the RecyclerView documentation
As the name implies, RecyclerView recycles those individual elements.
When an item scrolls off the screen, RecyclerView doesn't destroy its
view. Instead, RecyclerView reuses the view for new items that have
scrolled onscreen. This reuse vastly improves performance, improving
your app's responsiveness and reducing power consumption.
That means that when the view gets reused it will keep the current properties. It's up to you to change them when onBindViewHolder gets called.
In your specific case
#Override
public void onBindViewHolder(#NonNull AdapterObject.ViewHolder holder, int position) {
Object o = objectList.get(position);
Log.d("TAG", o.getAtribute());
if (o.getAtribute().equals("A")){
holder.atribute.setVisibility(View.VISIBLE);
} else. {
holder.atribute.setVisibility(View.GONE);
}
}
I am working on an android project and I am putting some TextViews inside a RecyclerView and at the same time I am trying to put those things in an array list as ViewHolder type. After some tests on the program i understood that the items that are inserted in the ArrayList are only the items that are shown in the screen. For example if my screen fits 15 textviews and i put 30 textviews inside the recycler view and arraylist, the size of the arraylist will be only 15 so i can't make any changes to the rest of the items.
Also when i scroll down the recycler view the arraylist get a size of the items that has been shown while scrolling but when i scroll back to the top and try to change the number of the TextViews and make them less the program crashes.
What i want is to have all of the items that have been added to the recycler view also in the arraylist in order to can use them.
Recycler View class code:
public class Tab1Child1Numbers extends RecyclerView.Adapter<Tab1Child1Numbers.ViewHolder> {
ArrayList<Integer> textFront;
ArrayList<Integer> textBack;
ArrayList<Integer> colors;
Context context;
ArrayList<ViewHolder> texts = new ArrayList<>();
public Tab1Child1Numbers(Context context, ArrayList<Integer> textFront, ArrayList<Integer> textBack, ArrayList<Integer> colors) {
super();
this.context = context;
this.textFront = textFront;
this.textBack = textBack;
this.colors = colors;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.tab1_child1_numbers, viewGroup, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
#Override
public void onBindViewHolder(final ViewHolder viewHolder, final int i) {
viewHolder.textFront.setText(textFront.get(i)+"");
viewHolder.textBack.setText(textBack.get(i)+"");
viewHolder.textFront.setBackgroundColor(colors.get(i));
viewHolder.textBack.setBackgroundColor(colors.get(i));
texts.add(viewHolder);
// cardsFront.add(viewHolder.imageFront);
// cardsBack.add(viewHolder.imgThumbnail);
viewHolder.setClickListener(new ItemClickListener() {
#Override
public void onClick(View view, int position, boolean isLongClick) {
if (isLongClick) {
} else {
Deck deck = new Deck();
deck.flipCard(texts.get(position).frame, texts.get(position).textFront, texts.get(position).textBack);
}
}
});
}
#Override
public int getItemCount() {
return textFront.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
public TextView textFront;
public TextView textBack;
public FrameLayout frame;
public LinearLayout layout;
private ItemClickListener clickListener;
public ViewHolder(View itemView) {
super(itemView);
textFront = (TextView) itemView.findViewById(R.id.txt1);
textBack = (TextView) itemView.findViewById(R.id.txt2);
frame = (FrameLayout) itemView.findViewById(R.id.list_frame);
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
}
public void setClickListener(ItemClickListener itemClickListener) {
this.clickListener = itemClickListener;
}
#Override
public void onClick(View view) {
clickListener.onClick(view, getPosition(), false);
}
#Override
public boolean onLongClick(View view) {
clickListener.onClick(view, getPosition(), true);
return true;
}
}
class Deck {
private void flipCard(View rootLayout, View cardFace, View cardBack) {
FlipAnimation flipAnimation = new FlipAnimation(cardFace, cardBack);
if (cardFace.getVisibility() == View.GONE) {
flipAnimation.reverse();
}
rootLayout.startAnimation(flipAnimation);
}
public void flipAll(){
System.out.println(texts.size()+"--------");
randomize();
for (int i = 0; i < texts.size(); i++) {
flipCard(texts.get(i).frame, texts.get(i).textFront, texts.get(i).textBack);
}
}
private void randomize(){
for (int i=0; i<texts.size(); i++){
if (texts.get(i).textFront.getVisibility() == View.GONE) {
texts.get(i).textFront.setText(textFront.get(i) + "");
texts.get(i).textFront.setBackgroundColor(colors.get(i));
}
else {
texts.get(i).textBack.setText(textBack.get(i) + "");
texts.get(i).textBack.setBackgroundColor(colors.get(i));
}
}
}
}
It looks like you're trying to do something that you shouldn't.
onBindViewHolder() is called by the system whenever it is about to display a ViewHolder to the user. So it will initially be called once for every view on the screen, plus once for a small number of views just off-screen (so that they can scroll on screen nicely).
However, this means it will also be called repeatedly as the user scrolls through the data in your adapter. In these cases, the ViewHolder being passed to onBindViewHolder() might have been recycled, meaning it might previously have been used to display different data and is now being re-used to display new data.
Let's say you have one million items in your data set, but your layout is set up in such a way that only 15 items are visible on screen at any one time. Chances are good that the system will wind up creating about 20 ViewHolder instances (15 on the screen, 5 available for re-use just off-screen). These same 20 ViewHolders will be used to display all one million items if the user scrolls enough. They'll just keep being re-used over and over.
That's why this line is problematic:
texts.add(viewHolder);
You're going to wind up building a list with potentially millions of objects in it, with the same 20 ViewHolders appearing multiple times in your list.
It would be much better to think about storing your data in a different way, rather than trying to store ViewHolders passed to onBindViewHolder().
I have a RecyclerView which gets populated by a RealmRecyclerViewAdapter but somehow there are no animations playing when the data changes.
The adapter class uses multiple ViewHolders for different layouts but that should not affect animations right?
public class DiaryPageEntryAdapter extends RealmRecyclerViewAdapter<Entry, RecyclerView.ViewHolder> {
static class MealEntryViewHolder extends RecyclerView.ViewHolder {
#BindView(R.id.item_diary_entry_drink_title) TextView tvMealEntryTitle;
#BindView(R.id.item_diary_entry_meal_time) TextView tvMealEntryTime;
BindView(R.id.item_diary_entry_meal_bullet_list) RecyclerView rvBulletList;
MealEntryBulletAdapter bulletAdapter;
public MealEntryViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
this.bulletAdapter = new MealEntryBulletAdapter();
rvBulletList.setLayoutManager(new LinearLayoutManager(itemView.getContext()));
rvBulletList.setAdapter(this.bulletAdapter);
}
void bindData(MealEntry mealEntry) {
tvMealEntryTitle.setText(mealEntry.getTitle());
tvMealEntryTime.setText(DateTimeUtils.timeValueToText(itemView.getContext(), mealEntry.getTime()));
this.bulletAdapter.updateData(mealEntry.getConsumedMeals() ,mealEntry.getConsumedDrinks());
}
}
// Other ViewHolders
public DiaryPageEntryAdapter(#Nullable OrderedRealmCollection<Entry> data, boolean autoUpdate) {
super(data, autoUpdate, true);
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case MEAL_ENTRY:
// Inflate meal entry layout and then create a new meal view holder with it
View rowMeal = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_diary_entry_meal, parent, false);
return new MealEntryViewHolder(rowMeal);
// Other case options.
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Entry entry = getItem(position);
if(Entry.isMealEntry(entry)) {
MealEntryViewHolder mealHolder = (MealEntryViewHolder) holder;
mealHolder.bindData(Entry.getMealEntryFromEntry(entry));
}
// Other if branches.
}
#Override
public int getItemViewType(int position) {
Entry entry = getItem(position);
if(Entry.isMealEntry(entry)) return MEAL_ENTRY;
// Other if branches.
}
The code for setting up the RecyclerView and adapter looks as following:
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.frag_diary_page_rv_entries);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
entryAdapter = new DiaryPageEntryAdapter(null, true);
recyclerView.setAdapter(entryAdapter);
The code that binds the data to the adapter is stated below:
RealmResults<Entry> sortedEntries = diaryEntry.getEntries()
.where()
.findAllSortedAsync("time");
entryAdapter.updateData(sortedEntries);
The auto-updates work fine but somehow no there is no animation when the data changes. A new entry simply appears but without animations. Furthermore I want a short animation to play once the RecyclerView is populated for the first time - an entrance animation similar to [http://anthony-skr.com/article/recyclerview-items-animation-with-rebound-effect][1].
Note: In my appĀ“s build.gradle file
dependencies {
// Other dependencies
compile 'io.realm:android-adapters:2.1.0'
}
In the Project build.gradle file:
dependencies {
classpath 'com.android.tools.build:gradle:2.3.2'
classpath "io.realm:realm-gradle-plugin:3.1.4"
}
From your code sample, it isn't easy to see where you call entryAdapter.updateDate() from, but calling this method continuously on every update will disable all animations as it just calls notifyDataSetChanged().
A more standard pattern would look like this:
RealmResults<Entry> sortedEntries = diaryEntry.getEntries()
.where()
.findAllSortedAsync("time");
entryAdapter = new DiaryPageEntryAdapter(sortedEntries, true);
recyclerView.setAdapter(entryAdapter);
Animations should work if you do the above.
I have created an app that contains a viewPager inside the mainActivity, this viewPager contains 5 fragments, of which 4 are recyclerViews and one is a normal linearLayout containing some text...
Here is a screenshot of the app, not all tabs in the tablayout are visible:
Now, as you might have seen already, there isn't much space in the viewPager for the user to see anything, so they have to scroll too much to view things in the recylerView. I want to modify my app so that when the user tries to scroll inside the recyclerView, the visible part of the mainActivity is scrolled down till the recyclerView occupies the entire page and then the recyclerView begins to scroll normally.
Can someone please help me implement this type of scroll feature into my app. You can just check out this app for a reference to what I'm saying. Just open up any movie or tvSeries and then try scrolling, the mainActivity gets scrolled first and then the rest of the layout.... Can someone please help. I've already tried the solutions on stackOverflow and many of them don't work, I also tried to google for a solution, but didn't get anything useful....
Here is the code for my adapter:
public class cardViewAdapterCreditsCast extends RecyclerView.Adapter<cardViewAdapterCreditsCast.ViewHolder> {
private Context context;
private List<creditsModel> creditsModels;
public cardViewAdapterCreditsCast(Context context, List<creditsModel> creditsModels) {
this.context = context;
this.creditsModels = creditsModels;
}
#Override
public cardViewAdapterCreditsCast.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.new_cast_row, parent, false);
return new cardViewAdapterCreditsCast.ViewHolder(view);
}
#Override
public void onBindViewHolder(cardViewAdapterCreditsCast.ViewHolder holder, int position) {
final creditsModel creditsModel = creditsModels.get(position);
int tempNumber = holder.celebImage.getWidth();
holder.celebImage.setMinimumHeight(tempNumber);
holder.celebImage.setMaxHeight(tempNumber + 1);
String imagePath = "https://image.tmdb.org/t/p/w500" + creditsModel.getProfilePath();
holder.starringAs.setText(creditsModel.getCharacter());
holder.celebName.setText(creditsModel.getActorName());
if (creditsModel.getProfilePath() != null) {
Picasso.with(context).load(imagePath).transform(new CircleTransform()).into(holder.celebImage);
} else
holder.celebImage.setBackgroundResource(R.drawable.not_found);
}
#Override
public int getItemCount() {
return creditsModels.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ImageView celebImage;
public TextView celebName;
public TextView starringAs;
private LinearLayout linearLayout;
public ViewHolder(View itemView) {
super(itemView);
linearLayout = (LinearLayout) itemView.findViewById(R.id.castRowMainLinearLayout);
celebImage = (ImageView) itemView.findViewById(R.id.castRowImage);
celebName = (TextView) itemView.findViewById(R.id.castRowName);
starringAs = (TextView) itemView.findViewById(R.id.castRowAppearance);
}
}
}
Use nested Scrollview if there are more than one scrollview or recyclerview.
You can use a CoordinatorLayout to implement this easily.
Example, http://saulmm.github.io/mastering-coordinator
Documentation, https://developer.android.com/reference/android/support/design/widget/CoordinatorLayout.html
I have a RecyclerView with an TextView text box and a cross button ImageView. I have a button outside of the recyclerview that makes the cross button ImageView visible / gone.
I'm looking to remove an item from the recylerview, when that items cross button ImageView is pressed.
My adapter:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> implements View.OnClickListener, View.OnLongClickListener {
private ArrayList<String> mDataset;
private static Context sContext;
public MyAdapter(Context context, ArrayList<String> myDataset) {
mDataset = myDataset;
sContext = context;
}
#Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.my_text_view, parent, false);
ViewHolder holder = new ViewHolder(v);
holder.mNameTextView.setOnClickListener(MyAdapter.this);
holder.mNameTextView.setOnLongClickListener(MyAdapter.this);
holder.mNameTextView.setTag(holder);
return holder;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.mNameTextView.setText(mDataset.get(position));
}
#Override
public int getItemCount() {
return mDataset.size();
}
#Override
public void onClick(View view) {
ViewHolder holder = (ViewHolder) view.getTag();
if (view.getId() == holder.mNameTextView.getId()) {
Toast.makeText(sContext, holder.mNameTextView.getText(), Toast.LENGTH_SHORT).show();
}
}
#Override
public boolean onLongClick(View view) {
ViewHolder holder = (ViewHolder) view.getTag();
if (view.getId() == holder.mNameTextView.getId()) {
mDataset.remove(holder.getPosition());
notifyDataSetChanged();
Toast.makeText(sContext, "Item " + holder.mNameTextView.getText() + " has been removed from list",
Toast.LENGTH_SHORT).show();
}
return false;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView mNumberRowTextView;
public TextView mNameTextView;
public ViewHolder(View v) {
super(v);
mNameTextView = (TextView) v.findViewById(R.id.nameTextView);
}
}
}
My layout is:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:id="#+id/layout">
<TextView
android:id="#+id/nameTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:padding="5dp"
android:background="#drawable/greyline"/>
<ImageView
android:id="#+id/crossButton"
android:layout_width="16dp"
android:layout_height="16dp"
android:visibility="gone"
android:layout_marginLeft="50dp"
android:src="#drawable/cross" />
</LinearLayout>
How can I get something like an onClick working for my crossButton ImageView? Is there a better way? Maybe changing the whole item onclick into a remove the item? The recyclerview shows a list of locations that need to be edited. Any technical advice or comments / suggestions on best implementation would be hugely appreciated.
I have done something similar.
In your MyAdapter:
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
public CardView mCardView;
public TextView mTextViewTitle;
public TextView mTextViewContent;
public ImageView mImageViewContentPic;
public ImageView imgViewRemoveIcon;
public ViewHolder(View v) {
super(v);
mCardView = (CardView) v.findViewById(R.id.card_view);
mTextViewTitle = (TextView) v.findViewById(R.id.item_title);
mTextViewContent = (TextView) v.findViewById(R.id.item_content);
mImageViewContentPic = (ImageView) v.findViewById(R.id.item_content_pic);
//......
imgViewRemoveIcon = (ImageView) v.findViewById(R.id.remove_icon);
mTextViewContent.setOnClickListener(this);
imgViewRemoveIcon.setOnClickListener(this);
v.setOnClickListener(this);
mTextViewContent.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
if (mItemClickListener != null) {
mItemClickListener.onItemClick(view, getPosition());
}
return false;
}
});
}
#Override
public void onClick(View v) {
//Log.d("View: ", v.toString());
//Toast.makeText(v.getContext(), mTextViewTitle.getText() + " position = " + getPosition(), Toast.LENGTH_SHORT).show();
if(v.equals(imgViewRemoveIcon)){
removeAt(getPosition());
}else if (mItemClickListener != null) {
mItemClickListener.onItemClick(v, getPosition());
}
}
}
public void setOnItemClickListener(final OnItemClickListener mItemClickListener) {
this.mItemClickListener = mItemClickListener;
}
public void removeAt(int position) {
mDataset.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, mDataSet.size());
}
Edit:
getPosition() is deprecated now, use getAdapterPosition() instead.
first of all, item should be removed from the list!
mDataSet.remove(getAdapterPosition());
then:
notifyItemRemoved(getAdapterPosition());
notifyItemRangeChanged(getAdapterPosition(), mDataSet.size()-getAdapterPosition());
if still item not removed use this magic method :)
private void deleteItem(int position) {
mDataSet.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, mDataSet.size());
holder.itemView.setVisibility(View.GONE);
}
Kotlin version
private fun deleteItem(position: Int) {
mDataSet.removeAt(position)
notifyItemRemoved(position)
notifyItemRangeChanged(position, mDataSet.size)
holder.itemView.visibility = View.GONE
}
The Problem
RecyclerView was built to display data in an efficient and responsive manner.
Usually you have a dataset which is passed to your adapter and is looped through to display your data.
Here your dataset is:
private ArrayList<String> mDataset;
The point is that RecyclerView is not connected to your dataset, and therefore is unaware of your dataset changes.
It just reads data once and displays it through your ViewHolder, but a change to your dataset will not propagate to your UI.
This means that whenever you make a deletion/addition on your data list, those changes won't be reflected to your RecyclerView directly. (i.e. you remove the item at index 5, but the 6th element remains in your recycler view).
A (old school) solution
RecyclerView exposes some methods for you to communicate your dataset changes, reflecting those changes directly on your list items.
The standard Android APIs allow you to bind the process of data removal (for the purpose of the question) with the process of View removal.
The methods we are talking about are:
notifyItemChanged(index: Int)
notifyItemInserted(index: Int)
notifyItemRemoved(index: Int)
notifyItemRangeChanged(startPosition: Int, itemCount: Int)
notifyItemRangeInserted(startPosition: Int, itemCount: Int)
notifyItemRangeRemoved(startPosition: Int, itemCount: Int)
A Complete (old school) Solution
If you don't properly specify what happens on each addition, change or removal of items, RecyclerView list items are animated unresponsively because of a lack of information about how to move the different views around the list.
The following code will allow RecyclerView to precisely play the animation with regards to the view that is being removed (And as a side note, it fixes any IndexOutOfBoundExceptions, marked by the stacktrace as "data inconsistency").
void remove(position: Int) {
dataset.removeAt(position)
notifyItemChanged(position)
notifyItemRangeRemoved(position, 1)
}
Under the hood, if we look into RecyclerView we can find documentation explaining that the second parameter we pass to notifyItemRangeRemoved is the number of items that are removed from the dataset, not the total number of items (As wrongly reported in some others information sources).
/**
* Notify any registered observers that the <code>itemCount</code> items previously
* located at <code>positionStart</code> have been removed from the data set. The items
* previously located at and after <code>positionStart + itemCount</code> may now be found
* at <code>oldPosition - itemCount</code>.
*
* <p>This is a structural change event. Representations of other existing items in the data
* set are still considered up to date and will not be rebound, though their positions
* may be altered.</p>
*
* #param positionStart Previous position of the first item that was removed
* #param itemCount Number of items removed from the data set
*/
public final void notifyItemRangeRemoved(int positionStart, int itemCount) {
mObservable.notifyItemRangeRemoved(positionStart, itemCount);
}
Open source solutions
You can let a library like FastAdapter, Epoxy or Groupie take care of the business, and even use an observable recycler view with data binding.
New ListAdapter
Google recently introduced a new way of writing the recycler view adapter, which works really well and supports reactive data.
It is a new approach and requires a bit of refactoring, but it is 100% worth switching to it, as it makes everything smoother.
here is the documentation, and here a medium article explaining it
Here are some visual supplemental examples. See my fuller answer for examples of adding and removing a range.
Add single item
Add "Pig" at index 2.
String item = "Pig";
int insertIndex = 2;
data.add(insertIndex, item);
adapter.notifyItemInserted(insertIndex);
Remove single item
Remove "Pig" from the list.
int removeIndex = 2;
data.remove(removeIndex);
adapter.notifyItemRemoved(removeIndex);
Possibly a duplicate answer but quite useful for me. You can implement the method given below in RecyclerView.Adapter<RecyclerView.ViewHolder>
and can use this method as per your requirements, I hope it will work for you
public void removeItem(#NonNull Object object) {
mDataSetList.remove(object);
notifyDataSetChanged();
}
I tried all the above answers, but inserting or removing items to recyclerview causes problem with the position in the dataSet. Ended up using delete(getAdapterPosition()); inside the viewHolder which worked great at finding the position of items.
The problem I had was I was removing an item from the list that was no longer associated with the adapter to make sure you are modifying the correct adapter you can implement a method like this in your adapter:
public void removeItemAtPosition(int position) {
items.remove(position);
}
And call it in your fragment or activity like this:
adapter.removeItemAtPosition(position);
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private Context context;
private List<cardview_widgets> list;
public MyAdapter(Context context, List<cardview_widgets> list) {
this.context = context;
this.list = list;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(this.context).inflate(R.layout.fragment1_one_item,
viewGroup, false);
return new MyViewHolder(view);
}
public static class MyViewHolder extends RecyclerView.ViewHolder {
TextView txtValue;
TextView txtCategory;
ImageView imgInorEx;
ImageView imgCategory;
TextView txtDate;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
txtValue= itemView.findViewById(R.id.id_values);
txtCategory= itemView.findViewById(R.id.id_category);
imgInorEx= itemView.findViewById(R.id.id_inorex);
imgCategory= itemView.findViewById(R.id.id_imgcategory);
txtDate= itemView.findViewById(R.id.id_date);
}
}
#NonNull
#Override
public void onBindViewHolder(#NonNull final MyViewHolder myViewHolder, int i) {
myViewHolder.txtValue.setText(String.valueOf(list.get(i).getValuee()));
myViewHolder.txtCategory.setText(list.get(i).getCategory());
myViewHolder.imgInorEx.setBackgroundColor(list.get(i).getImg_inorex());
myViewHolder.imgCategory.setImageResource(list.get(i).getImg_category());
myViewHolder.txtDate.setText(list.get(i).getDate());
myViewHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
list.remove(myViewHolder.getAdapterPosition());
notifyDataSetChanged();
return false;
}
});
}
#Override
public int getItemCount() {
return list.size();
}}
i hope this help you.
if you want to remove item you should do this:
first remove item:
phones.remove(position);
in next step you should notify your recycler adapter that you remove an item by this code:
notifyItemRemoved(position);
notifyItemRangeChanged(position, phones.size());
but if you change an item do this:
first change a parameter of your object like this:
Service s = services.get(position);
s.done = "Cancel service";
services.set(position,s);
or new it like this :
Service s = new Service();
services.set(position,s);
then notify your recycler adapter that you modify an item by this code:
notifyItemChanged(position);
notifyItemRangeChanged(position, services.size());
hope helps you.
String str = arrayList.get(position);
arrayList.remove(str);
MyAdapter.this.notifyDataSetChanged();
To Method onBindViewHolder Write This Code
holder.remove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Cursor del=dbAdapter.ExecuteQ("delete from TblItem where Id="+values.get(position).getId());
values.remove(position);
notifyDataSetChanged();
}
});
Incase Anyone wants to implement something like this in Main class instead of Adapter class, you can use:
public void removeAt(int position) {
peopleListUser.remove(position);
friendsListRecycler.getAdapter().notifyItemRemoved(position);
friendsListRecycler.getAdapter().notifyItemRangeChanged(position, peopleListUser.size());
}
where friendsListRecycler is the Adapter name
you must to remove this item from arrayList of data
myDataset.remove(holder.getAdapterPosition());
notifyItemRemoved(holder.getAdapterPosition());
notifyItemRangeChanged(holder.getAdapterPosition(), getItemCount());
//////// set the position
holder.cancel.setTag(position);
///// click to remove an item from recycler view and an array list
holder.cancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int positionToRemove = (int)view.getTag(); //get the position of the view to delete stored in the tag
mDataset.remove(positionToRemove);
notifyDataSetChanged();
}
});
make interface into custom adapter class and handling click event on recycler view..
onItemClickListner onItemClickListner;
public void setOnItemClickListner(CommentsAdapter.onItemClickListner onItemClickListner) {
this.onItemClickListner = onItemClickListner;
}
public interface onItemClickListner {
void onClick(Contact contact);//pass your object types.
}
#Override
public void onBindViewHolder(ItemViewHolder holder, int position) {
// below code handle click event on recycler view item.
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onItemClickListner.onClick(mContectList.get(position));
}
});
}
after define adapter and bind into recycler view called below code..
adapter.setOnItemClickListner(new CommentsAdapter.onItemClickListner() {
#Override
public void onClick(Contact contact) {
contectList.remove(contectList.get(contectList.indexOf(contact)));
adapter.notifyDataSetChanged();
}
});
}
In case you are wondering like I did where can we get the adapter position in the method getadapterposition(); its in viewholder object.so you have to put your code like this
mdataset.remove(holder.getadapterposition());
In the activity:
mAdapter.updateAt(pos, text, completed);
mAdapter.removeAt(pos);
In the your adapter:
void removeAt(int position) {
list.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, list.size());
}
void updateAt(int position, String text, Boolean completed) {
TodoEntity todoEntity = list.get(position);
todoEntity.setText(text);
todoEntity.setCompleted(completed);
notifyItemChanged(position);
}
in 2022, after trying everything the whole internet given below is the answer
In MyViewHolder class
private myAdapter adapter;
inside MyViewHolder function initalise adapter
adapter = myAdapter.this
inside onclick
int position = getAdapterPosition()
list.remove(position);
adapter.notifyItemRemoved(position);