I have a little problem with ListView. How do I clear a ListView content, knowing that it has a custom adapter?
edit -
the custom adapter class extends BaseAdapter, it looks like this:
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class MyAdapter extends BaseAdapter {
private Activity activity;
private String[] data;
private static LayoutInflater inflater = null;
public MyAdapter(Activity a, String[] str) {
activity = a;
data = str;
inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public static class ViewHolder {
public TextView text;
}
#Override
public int getCount() {
return data.length;
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View view, ViewGroup parent) {
View v = view;
ViewHolder holder;
if (v == null) {
v = inflater.inflate(R.layout.rowa, null);
holder = new ViewHolder();
holder.text= v.findViewById(R.id.dexter);
v.setTag(holder);
} else {
holder = v.getTag();
}
holder.text.setText(data[position]);
return v;
}
}
Simply write
listView.setAdapter(null);
I guess you passed a List or an Array to the Adapter. If you keep the instance of this added collection, you can do a
collection.clear();
listview.getAdapter().notifyDataSetChanged();
this'll work only if you instantiated the adapter with collection and it's the same instance.
Also, depending on the Adapter you extended, you may not be able to do this. SimpleAdapter is used for static data, thus it can't be updated after creation.
PS. not all Adapters have a clear() method. ArrayAdapter does, but ListAdapter or SimpleAdapter don't
It's simple .First you should clear your collection and after clear list like this code :
yourCollection.clear();
setListAdapter(null);
As of Android versions M and N, following works for me and would be the correct approach. Emptying the ListView or setting the Adapter to null is not the right approach and would lead to null pointer issue, invalid ListView and/or crash of the app.
Simply do:
mList.clear();
mAdapter.notifyDataSetChanged();
i.e. first you clear the list altogether, and then let the adapter know about this change. Android will take care of correctly updating the UI with an empty list. In my case, my list is an ArrayList.
In case you are doing this operation from a different thread, run this code on the UI thread:
runOnUiThread(mRunnable);
Where mRunnable would be:
Runnable mRunnable = new Runnable() {
public void run() {
mList.clear();
mAdapter.notifyDataSetChanged();
}
};;
Simple its works me:)
YourArrayList_Object.clear();
Remove your items from your custom adapter and call notifyDataSetChanged().
There is a solution for the duplicate entry in listview.
You have to declare the onBackPress()-method on your activity and write down the highlight code given below:
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
super.onBackPressed();
**
attendence_webdata.clear(); list.setAdapter(null);
--------------------------------------------------
**
}
Just put the code ListView.Items.Clear(); on your method
Call clear() method from your custom adapter .
You need to call both clear() from ArrayAdapter and notifyDataSetChanged() both.
Below is link
click
Related
I have an adapter which fills a ListView with 2 TextViews with data from a TreeMap.
When the user adds or deletes Data from the ListView, the View should be refreshed.
So here is my Adapter:
public class MyAdapter extends BaseAdapter {
private final ArrayList mData;
public MyAdapter(Map<String, String> map) {
mData = new ArrayList();
mData.addAll(map.entrySet());
}
#Override
public int getCount() {
return mData.size();
}
#Override
public Map.Entry<String, String> getItem(int position) {
return (Map.Entry) mData.get(position);
}
#Override
public long getItemId(int position) {
// TODO implement you own logic with ID
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final View result;
if (convertView == null) {
result = LayoutInflater.from(parent.getContext()).inflate(R.layout.my_adapter_item, parent, false);
} else {
result = convertView;
}
Map.Entry<String, String> item = getItem(position);
// TODO replace findViewById by ViewHolder
((TextView) result.findViewById(android.R.id.text1)).setText(item.getKey());
((TextView) result.findViewById(android.R.id.text2)).setText(item.getValue());
return result;
}}
Because I want to update the view from a dialog and on another question I read, that notifyDataSetChanged() needs to be called from the UIThread I put my notifyDataSetChanged() into a Runnable. here is it:
Runnable run = new Runnable(){
public void run(){
Log.v("in the Runnable: ", String.valueOf(colorHashMap));
adapter.notifyDataSetChanged();
}
};
And this it how the Runnable gets called in the Dialog:
DefaultColorActivity.this.runOnUiThread(run);
But I no matter what I try or do, the List just won't get updated. I need to close and reopen the activity to get the new List.
create a method in your adapter like:
public void updateList(){
notifyDataSetChanged()
}
and call this method when you want to refresh the list
Call notifyDataSetChanged() method from your Adapter class (in getView() method) which extends BaseAdapter after deleting item.
First of all you have to make changes in map (Data source of the adapter). And use Handler class(Android OS Thread) to run the thread like this
Handler handler=new Handler();
handler.post(run);
you can not create object of list.
just create reference and asign list to your list
remove this statement in you adapter class
mData = new ArrayList();
I am using the library found at:
https://github.com/tjerkw/Android-SlideExpandableListView
to provide slidedown views on my listitems. The problem I am running into is that each of my list items has a delete button which will remove the item from the underlying adapter. When this happens if the item that was removed was expanded then the item below it will become expanded. After digging through the source for the expandablelistview library I found that the culprit is a BitSet which is being used to keep track of the states of the listviews ( expanded 1, not expanded 0 ). When I remove an item from the list the list of states does not get updated. It needs to shift all values down. The problem is I am not sure how to notify the library that my adapter has had an item removed from it.
My custom list adapter extends array adapter and when I remove an item I call notifyDataSetChanged. Somehow I need to detect that call in the slideExpandablelistview which wraps my adapter so that I can update the BitSet. IF anyone has worked with this library before or care to take a look I would love some help.
I create the expanandablelistview by doing
myAdapter= new SlideExpandableListAdapter(new CustomAdapter(getActivity(), new ArrayList<CustomObject>()), R.id.contact_row, R.id.expandable);
Thanks,
Nathan
"When this happens if the item that was removed was expanded then the item below it will become expanded."
After deleting the item from your ArrayList and then doing adapter.notifyDataSetChanged(), you can do something like:
((ActionSlideExpandableListView) list).collapse();
Here is a full example that I made by modifying the author's sample that comes with the library:
package com.tjerkw.slideexpandable.sample;
import java.util.ArrayList;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import android.widget.Toast;
import com.tjerkw.slideexpandable.library.ActionSlideExpandableListView;
public class ExampleActivity extends Activity
{
PersonDB db;
ArrayList<String> people;
ArrayAdapter<String> adapter;
#Override
public void onCreate(Bundle savedData)
{
super.onCreate(savedData);
this.setContentView(R.layout.single_expandable_list);
final ActionSlideExpandableListView list = (ActionSlideExpandableListView) this.findViewById(R.id.list);
db = PersonDB.getInstance();
people = db.getPeople();
adapter = new PersonArrayAdapter(people);
list.setAdapter(adapter);
// listen for events in the two buttons for every list item.
// the 'position' var will tell which list item is clicked
list.setItemActionListener(new ActionSlideExpandableListView.OnActionClickListener() {
#Override
public void onClick(View listView, View buttonview, int position)
{
switch (buttonview.getId())
{
case R.id.buttonA:
people.remove(position);
((ArrayAdapter<String>) adapter).notifyDataSetChanged();
((ActionSlideExpandableListView) list).collapse();
break;
case R.id.buttonB:
Toast.makeText(ExampleActivity.this, "You pressed buttonB", Toast.LENGTH_SHORT).show();
}
}
// note that we also add 1 or more ids to the setItemActionListener
// this is needed in order for the listview to discover the buttons
}, R.id.buttonA, R.id.buttonB);
}
private class PersonArrayAdapter extends ArrayAdapter<String>
{
public PersonArrayAdapter(ArrayList<String> people)
{
super(ExampleActivity.this, R.layout.expandable_list_item, people);
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
// if we weren't given a view, inflate one
if (convertView == null)
{
convertView = getLayoutInflater().inflate(R.layout.expandable_list_item, null);
}
TextView textView = (TextView) convertView.findViewById(R.id.text);
textView.setText(people.get(position));
return convertView;
}
#Override
public int getCount()
{
return people.size();
}
}
}
Here is the dummy database class:
package com.tjerkw.slideexpandable.sample;
import java.util.ArrayList;
public class PersonDB
{
private static PersonDB db = null;
private ArrayList<String> people;
private PersonDB()
{
people = new ArrayList<String>();
// fill "database" with dummy data
for (int i = 0; i < 20; i++)
people.add(i, "Person " + i);
}
public static PersonDB getInstance()
{
if (db == null)
db = new PersonDB();
return db;
}
public ArrayList<String> getPeople()
{
return people;
}
public String getPerson(int i)
{
return people.get(i);
}
public void deletePerson(int i)
{
people.remove(i);
}
}
EDIT: I noticed a bug with this code. When a row is deleted and the row below it moves up to fill that space, the text on the new row's buttonA appears left-justified. The only way I could think of to solve this was to replace this line:
((ArrayAdapter<String>) adapter).notifyDataSetChanged();
with these two lines:
adapter = new PersonArrayAdapter(people);
list.setAdapter(adapter);
If anyone has a better solution I would love to see it.
When I repopulate my ListView, I call a specific method from my Adapter.
Problem:
When I call updateReceiptsList from my Adapter, the data is refreshed, but my ListView doesn't reflect the change.
Question:
Why doesn't my ListView show the new data when I call notifyDataSetChanged?
Adapter:
public class ReceiptListAdapter extends BaseAdapter {
public List<Receipt> receiptlist;
private Context context;
private LayoutInflater inflater;
private DateHelpers dateH;
public ReceiptListAdapter(Activity activity, Context mcontext, List<Receipt> rl) {
context = mcontext;
receiptlist = rl;
Collections.reverse(receiptlist);
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
dateH = new DateHelpers();
}
#Override
public int getCount() {
try {
int size = receiptlist.size();
return size;
} catch(NullPointerException ex) {
return 0;
}
}
public void updateReceiptsList(List<Receipt> newlist) {
receiptlist = newlist;
this.notifyDataSetChanged();
}
#Override
public Receipt getItem(int i) {
return receiptlist.get(i);
}
#Override
public long getItemId(int i) {
return receiptlist.get(i).getReceiptId() ;
}
private String getPuntenString(Receipt r) {
if(r.getPoints().equals("1")) {
return "1 punt";
}
return r.getPoints()+" punten";
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
final Receipt receipt = receiptlist.get(position);
ReceiptViewHolder receiptviewholder;
Typeface tf_hn = Typeface.createFromAsset(context.getAssets(), "helveticaneue.ttf");
Typeface tf_hn_bold = Typeface.createFromAsset(context.getAssets(), "helveticaneuebd.ttf");
if (vi == null) { //convertview==null
receiptviewholder = new ReceiptViewHolder();
vi = inflater.inflate(R.layout.view_listitem_receipt, null);
vi.setOnClickListener(null);
vi.setOnLongClickListener(null);
vi.setLongClickable(false);
receiptviewholder.shop = (TextView) vi.findViewById(R.id.tv_listitemreceipt_shop);
receiptviewholder.date = (TextView) vi.findViewById(R.id.tv_listitemreceipt_date);
receiptviewholder.price = (TextView) vi.findViewById(R.id.tv_listitemreceipt_price);
receiptviewholder.points = (TextView) vi.findViewById(R.id.tv_listitemreceipt_points);
receiptviewholder.shop.setTypeface(tf_hn_bold);
receiptviewholder.price.setTypeface(tf_hn_bold);
vi.setTag(receiptviewholder);
}else{//convertview is not null
receiptviewholder = (ReceiptViewHolder)vi.getTag();
}
receiptviewholder.shop.setText(receipt.getShop());
receiptviewholder.date.setText(dateH.timestampToDateString(Long.parseLong(receipt.getPurchaseDate())));
receiptviewholder.price.setText("€ "+receipt.getPrice());
receiptviewholder.points.setText(getPuntenString(receipt));
vi.setClickable(false);
return vi;
}
public static class ReceiptViewHolder {
public TextView shop;
public TextView date;
public TextView price;
public TextView points;
}
public Object getFilter() {
// XXX Auto-generated method stub
return null;
}
}
--EDIT:
found Workaround
Just to have some functional code i do now:
listview.setAdapter( new ReceiptListAdapter(activity,mcontext, -new dataset-);
Works, but not how it is supposed to work.
Change your method from
public void updateReceiptsList(List<Receipt> newlist) {
receiptlist = newlist;
this.notifyDataSetChanged();
}
To
public void updateReceiptsList(List<Receipt> newlist) {
receiptlist.clear();
receiptlist.addAll(newlist);
this.notifyDataSetChanged();
}
So you keep the same object as your DataSet in your Adapter.
I have the same problem, and i realize that. When we create adapter and set it to listview, listview will point to object somewhere in memory which adapter hold, data in this object will show in listview.
adapter = new CustomAdapter(data);
listview.setadapter(adapter);
if we create an object for adapter with another data again and notifydatasetchanged():
adapter = new CustomAdapter(anotherdata);
adapter.notifyDataSetChanged();
this will do not affect to data in listview because the list is pointing to different object, this object does not know anything about new object in adapter, and notifyDataSetChanged() affect nothing.
So we should change data in object and avoid to create a new object again for adapter
As I have already explained the reasons behind this issue and also how to handle it in a different answer thread Here. Still i am sharing the solution summary here.
One of the main reasons notifyDataSetChanged() won't work for you - is,
Your adapter loses reference to your list.
When creating and adding a new list to the Adapter. Always follow these guidelines:
Initialise the arrayList while declaring it globally.
Add the List to the adapter directly with out checking for null and empty
values . Set the adapter to the list directly (don't check for any
condition). Adapter guarantees you that wherever you make
changes to the data of the arrayList it will take care of it, but never loose the
reference.
Always modify the data in the arrayList itself (if your data is completely new
than you can call adapter.clear() and arrayList.clear() before
actually adding data to the list) but don't set the adapter i.e If
the new data is populated in the arrayList than just
adapter.notifyDataSetChanged()
Hope this helps.
Maybe try to refresh your ListView:
receiptsListView.invalidate().
EDIT: Another thought came into my mind. Just for the record, try to disable list view cache:
<ListView
...
android:scrollingCache="false"
android:cacheColorHint="#android:color/transparent"
... />
I had the same problem using ListAdapter
I let Android Studio implement methods for me and this is what I got:
public class CustomAdapter implements ListAdapter {
...
#Override
public void registerDataSetObserver(DataSetObserver observer) {
}
#Override
public void unregisterDataSetObserver(DataSetObserver observer) {
}
...
}
The problem is that these methods do not call super implementations so notifyDataSetChange is never called.
Either remove these overrides manually or add super calls and it should work again.
#Override
public void registerDataSetObserver(DataSetObserver observer) {
super.registerDataSetObserver(observer);
}
#Override
public void unregisterDataSetObserver(DataSetObserver observer) {
super.unregisterDataSetObserver(observer);
}
If adapter is set to AutoCompleteTextView then notifyDataSetChanged() doesn't work.
Need this to update adapter:
myAutoCompleteAdapter = new ArrayAdapter<String>(MainActivity.this,
android.R.layout.simple_dropdown_item_1line, myList);
myAutoComplete.setAdapter(myAutoCompleteAdapter);
Refer: http://android-er.blogspot.in/2012/10/autocompletetextview-with-dynamic.html
class StudentAdapter extends BaseAdapter {
ArrayList<LichHocDTO> studentList;
private void capNhatDuLieu(ArrayList<LichHocDTO> list){
this.studentList.clear();
this.studentList.addAll(list);
this.notifyDataSetChanged();
}
}
You can try. It work for me
If by any chance you landed on this thread and wondering why adapter.invaidate() or adapter.clear() methods are not present in your case then maybe because you might be using RecyclerView.Adapter instead of BaseAdapter which is used by the asker of this question. If clearing the list or arraylist not resolving your problem then it may happen that you are making two or more instances of the adapter for ex.:
MainActivity
...
adapter = new CustomAdapter(list);
adapter.notifyDataSetChanged();
recyclerView.setAdapter(adapter);
...
and
SomeFragment
...
adapter = new CustomAdapter(newList);
adapter.notifyDataSetChanged();
...
If in the second case you are expecting a change in the list of inflated views in recycler view then it is not gonna happen as in the second time a new instance of the adapter is created which is not attached to the recycler view. Setting notifyDataSetChanged in the second adapter is not gonna change the content of recycer view. For that make a new instance of the recycler view in SomeFragment and attach it to the new instance of the adapter.
SomeFragment
...
recyclerView = new RecyclerView();
adapter = new CustomAdapter();
recyclerView.setAdapter(adapter);
...
Although, I don't recommend making multiple instances of the same adapter and recycler view.
In my case I simply forget to add in my fragment mRecyclerView.setAdapter(adapter)
Add this code
runOnUiThread(new Runnable() { public void run() {
adapter = new CustomAdapter(anotherdata);
adapter.notifyDataSetChanged();
}
});
I made a very noob mistake that I was setting the adapter of RecyclerView before initialzing the adapter itself like this.
// Assuume oneOffJobTasksListRVAdapter is declared already
recyclerView.setAdapter(oneOffJobTasksListRVAdapter);
oneOffJobTasksListRVAdapter = new OneOffJobTasksListRVAdapter();
Switching the lines fixed my issue.
oneOffJobTasksListRVAdapter = new OneOffJobTasksListRVAdapter();
recyclerView.setAdapter(oneOffJobTasksListRVAdapter);
If you're using a custom adapter you have to add
#Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
}
to your custom adapter methods, then you only need to call notifyDataSetChanged() after you change your data, like replace, remove or add a new item
ArrayList <String> items;
int position=1;
items.set(position,"Changed Item");
items.remove(position);
items.add("New item");
notifyDataSetChanged();
I have the same problem
but I just finished it!!
you should change to
public class ReceiptListAdapter extends BaseAdapter {
public List<Receipt> receiptlist;
private Context context;
private LayoutInflater inflater;
private DateHelpers dateH;
private List<ReceiptViewHolder> receiptviewlist;
public ReceiptListAdapter(Activity activity, Context mcontext, List<Receipt> rl) {
context = mcontext;
receiptlist = rl;
receiptviewlist = new ArrayList<>();
receiptviewlist.clear();
for(int i = 0; i < receiptlist.size(); i++){
ReceiptViewHolder receiptviewholder = new ReceiptViewHolder();
receiptviewlist.add(receiptviewholder);
}
Collections.reverse(receiptlist);
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
dateH = new DateHelpers();
}
#Override
public int getCount() {
try {
int size = receiptlist.size();
return size;
} catch(NullPointerException ex) {
return 0;
}
}
public void updateReceiptsList(List<Receipt> newlist) {
receiptlist = newlist;
this.notifyDataSetChanged();
}
#Override
public Receipt getItem(int i) {
return receiptlist.get(i);
}
#Override
public long getItemId(int i) {
return receiptlist.get(i).getReceiptId() ;
}
private String getPuntenString(Receipt r) {
if(r.getPoints().equals("1")) {
return "1 punt";
}
return r.getPoints()+" punten";
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
final Receipt receipt = receiptlist.get(position);
ReceiptViewHolder receiptviewholder;
Typeface tf_hn = Typeface.createFromAsset(context.getAssets(), "helveticaneue.ttf");
Typeface tf_hn_bold = Typeface.createFromAsset(context.getAssets(), "helveticaneuebd.ttf");
if (vi == null) { //convertview==null
ReceiptViewHolder receiptviewholder = receiptviewlist.get(position);
vi = inflater.inflate(R.layout.view_listitem_receipt, null);
vi.setOnClickListener(null);
vi.setOnLongClickListener(null);
vi.setLongClickable(false);
receiptviewholder.shop = (TextView) vi.findViewById(R.id.tv_listitemreceipt_shop);
receiptviewholder.date = (TextView) vi.findViewById(R.id.tv_listitemreceipt_date);
receiptviewholder.price = (TextView) vi.findViewById(R.id.tv_listitemreceipt_price);
receiptviewholder.points = (TextView) vi.findViewById(R.id.tv_listitemreceipt_points);
receiptviewholder.shop.setTypeface(tf_hn_bold);
receiptviewholder.price.setTypeface(tf_hn_bold);
vi.setTag(receiptviewholder);
}else{//convertview is not null
receiptviewholder = (ReceiptViewHolder)vi.getTag();
}
receiptviewholder.shop.setText(receipt.getShop());
receiptviewholder.date.setText(dateH.timestampToDateString(Long.parseLong(receipt.getPurchaseDate())));
receiptviewholder.price.setText("€ "+receipt.getPrice());
receiptviewholder.points.setText(getPuntenString(receipt));
vi.setClickable(false);
return vi;
}
public static class ReceiptViewHolder {
public TextView shop;
public TextView date;
public TextView price;
public TextView points;
}
public Object getFilter() {
// XXX Auto-generated method stub
return null;
}
}
My case was different but it might be the same case for others
for those who still couldn't find a solution and tried everything above, if you're using the adapter inside fragment then the reason it's not working fragment could be recreating so the adapter is recreating everytime the fragment recreate
you should verify if the adapter and objects list are null before initializing
if(adapter == null){
adapter = new CustomListAdapter(...);
}
...
if(objects == null){
objects = new ArrayList<>();
}
I've got some troubles with notifyDataSetChanged() of a BaseAdapter. This method is called in refreshItems() and shall update the BaseAdapter of my ListActivity. On calling notifyDataSetChanged() nothing happens until I scroll down the ListView for example with the arrow keys. Somehow the modified getView() method also is not called. Maybe you can give me a hint - thanks! :)
public class WinampControlClientPlaylist extends ListActivity {
static WinampControlClientPlaylist activity = null;
static EfficientAdapter adapter = null;
static class EfficientAdapter extends BaseAdapter {
public EfficientAdapter(Context context) {
mInflater = LayoutInflater.from(context);
}
private LayoutInflater mInflater;
#Override
public int getCount() {
return Settings.playlistlength;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null)
{
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.listview, null);
holder.text = (TextView) convertView.findViewById(R.string.playlist_title);
holder.image = (ImageView) convertView.findViewById(R.string.playlist_play);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.text.setText(Settings.playlist[position]);
if (position == Settings.playlistPosition)
{
holder.text.setTypeface(null, Typeface.ITALIC);
holder.image.setVisibility(0);
}
else
{
holder.text.setTypeface(null, Typeface.NORMAL);
holder.image.setVisibility(4);
}
return convertView;
}
static class ViewHolder {
TextView text;
ImageView image;
}
#Override
public Object getItem(int position) {
return Settings.playlist[position];
}
}
void initialize()
{
adapter = new EfficientAdapter(this);
setListAdapter(adapter);
//registerForContextMenu(getListView());
}
#Override
public void onResume()
{
super.onResume();
// REFRESH PLAYLIST
if (getListAdapter() == null && Settings.playlist != null)
initialize();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.playlist);
activity = this;
}
static void refreshItems()
{
try {
adapter.notifyDataSetChanged();
} catch (Exception e) {}
}
}
I had the same problem (ListView updates only when i scroll it, even notifyDataSetChanged didn't help). i solve it this way: just try to do your "view modifications" in thread which creates your user interface i.e.
activity.runOnUiThread(new Runnable() {
public void run() {
//do your modifications here
// for example
adapter.add(new Object());
adapter.notifyDataSetChanged()
}
});
Try calling invalidate() on your ListView.
As Franco pointed out, notifyDataSetChanged() is used to tell the ListView that the contents of its adapter have changed, not that it needs to redraw itself. You are just changing a setting that affects how something is rendered. Try calling refreshDrawableState to tell the list to redraw.
I had the same issue, and the solution for me was to call requestLayout() on the ListView.
I think there may be some problems with the adapter;
maybe it's not set.
In my experience, there was always some kind of reason which prevented the listview (and adapter) to update.
call AbsListView.invalidateViews() on your listview after BaseAdapter.notifyDataSetChanged()
I encountered the same problem, and I tried to call notifyDataSetChanged() on the adapter. Besides, I also tried to call refreshDrawableState(), invalidateViews() on the view and none of those worked. All these methods are called in the UI thread. Then I found this How to clear the views which are held in the ListView's RecycleBin? . Finally setAdapter() worked, only if I create a new adapter.
The main reason behind this is the wrong reference of the adapter on which you are calling notifyDataSetChanged();
I think you need to make sure that you are creating adapter object once and call notifyDataSetChanged() on the same object.
You can debug the object reference value at creating time of adapter object and when you are calling notifyDataSetChanged() method.
Why it works in first code ?
--- Because you are setting the values to temp List and passing it the adapter and it shows it into listview.
Why not work in second code ?
--- Because you are setting temp to adapter far before you set value into temp
second,your adapter class might not getting the updated value when you set new value to temp ..that because temp is not public or not at class level or not static.. Put the temp declaration at root level and try.
And please show your full code as much as required and Logcat if you getting any warnings than also.
From this answer in stack overflow and the sample project referred there, i got the Idea of RotationAsync, where a progress bar work fine with device rotation.
But my problem is, i have a listview with each row there is progress bar. And is there any way to retain the progress while rotation for reach row.
Me creating onclicklistener object for the button click listener in getview function of my adapter class. Where its onClick function call the AsyncTask class
Since each getview (row) is calling different instant of my AsyncTask, i cannot make it static of single ton class.
Any Idea on this.
Thanks.
So you have a ListView which I assume you have some adapter which in it's get view hosts the progress bars. However that progress must be backed by something right? So just save that data. Like I am assuming an adapter like so:
public class MyProgressBarAdapter extends BaseAdapter {
private ArrayList<Integer> mProgessValues;
private SparseArray<AsyncTask<?,?,?>> mTasks;
// No stored reference to a Context
private MyProgressBarAdapter() {
}
public void saveState(Bundle bundle) {
bundle.putIntegerArrayList(getClass().getName() + ".progressValues", mProgressValues);
}
public Object exportLiveState() {
return mTasks;
}
public static MyProgressBarAdapter restore(Bundle bundle, Object rawState) {
MyProgressBarAdapter adapter = new MyProgressBarAdapter();
Class<MyProgressBarAdapter> c = adapter.getClass();
ArrayList<Integer> progresses = null;
if (bundle != null) {
progresses = bundle.getIntegerArrayList(c.getName() + ".progressValues");
}
if (progresses == null) {
progresses = new ArrayList<Integer>();
}
adapter.mProgressValues = progresses;
if (rawState != null && rawState instanceof SparseArray) {
adapter.mTasks = (SparseArray<AsyncTask<?,?,?>>) rawState;
}
return adapter;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView = getViewWithHolder(convertView, parent);
ViewHolder holder = convertView.getTag();
// set the appropriate things on the view elements.
holder.position = position;
holder.taskContainer = mTasks;
holder.progressBar.setProgress(mProgressValues.get(position));
convertView.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
ViewHolder holder = view.getTag();
int pos = holder.position;
SparseArray<AsyncTask> tasks = holder.taskContainer;
AsyncTask task = tasks.get(pos);
if (task == null) {
// Create your task
task = new AsyncTask<?, ?, ?> (...);
tasks.put(pos, task);
task.execute();
}
}
return convertView;
}
/// You can write the rest of the adapter I believe.
...
}
and then you don't really need onConfigurationChanged. Just read and save your data accordingly.
public class MyActivity extends Activity {
ListView mListView;
MyProgressBarAdapter mAdapter;
#Override
public void onCreate(Bundle savedState) {
super.onCreate();
Object[] liveState = getLastNonConfigurationInstance();
setContentView(R.layout.mylistview_with_progressbars);
mListView = findViewById(R.id.listview);
// Be consistent with the index
MyProgressBarAdapter adapter = MyProgressBarAdapter.restore(savedState, liveState[0]);
mListView.setAdapter(adapter);
mAdapter = adapter;
...
}
#Override
public void onSaveInstanceState(Bundle bundle) {
mAdapter.save(bundle);
}
#Override
public Object[] onRetainNonConfigurationInstance () {
// size to be whatever live state you need to store other than the adapter
Object[] objects = new Object[1];
// This reference will be retained between onCreate() and onDestroy() calls.
objects[0] = mAdapter.exportLiveState();
// Any other things that can't be serialized
return objects;
}
#Override
public Object[] getLastNonConfigurationInstance() {
Object[] live = (Object[]) super.getLastNonConfigurationInstance();
if (live == null) {
live = new Object[1];
}
return live;
}
// The rest of your activity
...
}
That will make it so that when you flip the orientation, the adapter will be recreated but it will be reinitialized to the same state it was in before. I made some assumptions about the way you store your progress and the nature of your asyncTasks but I hope you can adjust as needed.
You could even, if you don't store a reference to any context, you might be able to get away with just storing the entire adapter itself inside the onRetainNonConfigurationInstance() and using that in the getLastRetainedNonConfigurationInstance()
You can set android:configChanges="orientation" in manifest file to make your activity does not restart when rotating
One solution that i used
If we have only one layout for both landscape and portrait mode, then we can we can solve this by
1. Set the activity asandroid:configChanges="orientation" in manifest file
2. Override the onConfigurationChanged like this
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
But the problem is still the if i need to use different layout for both landscape and portrait mode, each have a listview with progress bar in each row. there i need to retain the progress while rotate which use same AsyncTask class.
How can you set percentage value for each row item? Why don't you update that value to the data item. You can have some thing like below. Since you have the data item you can store whatever you want :) Ps: I wonder that I can format text in comment to not add new answer.
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView,
ViewGroup parent)
public Object getChild(int groupPosition, int childPosition)