I want to load the clicked image in the next activity in fullscreen view. I don't know what I am doing wrong. The app is running completely fine but the image is not loading on the next screen. am new to android development and I thought I should start learning by doing a project. I am not understanding what is the problem in my coding.
public class CategoriesAdapter extends RecyclerView.Adapter<CategoriesAdapter.ImageViewHolder> {
private Context mCtx;
private List<Category> imageslist;
public CategoriesAdapter(Context mCtx, List<Category> imageslist) {
this.mCtx = mCtx;
this.imageslist = imageslist;
}
#NonNull
#Override
public ImageViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view= LayoutInflater.from(mCtx).inflate(R.layout.recyclerview_images,parent,false);
return new ImageViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull final ImageViewHolder holder, final int position) {
final Category images=imageslist.get(position);
Glide.with(mCtx).load(images.url).into(holder.imageView);
holder.imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent=new Intent(mCtx, LoadWall.class);
intent.putExtra("url", (Parcelable) imageslist.get(position));
mCtx.startActivity(intent);
}
});
}
#Override
public int getItemCount() {
return imageslist.size();
}
class ImageViewHolder extends RecyclerView.ViewHolder{
ImageView imageView;
public ImageViewHolder(#NonNull View itemView) {
super(itemView);
imageView=itemView.findViewById(R.id.image_view);
}
}
}
This is the activity where I want to load the image. But its not loading. Please Help
public class LoadWall extends AppCompatActivity {
ImageView imageView;
int myImage;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_load_wall);
imageView=findViewById(R.id.load_image);
get();
}
private void get(){
if(getIntent().hasExtra("url")){
String image=getIntent().getStringExtra("url");
set(image);
}
else{
Toast.makeText(this,"No Data",Toast.LENGTH_SHORT).show();
}
}
private void set(String image){
Glide.with(this).load(image).into(imageView);
}
}
Here you only need to pass URL as a String. Parcelable is not required.
intent.putExtra("url", imageslist.get(position).getUrl());
Option 1)
In your next activity you are looking for String.
String image=getIntent().getStringExtra("url");
in first activity in onClick() change your code to this.
Intent intent=new Intent(mCtx, LoadWall.class);
intent.putExtra("url", imageslist.get(position));
intent.startActivity(intent);
As i see imageslist.get(position) will return Category so you will need to add your url parameter. Something like this imageslist.get(position).getUrl();
Option 2)
If you want to get Category object then in next activity change to this
Category category = getIntent().getParcelableExtra("url");
Your imagesList contains data of type Category and you send an entry from this list to the next activity. However, the second activity expects a String to be received. It will check to see if it has an extra (it has - but not what you need), then try to retrieve that value as a String which will result in a null String. Having null, Glide will not load anything.
In other words, you made a small mistake on what data you use. When you load the data, you do it correctly by using the url field
final Category images=imageslist.get(position);
Glide.with(mCtx).load(**images.url**).into(holder.imageView);
But when you are passing it to the next activity, you send the entire object
intent.putExtra("url", **(Parcelable) imageslist.get(position)**);
Using the url field as you did in the first case will make your app work properly.
Start your Activity
Intent intent=new Intent(mCtx, LoadWall.class);
intent.putExtra("url", images.url);
mCtx.startActivity(intent);
I have an increment system and I want when onClick to save value from DialogAlert in a column in ListView Adapter.
Here is my Adapter:
public class VanzatorProduseList extends ArrayAdapter<VanzatorProduse> {
private Activity context;
private SparseBooleanArray selectedListItemsIds;
private List<VanzatorProduse> vanzatorProduseList;
public VanzatorProduseList(Activity context, List<VanzatorProduse> vanzatorProduseList){
super(context, R.layout.list_produse_vanzator, vanzatorProduseList);
this.context = context;
selectedListItemsIds = new SparseBooleanArray();
this.vanzatorProduseList = vanzatorProduseList;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View listViewItem = inflater.inflate(R.layout.list_produse_vanzator, null, true);
TextView textViewProdus1 = (TextView) listViewItem.findViewById(R.id.textViewProdus1);
TextView textViewPret1 = (TextView) listViewItem.findViewById(R.id.textViewPret1);
final TextView textViewCantitate1 = (TextView) listViewItem.findViewById(R.id.textViewCantitate1);
final VanzatorProduse vanzatorProduse = vanzatorProduseList.get(position);
textViewProdus1.setText(vanzatorProduse.getProdus());
textViewPret1.setText(vanzatorProduse.getPret());
textViewCantitate1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// custom dialog
final Dialog dialog = new Dialog(context);
dialog.setContentView(R.layout.dialog_alert);
dialog.setTitle("Alege Canitatea");
// set the custom dialog components - text, image and button
final Button dialogBtn = (Button) dialog.findViewById(R.id.dialog_btn);
final ElegantNumberButton elegantNumberButton = (ElegantNumberButton) dialog.findViewById(R.id.elegantNumberButton);
// if button is clicked, close the custom dialog
dialogBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String num = elegantNumberButton.getNumber();
vanzatorProduseList.add(num);
dialog.dismiss();
}
});
dialog.show();
}
});
return listViewItem;
}
Here is what I tried but I got an error and no idea what to do next :
String num = elegantNumberButton.getNumber();
vanzatorProduseList.add(num);
Error:
'add(com.dev.darius.neglije.Vanzator.ListaProduse.VanzatorProduse)' in 'java.util.List' cannot be applied to '(java.lang.String)'
Here I'm stuck I want to display in TextView called textViewCantitate1.
Hope you understand.
As stated in earlier answers by #jibrahim:
You are trying to add String type into List vanzatorProduseList. You can add only VanzatorProduse type into vanzatorProduseList list. So, the cause of the problem is:
String num = elegantNumberButton.getNumber();
vanzatorProduseList.add(num);
You need to do something like this Create Object of your Custom class and assign value to that:
String num = elegantNumberButton.getNumber();
VanzatorProduse numVanProObject = new VanzatorProduse();
numVanProObject .setNumber(num );
vanzatorProduseList.add(numVanProObject );
But your custom call should have method to cater this type issue
Edit: Do not forget to call notifyDataSetChanged() method to refresh the list
VanzatorProduse producse = new VanzatorProduse();
producse.setProdus("add value here")
vanzatorProduseList.add(producse);
You are trying to add String type into List<VanzatorProduse> vanzatorProduseList. You can add only VanzatorProduse type into vanzatorProduseList list. So, the cause of the problem is:
String num = elegantNumberButton.getNumber();
vanzatorProduseList.add(num);
In your code you have following lines:
final VanzatorProduse vanzatorProduse = vanzatorProduseList.get(position);
textViewProdus1.setText(vanzatorProduse.getProdus());
textViewPret1.setText(vanzatorProduse.getPret());
So, might be you add num value into vanzatorProduse.setProdus(num) or any other appropriate field and then add it into the list:
vanzatorProduseList.add(vanzatorProduse);
I need to call a new activity, when a button inside one of my recyclerview row elements is called. Each row item in the list contains 4 buttons, one of which needs to open a new activity which will be used to edit the data in that row.
Here is the code for my button so far:
public void onBindViewHolder(CounterLayoutAdapter.ViewHolder holder, final
int position) {
final Counter counter = counterList.get(position);
//counter is a class which holds the data that will be displayed on one
//row
String comment = counter.getComment();
String name = counter.getCounterName();
int number = counter.getCurrentValue();
//LocalDate modifyDate = counter.getLastModifyDate();
Button up = holder.itemView.findViewById(R.id.buttonUp);
Button down = holder.itemView.findViewById(R.id.buttonDown);
Button reset = holder.itemView.findViewById(R.id.buttonReset);
Button edit = holder.itemView.findViewById(R.id.buttonEdit);
Button delete = holder.itemView.findViewById(R.id.buttonDelete);
// code for 4 other buttons goes here
//
edit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
Since I need the activity that I open to return user inputted data for me, I am using startActivityForResult. However, as far as I can tell, this will only work inside an actual activity class.
So then I tried passing the mainactivity context to my CounterLayoutAdapter class, where all of my button code is. However, the OnBindViewHolder method still cannot access it there. So I tried to pass the context to OnBindViewHolder, but that doesn't work either, as it won't override the abstract class if i do that..
So, how on earth can I call a new activity here?
Alternatively, if there is some other way to get user input into 4 fields and return that input back to the adapter, without calling an activity, that would work as well.
EDIT: viewholder and layout inflation
public static class ViewHolder extends RecyclerView.ViewHolder implements
View.OnClickListener {
private TextView name;
private TextView comment;
private TextView number;
//private TextView date;
public ViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
comment = itemView.findViewById(R.id.textComment);
name = itemView.findViewById(R.id.textName);
number = itemView.findViewById(R.id.editTextNum);
//date = itemView.findViewById(R.id.textDate);
}
#Override
public void onClick(View view) {}
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View inflatedView =
LayoutInflater.from(parent.getContext()).inflate(R.layout
.row_layout, parent, false);
return new ViewHolder(inflatedView);
}
You can call startActivityForResult() in adapter class.
Get context in adapter like Context context=holder.up.getContext();
then in your button's OnClickListener do this.
edit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent=new Intent(context,ActivityYouWantToStart.class);
//Pass any extras if you want to.
((Activity)context).startActivityForResult(intent,REQUEST_CODE);
}
});
Then in your activity (which contain this recyclerView) override onActivityResult like this
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE) {//same REQUEST_CODE you used in adapter
if (resultCode == RESULT_OK) {
//Do your thing and get the data you want.
adapter.onDataReady(Data data);//where adapter is your recycler adapter,
//and data is whatever data you want to pass to adapter
//(Data you got from the activityResult, do not confuse it with onActivityResult's parameter 'Intent data')
}
}
}
Finally in your Recycler Adapter class, define onDataReady() function like
public void onDataReady(Data data){
//Update RecyclerView with new data
}
Hope this helps. I once did this, and it works for me. Let me know if you have any problem.
As you see , you do not have to findViewById in onBindViewHolder.
public void onBindViewHolder(CounterLayoutAdapter.ViewHolder holder, final
int position) {
final Counter counter = counterList.get(position);
//counter is a class which holds the data that will be displayed on one
//row
String comment = counter.getComment();
String name = counter.getCounterName();
int number = counter.getCurrentValue();
//LocalDate modifyDate = counter.getLastModifyDate();
holder.edit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
Then you should init edit in ViewHolder constructor.
public ViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
comment = itemView.findViewById(R.id.textComment);
name = itemView.findViewById(R.id.textName);
number = itemView.findViewById(R.id.editTextNum);
//date = itemView.findViewById(R.id.textDate);
// init four button
edit = itemView.findViewById(R.id.buttonEdit)
}
I have a RecyclerView with each element representing an event. I want to let the user select events by clicking it. Once selected, the event(s) and a report button will be colored:
UI before performing a click: click here.
UI After performing a click: click here.
It's pretty simple and allegedly works; I set an OnClickListener for each ViewHolder which is responsible for coloring the item, and when fired it's triggering another event in the owning activity named onOccurrenceSelected, which is responsible for changing the button's state.
However, when scrolling through the RecyclerView's items, other irrelevant items are colored like their OnClickListener was triggered (though it wasn't), and when scrolling back the selected event is colored as not selected. While this is happening, the only event that's supposed to color the items is not triggered.
Any explanation for such behavior? Thanks!
EDIT: Here are some relevant code from the adapter:
private List<Occurrence> mDataSet;
private Activity activity;
public <OccurrencesActivity extends OnOccurrenceSelectedListener> OccurrencesAdapter(OccurrencesActivity occurrencesActivity, List<Occurrence> occurrences) {
this.activity = (android.app.Activity) occurrencesActivity;
mDataSet = occurrences;
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
Occurrence instance = mDataSet.get(position);
...
setOnClickListener(holder, instance);
}
private void setOnClickListener(final ViewHolder holder, final Occurrence occurrence) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!occurrence.isSelected()) {
holder.itemView.setBackgroundColor(App.getContext().getResources().getColor(R.color.turquoise));
holder.titleTextView.setTextColor(App.getContext().getResources().getColor(R.color.white));
holder.statusTextView.setTextColor(App.getContext().getResources().getColor(R.color.white));
holder.dateTextView.setTextColor(App.getContext().getResources().getColor(R.color.white));
holder.timeTextView.setTextColor(App.getContext().getResources().getColor(R.color.white));
} else {
holder.itemView.setBackgroundColor(App.getContext().getResources().getColor(R.color.white));
holder.titleTextView.setTextColor(App.getContext().getResources().getColor(R.color.turquoise));
holder.statusTextView.setTextColor(App.getContext().getResources().getColor(R.color.grey));
holder.dateTextView.setTextColor(App.getContext().getResources().getColor(R.color.grey));
holder.timeTextView.setTextColor(App.getContext().getResources().getColor(R.color.grey));
}
occurrence.setSelected(!occurrence.isSelected());
((OnOccurrenceSelectedListener)activity).onOccurrenceSelected(mDataSet);
}
});
}
Recyclerview always resuse views while scrolling so you have to store selected positions into temporary arraylist and then keep condition check into onBindViewHolder that whether that particular position is already exists in arraylist or not? I updated your adaper. find the below changes with comment
private List<Occurrence> mDataSet;
private Activity activity;
//Added here temporary ArrayList
private ArrayList<String> mSelectedPosition = new ArrayList<String>;
public <OccurrencesActivity extends OnOccurrenceSelectedListener> OccurrencesAdapter(OccurrencesActivity occurrencesActivity, List<Occurrence> occurrences) {
this.activity = (android.app.Activity) occurrencesActivity;
mDataSet = occurrences;
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
//Set ViewTag
holder.itemView.setTag(position);
//Check everyposition during view binding process
if(mSelectedPosition.contains(String.valueOf(position))){
holder.itemView.setBackgroundColor(App.getContext().getResources().getColor(R.color.white));
holder.titleTextView.setTextColor(App.getContext().getResources().getColor(R.color.turquoise));
holder.statusTextView.setTextColor(App.getContext().getResources().getColor(R.color.grey));
holder.dateTextView.setTextColor(App.getContext().getResources().getColor(R.color.grey));
holder.timeTextView.setTextColor(App.getContext().getResources().getColor(R.color.grey));
}else{
holder.itemView.setBackgroundColor(App.getContext().getResources().getColor(R.color.white));
holder.titleTextView.setTextColor(App.getContext().getResources().getColor(R.color.turquoise));
holder.statusTextView.setTextColor(App.getContext().getResources().getColor(R.color.grey));
holder.dateTextView.setTextColor(App.getContext().getResources().getColor(R.color.grey));
holder.timeTextView.setTextColor(App.getContext().getResources().getColor(R.color.grey));
}
Occurrence instance = mDataSet.get(position);
...
setOnClickListener(holder, instance);
}
private void setOnClickListener(final ViewHolder holder, final Occurrence occurrence) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Get Position
int position = (int) view.getTag();
//Remove SelectedPosition if Already there
if(mSelectedPosition.contains(position))
mSelectedPosition.remove(String.valueOf(position));
else
mSelectedPosition.add(String.valueOf(position));
notifyDataSetChanged();
//Not sure about this lines
occurrence.setSelected(!occurrence.isSelected());
((OnOccurrenceSelectedListener)activity).onOccurrenceSelected(mDataSet);
}
});
}
Its the default behaviour of recyclerview. it will recycle/reuse views which are not in use currently. If you want to save the state which is colored or not. Then save a parameter in your List<Object> per position. and as per position in onBindViewHolder method use that position to change the color.
Try by Setting Tag to your item in onBindViewHolder of Adapter
holder.yourItem.setTag(position);
And then Inside the onClickListener,Just save that position in shared Pref. if it's selected, whenever you set adapter then before setting values just check that is it selected or not based on shared Pref. and perform action for same.
public void onClick(View view) {
if (!occurrence.isSelected()) {
//save position in share pref.
}
}
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);