Replace ArrayAdapter's dataset - android

In Android, you can provide an ArrayList when creating an ArrayAdapter for a ListView. I need to update a number of items in the ArrayList.
The ususal way is to just call notifyDatasetChanged. What I prefer to do is reload the entire data into a new ArrayList from my database and then apply this new ArrayList to the existing ArrayAdapter but without creating a new adapter. Creating a new adapter will cause the ListView to go blank and start with position zero. This would also be obvious if the user were scrolling and I suddenly recreated a new adapter.
Is it possible to apply a completely new ArrayList to the existing adapter? The primary reason I want to do this is because it is very fast to just reload a new ArrayList with all the data than having to go through an existing ArrayList and inserting, deleting or updating existing items.

1) First of all. You need to use custom ArrayAdapter (or SimpleAdapter or RecycleViewAdapter)
2) Than create function in your custom adapter :
// Initialize your list;
private ArrayList<Model> arrayList;
.....
//Create constructor and past starting ArrayList
public MyAdapter (ArrayList<Model> array) {
this.arrayList = array;
}
......
public void updateMyData (ArrayList array) {
clear();
// Or you can use arrayList.addAll(array); - just add new items
this.arrayList = array;
notifyDataSetChange();
}
.....
3) In your Activity (or where you initialize adapter)
just use code like this:
MyAdapter myAdapter = new MyAdapter(startArratListData);
// And Than for updating data:
myAdapter.updateMyData(newArrayListData);

Related

Refresh listview data from custom ArrayAdapter which is populated by SQLite Database

I have a custom ArrayAdapter which is set to a listview with data from database:
CustomAdapter adapter = new CustomAdapter(myview.getContext(), -1, database.getAll());
listview.setAdapter(adapter);
Now, I want when the user deletes a database item the listview should refresh.
Until now, I can successfully delete the item from the database, but it remains in the listview. In the ArrayAdapter class I call refresh() method from a new class same to adapter's parent class
public void refresh(){
ParentClass class_par = new ParentClass();
class_par.refreshfromParent();
}
And in the ParentClass I have a new method: refreshfromParent()
public void refreshfromAlarm(){
DatabaseHandler database = new DatabaseHandler(myview.getContext());
listview.setAdapter(new CustomAdapter(myview.getContext(), -1, database.getAll())); // here I change listview adapter, and populate it with new database data, but I get NullPointerException
}
So, how can I refresh listview items? Please, DO NOT mention notifyDataSetChanged(), it DOES NOT work.
here you making en error
CustomAdapter adapter = new CustomAdapter(myview.getContext(), -1, database.getAll());
listview.setAdapter(adapter);
//so first you should make an arrayList and define it globally like
// ArrayList <yourType>list = new ArrayList<>();
//then initialize your adapter like this
list.addAll(databse.getAll());
CustomAdapter adapter = new CustomAdapter(myview.getContext(), -1, list);
listview.setAdapter(adapter);
// now when you want to delete an item
// delete it from your list like list.remove(location)
// and also delete same item from your datebase
// after that just call this
notifyDataSetChanged();
I realized that notifyDataSetChanged is a big trouble, so I decided to close and reload my fragment which contains my listview. Thus, the result looks the same with DataSetChanged and there is no difference in the users' eyes. I suggest everyone who reaches in this question do the same.

How to add Listview as footer in listview in android?

I have Mainactivity which contain listview with some item and I want to add another listview in that listview as footer.How can I add this
Its not recommended to add a ListView as a footer of another ListView. You might consider making a list of objects containing both list and pass the list to your Adapter.
So if you merge two lists in a common format, you need to be tricky for the layout selection for each item in your list. Let me show you an example of a common class.
public class CommonClass {
// Set null values initially.
private ClassA mFirstListClass = null;
private ClassB mSecondListClass = null;
}
Now take an ArrayList of this object to pass it to your Adapter. In your bindView check if the item is a ClassA object or ClassB object (as you can easily determine them by checking which object is null) and then set proper action.
I think for these kinds of problems RecyclerView is better. Its very simple to implement and you can find the implementation document here.
// Create a List from String Array elements
final List<String> tests = new ArrayList<String>(Arrays.asList(test));
// Create an ArrayAdapter from List
final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>
(this, android.R.layout.simple_list_item_1, tests);
// DataBind ListView with items from ArrayAdapter
lv.setAdapter(arrayAdapter);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Add new Items to List
tests.add("abc");
tests.add("def");
/*
notifyDataSetChanged ()
Notifies the attached observers that the underlying
data has been changed and any View reflecting the
data set should refresh itself.
*/
arrayAdapter.notifyDataSetChanged();
}
});
for more http://android--code.blogspot.in/2015/08/android-listview-add-items.html

Best way to update data with a RecyclerView adapter [duplicate]

This question already has answers here:
How to update RecyclerView Adapter Data
(16 answers)
Closed 5 years ago.
When I have to use a classic adapter with a ListView, I update my data in the ListView like this:
myAdapter.swapArray(data);
public swapArray(List<Data> data) {
clear();
addAll(data);
notifyDataSetChanged();
}
I would like to know what is the best practice for a RecyclerView. Because in a RecyclerView adapter you can't do a clear and addAll as in ListView.
So I tried just with a notifyDataSetChanged, but it didn't work.
Then I tried with a swapAdapter on my view:
List<Data> data = newData;
MyRecyclerAdapter adapter = new MyRecyclerAdapter(data);
// swapAdapter on my recyclerView (instead of a .setAdapter like with a classic listView).
recyclerViewList.swapAdapter(adapter, false);
But with this last solution, I still have to create a new instance of my adapter and I feel like it's not the best solution. I should be able just to change my data without a new MyRecyclerAdapter.
RecyclerView's Adapter doesn't come with many methods otherwise available in ListView's adapter. But your swap can be implemented quite simply as:
class MyRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
List<Data> data;
...
public void swap(ArrayList<Data> datas)
{
data.clear();
data.addAll(datas);
notifyDataSetChanged();
}
}
Also there is a difference between
list.clear();
list.add(data);
and
list = newList;
The first is reusing the same list object. The other is dereferencing and referencing the list. The old list object which can no longer be reached will be garbage collected but not without first piling up heap memory. This would be the same as initializing new adapter everytime you want to swap data.
#inmyth's answer is correct, just modify the code a bit, to handle empty list.
public class NewsAdapter extends RecyclerView.Adapter<...> {
...
private static List mFeedsList;
...
public void swap(List list){
if (mFeedsList != null) {
mFeedsList.clear();
mFeedsList.addAll(list);
}
else {
mFeedsList = list;
}
notifyDataSetChanged();
}
I am using Retrofit to fetch the list, on Retrofit's onResponse() use,
adapter.swap(feedList);
DiffUtil can the best choice for updating the data in the RecyclerView Adapter which you can find in the android framework. DiffUtil is a utility class that can calculate the difference between two lists and output a list of update operations that converts the first list into the second one.
Most of the time our list changes completely and we set new list to RecyclerView Adapter. And we call notifyDataSetChanged to update adapter. NotifyDataSetChanged is costly. DiffUtil class solves that problem now. It does its job perfectly!
Found following solution working for my similar problem:
private ExtendedHashMap mData = new ExtendedHashMap();
private String[] mKeys;
public void setNewData(ExtendedHashMap data) {
mData.putAll(data);
mKeys = data.keySet().toArray(new String[data.size()]);
notifyDataSetChanged();
}
Using the clear-command
mData.clear()
is not nessescary

Android ListView adapter data, mantaining consistency

When you create a custom adapter extending ArrayAdapter<T>, it has usually the form:
public class ListAdapter extends ArrayAdapter<Item> {
private List<Item> mData;
public ListAdapter(Context context, int resource, List<Item> data) {
super(context, resource, data);
mData = data;
}
}
The data is initially saved in a private member mData, but also the ArrayAdapter saves the data in its own member mObjects. I am pretty sure those are not actual copies, but references to the same list.
Now, and this is my question, if during the ListView processing, for some reason, you have to replace your own list with a fresh new List, I think you should also do:
mData = new List<Item>();
super.clear();
super.addAll(mData);
otherwise there will be no consistency in ListView, and methods like getFilter().filter() will not work.
Am I correct?
I think, when you say mData = data; it only copies pointer of the data array, because when you execute that;
ListAdapter adapter = new ListAdapter(context, resource, data);
data.clear();
adapter.notifyDataSetChanged();
it changes list. So it keeps pointer of your source array,
Second, I think (not sure) you cannot use filter function of adapter, at least I couldn't use and write my own filter function. I filter elements from sqlite(I take my elements from database). and use notifyDataSetChanged function of adapter.
You are right. Your ListAdapter doesn't make a deep copy of the provided list of Items. This means that changing an Item instance 'outside' the ListAdapter will put the ListAdapter in an invalid state.
However, you can 'fix' this by calling notifyDataSetChanged on the ListAdapter.
List<Item> itemList = ....
....
....
ListAdapter adapter = new ListAdapter(this, R.layout.somelayout, itemList);
....
Now, if you change an item 'outside' the ListAdapter, you can still make your ListAdapter be in sync with the change:
itemList.get(idx).changeSomethingInItem("Hello"); // Changes the Item at index 'idx'.
adapter.notifyDataSetChanged(); // Notify adapter about this change.
you really needn't pretty sure whether it actual copies or not ,just extend BaseAdapter

android ArrayAdapter items update

I have ArrayAdapter with this items structure:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout ... >
<TextView
android:id="#+id/itemTextView"
... />
</RelativeLayout>
And add this adapter so:
mAdapter = new ArrayAdapter<String>(this, R.layout.item,
R.id.itemTextView, itemsText);
All is fine but I want to update text in adapter's items. I found a solution
mAdapter.notifyDataSetChanged();
but do not understand how to use it. Help please.
upd
My code:
String[] itemsText = {"123", "345", "567"};
ArrayAdapter<String> mAdapter;
onCreate
mAdapter = new ArrayAdapter<String>(this, R.layout.roomitem,
R.id.itemTextView, itemsText);
setListAdapter(mAdapter);
itemsText = {"789", "910", "1011"};
onClick
mAdapter.notifyDataSetChanged();
//it's dont work
I think something like this
public void updatedData(List itemsArrayList) {
mAdapter.clear();
if (itemsArrayList != null){
for (Object object : itemsArrayList) {
mAdapter.insert(object, mAdapter.getCount());
}
}
mAdapter.notifyDataSetChanged();
}
Your problem is a typical Java error with pointers.
In a first step you are creating an array and passing this array to the adapter.
In the second step you are creating a new array (so new pointer is created) with new information but the adapter is still pointing to the original array.
// init itemsText var and pass to the adapter
String[] itemsText = {"123", "345", "567"};
mAdapter = new ArrayAdapter<String>(..., itemsText);
//ERROR HERE: itemsText variable will point to a new array instance
itemsText = {"789", "910", "1011"};
So, you can do two things, one, update the array contents instead of creating a new one:
//This will work for your example
items[0]="123";
items[1]="345";
items[2]="567";
... or what I would do, use a List, something like:
List<String> items= new ArrayList<String>(3);
boundedDevices.add("123");
boundedDevices.add("456");
boundedDevices.add("789");
And in the update:
boundedDevices.set("789");
boundedDevices.set("910");
boundedDevices.set("1011");
To add more information, in a real application normally you update the contents of the list adapter with information from a service or content provider, so normally to update the items you would do something like:
//clear the actual results
items.clear()
//add the results coming from a service
items.addAll(serviceResults);
With this you will clear the old results and load the new ones (think that the new results should have a different number of items).
And off course after update the data the call to notifyDataSetChanged();
If you have any doubt don't hesitate to comment.
Assuming itemTexts as String array or String ArrayList,where you are adding new items into itemsTextat that time after that you can call
mAdapter.notifyDataSetChanged();
If you did not get answer then please put some code.
I did something like this. And it works correctly.
Add method to the Adapter class:
public void updateList(ArrayList<ITEM> itemList){
this.itemList.clear();
this.adapterList = new ArrayList<ITEM>();
this.adapterList .addAll(itemList);
notifyDataSetChanged();
}
Call the method in the class you use the adapter:
itemList.add(item);
adapter.updateList(itemList);

Categories

Resources