I have a problem dealing with recyclerview, when i return back to the activity after opening another activity, it duplicates all the items i displayed. Is there any way to fix this?
Like on list view, it just automatically clears the list and then display it again. can you show me how? thanks
OnCreate
int x = 0;
for(String Name : property_name){
JSONObject jsonObject = arrayResponse.getJSONObject(x);
property_id[x] = jsonObject.getString("property_id");
property_name[x] = jsonObject.getString("property_name");
type[x] = jsonObject.getString("property_type");
price[x] = jsonObject.getString("price");
address[x] = jsonObject.getString("address");
ListingNearby listingNearby = new ListingNearby(property_id[x], property_name[x], type[x], price[x], Math.round(distance[x]));
x++;
list.add(listingNearby);
}
recyclerView = (RecyclerView) findViewById(R.id.ln_recycler_view);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
adapter = new ListingNearbyAdapter(list);
recyclerView.setAdapter(adapter);
I wonder what to put in onResume so that the listview clears the list and then display it again.
Just try to list.clear() before you begin your loop. I guess your list is kind of static variable.
override these two method in your adapter:
#Override
public int getItemCount() {
return reviewModels.size();
}
#Override
public long getItemId(int position) {
return position;
}
it worked for me
Related
I'm trying to update my recyclerview using notifyDataSetChanged() but it doesn't work. I am setting the adapter to the recyclerview like this:
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(ctx, LinearLayoutManager.VERTICAL, false);
lstSong.setLayoutManager(mLayoutManager);
lstSong.setItemAnimator(new DefaultItemAnimator());
lstSong.addItemDecoration(new GridSpacingItemDecoration(2, dpToPx(0), true));
arrSong = new ArrayList<Song>();
arrSong = kFunc.getAllSong();
songAdapter = new SongAdapter(ctx, arrSong);
lstSong.setAdapter(songAdapter);
This lines of code displays the data. But when i add a new data and refresh the recyclerview with songAdapter.notifyDataSetChanged(); the data won't show up. I know i can display it by using setAdapter() but i want to do it properly.
I add the data before I make the refresh. This is the code:
kFunc = new Function(ctx);
Song song = new Song();
song.setTitle(title);
song.setArtist(artist);
song.setYear_released(yearReleased);
song.setAlbum(album);
song.setGenre(genre);
song.setDuration(duration);
song.setCode(code);
song.setLyrics(lyrics);
kFunc.addSong(song);
dialog.dismiss();
arrSong = kFunc.getAllSong();
songAdapter.notifyDataSetChanged();
Create a method inside adapter like
public updateItems(ArrayList<Song> songs){
arrSong=songs;
}
And while getting new values in your class call the method using adapdter object
lstSong.updateItems(arrSong);
notifyDataSetChanged();
I don't know where you added new item to RecyclerView.Adapter. This is a sample code to add and set a item. More detail Sample RecyclerViewAdapter
#Override
public void addItem(M item) {
items.add(item);
notifyItemInserted(items.size() - 1);
}
#Override
public void addItem(int position, M item) {
items.add(position, item);
notifyItemInserted(position);
}
#Override
public void addAllItems(List<M> items) {
this.items.addAll(items);
notifyDataSetChanged();
}
#Override
public void setItems(List<M> items) {
this.items = items;
notifyDataSetChanged();
}
You should try by updating the list of the songs before you notify the adapter.
for example
arraySongs = <retrive updated data of the song>;
adapter.notifyDataStateChanged()
if you are in ListView which you are not but for you information only.
adapter.lstSong =<updated songs List>;
adapter.notifyDataStteChanged();
try this this worked for me.
happy coding. :)
In my App I have crated a MyList.class which looks like this:
public class MyList {
private ArrayList<Obj> objList = new ArrayList<>();
//adds object to list
public void addObjToList(Obj obj) {
objList.add(obj);
}
//gets the whole list
public static ArrayList getObjList() {return objList;}
//gets the size of the list
public static int getObjListSize() {return objList.size();}
//removes obj from list based on his position
public void removeObj(int pos) {
objList.remove(pos);
}
}
From the CreateObj.class where I create the Obj I have this code to add it to the objList:
// creates the new object
Obj newObj = new Obj("Name", 3 /*int*/ );
// creates a new List
MyList myList = new MyList();
// adds the obj into the list
myList.addObjToList(newObj);
It successfully adds the obj to the list. Now from my Main_Activity.class I need to retrieve it and inflate it into a recyclerView, which I do in the onCreate() method like this:
currentObjList = MyList.getObjList();
//puts list into recycler
recyclerView = (RecyclerView) findViewById(R.id.recycler);
recyclerView.setLayoutManager(new LinearLayoutManager(this,
LinearLayoutManager.VERTICAL, false));
adapter = new RecyclerAdapter(this, currentObjList);
recyclerView.setAdapter(adapter);
Notice that I do not set MyList myList = new MyList() in my Main_Activity because I want the list to be the one created in the CreateObj class.
Obviously this is not the right way to do it, because if, let's say I want to delete an element from the recyclerView, I need to remove it from the objList (in the MyList.class) too, and that's not possible since I cannot access the MyList.class methods without setting a new MyList(), and if I do set it to new, It would not keep the Obj added from the CreateObj class.
In short: How can I have the same objList to be both accessible and modifiable from both, CreateObj.class and Main_Activity.class.
Following my comment this is a draft of what I was suggesting.
Please note I haven't ran this code so it must have errors and typos, it is just to reflect the idea of what I was proposing.
The Activity that receives the input holds a referenct to the class that creates the object and to the class that holds the ArrayList.
Upon user input, the activity asks the object creator to create an ojbect and passes it back to the activity. Then the activity adds it to the list.
And finally it notifies the recycler adapter that the data has changed.
In MainActivity:
private CreateObj createObj;
private MyList myList;
//Other memeber variables for Input elements on the screen
//used in createObje.create() to build the new object.
public void onCreate(...){
...
createObj = new CreateObj();
myList = new MyList();
currentObjList = MyList.getObjList();
//puts list into recycler
recyclerView = (RecyclerView) findViewById(R.id.recycler);
recyclerView.setLayoutManager(new LinearLayoutManager(this,
LinearLayoutManager.VERTICAL, false));
adapter = new RecyclerAdapter(this, currentObjList);
recyclerView.setAdapter(adapter);
...
aUserConfirmInputElement.setOnClickListener(new OnClickListener()){
public void onClick(){
Obj obj = createObj.create();
myList.addObjectToList(obj);
adapter.notifyDataSetChanged();
}
}
...
}
I have a RecyclerView which displays two pieces of data in each row.
Both are from a List Players.
What I need is to update the second piece of data (which is a counter, an int) each time an element is clicked.
Basically I have this players List modified, but don't know how to put it back in to the RecyclerView edited.
My Adapter Code
TextView name;
TextView counter;
CoursesViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
name = (TextView) itemView.findViewById(R.id.textName);
counter = (TextView) itemView.findViewById(R.id.textCounter);
}
[...]
#Override
public void onBindViewHolder(CoursesViewHolder holder, int position) {
Player player = mArrayCourses.get(position);
holder.name.setText(player.getName());
holder.counter.setText(String.valueOf(player.getCount()));
}
What I've tried
adapter = new CoursesAdapter(players);
myList.setAdapter(adapter);
myList.invalidate();
Edit:
// Piece of code of the activity where my RecyclerView is
myList = (RecyclerView) findViewById(R.id.playersVote);
myList.setLayoutManager(new LinearLayoutManager(this));
adapter = new CoursesAdapter(players);
myList.setAdapter(adapter);
// RecyclerView with a click listener
CoursesAdapter clickAdapter = new CoursesAdapter(players);
clickAdapter.setOnEntryClickListener(new CoursesAdapter.OnEntryClickListener() {
#Override
public void onEntryClick(View view, int position) {
// Let each player vote (ghosts too)
Player player = players.get(position);
player.incrementCount();
//Toast.makeText(ListPlayersVote.this, String.valueOf(player.getCount()), Toast.LENGTH_SHORT).show();
votes++;
Every time that your data change you should notify those changes in the adapter, using notifyDataSetChanged()
notifyDataSetChanged(): Notifies the attached observers that the underlying data has been
changed and any View reflecting the data set should refresh itself.
like this:
adapter = new CoursesAdapter(players);
myList.setAdapter(adapter);
....
....
adapter.notifyDataSetChanged();
Use the below code to change the particular Item in a recyclerview
public void updatedelivact(String value,int index) {
ChatMessage chatMessage = getItem(index);
Collection<Integer> readIds = chatMessage.getDeliveredIds();
readIds.add(userid);
chatMessage.setReadIds(readIds);
//To change the perticular item
notifyItemChanged(index);
}
I am trying to remove all the elements from my RecyclerView in my onRestart method so the items don't get loaded twice:
#Override
protected void onRestart() {
super.onRestart();
// first clear the recycler view so items are not populated twice
for (int i = 0; i < recyclerAdapter.getSize(); i++) {
recyclerAdapter.delete(i);
}
// then reload the data
PostCall doPostCall = new PostCall(); // my AsyncTask...
doPostCall.execute();
}
But for some reason the delete method I created in the adapter is not functioning properly:
in RecyclerAdapter.java:
public void delete(int position){
myList.remove(position);
notifyItemRemoved(position);
}
public int getSize(){
return myList.size();
}
I think every other item in my list gets deleted instead of the entire list.
With a listview it was so easy and I simply called adapter.clear().
Can someone please help me fix up the code?
I think I should be using notifyItemRangeRemoved(...,...); but I am not sure how. TIA
This works great for me:
public void clear() {
int size = data.size();
if (size > 0) {
for (int i = 0; i < size; i++) {
data.remove(0);
}
notifyItemRangeRemoved(0, size);
}
}
Source: https://github.com/mikepenz/LollipopShowcase/blob/master/app/src/main/java/com/mikepenz/lollipopshowcase/adapter/ApplicationAdapter.java
or:
public void clear() {
int size = data.size();
data.clear();
notifyItemRangeRemoved(0, size);
}
For you:
#Override
protected void onRestart() {
super.onRestart();
// first clear the recycler view so items are not populated twice
recyclerAdapter.clear();
// then reload the data
PostCall doPostCall = new PostCall(); // my AsyncTask...
doPostCall.execute();
}
Avoid deleting your items in a for loop and calling notifyDataSetChanged in every iteration. Instead just call the clear method in your list myList.clear(); and then notify your adapter
public void clearData() {
myList.clear(); // clear list
mAdapter.notifyDataSetChanged(); // let your adapter know about the changes and reload view.
}
setAdapter(null);
Useful if RecycleView have different views type
recyclerView.removeAllViewsInLayout();
The above line would help you remove all views from the layout.
For you:
#Override
protected void onRestart() {
super.onRestart();
recyclerView.removeAllViewsInLayout(); //removes all the views
//then reload the data
PostCall doPostCall = new PostCall(); //my AsyncTask...
doPostCall.execute();
}
This is how I cleared my recyclerview and added new items to it with animation:
mList.clear();
mAdapter.notifyDataSetChanged();
mSwipeRefreshLayout.setRefreshing(false);
//reset adapter with empty array list (it did the trick animation)
mAdapter = new MyAdapter(context, mList);
recyclerView.setAdapter(mAdapter);
mList.addAll(newList);
mAdapter.notifyDataSetChanged();
Help yourself:
public void clearAdapter() {
arrayNull.clear();
notifyDataSetChanged();
}
I use this. This actually clears the recylerview completely. I had tried adapter.notifyDataSetChanged(); but it was just not updating any view in my case. Of course U had cleared the list first. But below code works fine and clears view of recyclerview completely.
listName.clear(); // clear list
adapter = new ModelAdaptor(Activity.this, listName);
recyclerView.setAdapter(adapter);
Another way to clear the recycleview items is to instanciate a new empty adapter.
mRecyclerView.setAdapter(new MyAdapter(this, new ArrayList<MyDataSet>()));
It's probably not the most optimized solution but it's working like a charm.
ListView uses clear().
But, if you're just doing it for RecyclerView. First you have to clear your RecyclerView.Adapter with notifyItemRangeRemoved(0,size)
Then, only you recyclerView.removeAllViewsInLayout().
For my case adding an empty list did the job.
List<Object> data = new ArrayList<>();
adapter.setData(data);
adapter.notifyDataSetChanged();
private void clearRecyclerView() {
CustomListViewValuesArr.clear();
customRecyclerViewAdapter.notifyDataSetChanged();
}
use this func
On Xamarin.Android, It works for me and need change layout
var layout = recyclerView.GetLayoutManager() as GridLayoutManager;
layout.SpanCount = GetItemPerRow(Context);
recyclerView.SetAdapter(null);
recyclerView.SetAdapter(adapter); //reset
You have better clear the array-list that you used for recyleview adapter.
arraylist.clear();
public void clearData() {
mylist.removeAll(mylist);
mAdapter.notifyDataSetChanged();
recyclerView.setAdapter(mAdapter);
}
My application is returning the latest data from firebase to the buttom of the ListView. But I want it to be on the top! I have thought about it and I think there is only two possible ways to do it.
1. Invert the Listview.
I think that this way is how it should be done but I couldn't figure it out. I have searched a lot on the web but no suitable solution for my case
This is my adapter code
public void onStart() {
super.onStart();
// Setup our view and list adapter. Ensure it scrolls to the bottom as data changes
final ListView listView = getListView();
// Tell our list adapter that we only want 50 messages at a time
mChatListAdapter = new ChatListAdapter(mFirebaseRef.limit(50), this, R.layout.chat_message, mUsername);
listView.setAdapter(mChatListAdapter);
}
And this is the code for the ChatListAdapter constructor for a custom list class ChatListAdapter which extends special list adapter class FirebaseListAdapter:
public ChatListAdapter(Query ref, Activity activity, int layout, String mUsername) {
super(ref, Chat.class, layout, activity);
this.mUsername = mUsername;
}
[Edit] This is some of the code for FirebaseListAdapter which extends BaseAdapter class
public FirebaseListAdapter(Query mRef, Class<T> mModelClass, int mLayout, Activity activity) {
this.mRef = mRef;
this.mModelClass = mModelClass;
this.mLayout = mLayout;
mInflater = activity.getLayoutInflater();
mModels = new ArrayList<T>();
mModelKeys = new HashMap<String, T>();
// Look for all child events. We will then map them to our own internal ArrayList, which backs ListView
mListener = this.mRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
T model = dataSnapshot.getValue(FirebaseListAdapter.this.mModelClass);
mModelKeys.put(dataSnapshot.getKey(), model);
// Insert into the correct location, based on previousChildName
if (previousChildName == null) {
mModels.add(0, model);
} else {
T previousModel = mModelKeys.get(previousChildName);
int previousIndex = mModels.indexOf(previousModel);
int nextIndex = previousIndex + 1;
if (nextIndex == mModels.size()) {
mModels.add(model);
} else {
mModels.add(nextIndex, model);
}
}
}
2. Descending query the data.
The second way seams impossible to me, because when I searched on Firebase API documentation and on the web, I couldn't find anyway to order retraived data on descending way.
My data on firebase look like the following:
glaring-fire-9714
chat
-Jdo7-l9_KBUjXF-U4_c
author: Ahmed
message: Hello World
-Jdo71zU5qsL5rcvBzRl
author: Osama
message: Hi!
Thank you.
A simple solution would be to manually move the newly added data to the top of the listview. As you rightly noticed, new data added to a listview will automatically be appended to the bottom of the list, but you may freely move entries once they are added. Something like the following would help you manually move the newest entry to the top of the list:
int iSwapCount = listView.getCount() - 1;
int iPosition = listView.getCount() - 1;
for (int j = 0; j < iSwapCount; j++)
{
Collections.swap(yourlistobject, iPosition, iPosition - 1);
iPosition = iPosition - 1;
}
The above code will begin by calculating the number of swaps that will be required to move last list entry to the top of the list, which is determined by the number of elements in the list - 1. The same is true for calculating the last position in the list. From there Collections.swap will be used to swap the last element in the list with the element before it; this will be repeated until the last element is now the first element, with the rest of the entries in the list remaining in the same order. This code would have to be called each time a new entry is added so that the overall order of the list is maintained.
I realize it has been a while since you asked but I had the same issue. It does not appear that there is a direct answer here.
Here's the change to the firebase adapter to get new items on the top of the list.
Notice the change from add(...) to add(0,...) and add(next...) to add(prev...)
Look for comments:
// prepend instead append
Example:
...
// Insert into the correct location, based on previousChildName
if (previousChildName == null) {
mModels.add(0, model);
mKeys.add(0, key);
} else {
int previousIndex = mKeys.indexOf(previousChildName);
int nextIndex = previousIndex + 1;
if (nextIndex == mModels.size()) {
//mModels.add(model);
//mKeys.add(key);
// prepend instead append
mModels.add(0,model);
mKeys.add(0,key);
} else {
//mModels.add(nextIndex, model);
//mKeys.add(nextIndex, key);
// prepend instead append
mModels.add(previousIndex, model);
mKeys.add(previousIndex, key);
}
}
...
Here is a simple way to invert a FirebaseUI list using a RecyclerView:
boolean reverseList = true;
LinearLayoutManager manager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, reverseList);
if (reverseList) {
manager.setStackFromEnd(true);
}
mRecyclerView.setLayoutManager(manager);