updating/refreshing List with custom ListAdapter - android

I am aware that there are plenty of similar questions, but they all have in common, that their solutions dont work with my list :(
I am trying to get my userList refreshing itself via the custom ArrayAdapter, when the database-contents are changed. In my case when i reset();
here my snippets (partial code):
MainActivity.java
public class MainActivity extends ListActivity {
private MyUserListAdapter myUserlistAdapter;
public ArrayList<User> myUserList = new ArrayList<User>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//shortened the list-filling. but it works properly!
User user = db.readUser(int);
myUserList.add(user);
myUserlistAdapter = new MyUserListAdapter(this, R.layout.row_main, myUserList);
setListAdapter(myUserlistAdapter);
//now when reset-button is hit, the listview should refresh itself
bReset.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//this is what is posted in most questions, but it does nothing for me
//myUserlistAdapter.notifyDataSetChanged();
//getListView().invalidateViews();
} });
and here myUserListAdapter.java:
public class MyUserListAdapter extends ArrayAdapter<User>{
private Context context;
private ArrayList<User> userList;
public MyUserListAdapter(Context context,
int textViewResourceId, ArrayList<User> userList) {
super(context, textViewResourceId, userList);
this.context = context;
this.userList = userList;
}
public View getView(int position, View v, ViewGroup parent) {
if (v == null) {
LayoutInflater li = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = li.inflate(R.layout.row_main, null);
}
User user = getItem(position);
TextView tvUser = (TextView) v.findViewById(R.id.tvUser);
ImageView ivVoted = (ImageView) v.findViewById(R.id.ivVoted);
tvUser.setText(user.getName());
//abfrage ob hasVoted() = true muss noch eingebaut werden.
if (user.getVoted().equals("1"))
ivVoted.setImageResource(R.drawable.redcheck);
else
ivVoted.setImageResource(R.drawable.greencheck);
return v;
}
}
User.java is just a simple object-class. think its not the troublemaker here!
any help is appreciated!!! thx :-)

I am trying to get my userList refreshing itself via the custom
ArrayAdapter, when the database-contents are changed.
Since you are using ArrayAdapter and not CursorAdapter when you update data in database your adapter won't refresh itself. Whenever you want to update ListView you need to provide new datasource for Adapter.
One possible solution is to create setter in adapter subclass that will change datasource of adapter.
Pseudo code:
/* setter in adapter subclass */
public void changeDataSource(ArrayList<User> newUserList) {
this.userList = newUserList;
}
Then call adapter.notifyDataSetChanged(); for ListView update.

Try this:
arrayAdapter.clear()
for(Object o : objects)
arrayAdapter.add(o)
clear() and add() call to notifyDataSetChanged() itself.

Related

addValueEventListener brings anything

I'm having some problem with Firebase method addValueEventListner().
My code should bring me user messages from my database and show it in a ListView called conversa, but it's not getting anything back.
Debugging the code, it did not enter in new ValeuEventListener(...) and getView() neither, although getView is working fine.
I made a teste filling the ArrayList with Mensagem local objetcs and it works.
Anyone knows where am I messing up?
The conversation activity:
public class ConversaActivity extends AppCompatActivity {
<...>
mensagens = new ArrayList<>();
adapter = new MensagemAdapter(
ConversaActivity.this,
mensagens);
conversa.setAdapter(adapter);
//Buscando todas as mensagens
firebase = ConfigFirebase.getFirebase();
firebase.child("mensagem").child(id_remetente).child(id_destinatario);
//Listener para as mensagens
valueEventListenerMensagem = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
mensagens.clear();
for(DataSnapshot dados: dataSnapshot.getChildren()) {
Mensagem mensagem_recuperada = dados.getValue(Mensagem.class);
mensagens.add(mensagem_recuperada);
}
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
firebase.addValueEventListener(valueEventListenerMensagem);
<...>
}
The messages adapter:
public class MensagemAdapter extends ArrayAdapter<Mensagem> {
private Context context;
private ArrayList<Mensagem> mensagens;
public MensagemAdapter(Context c, ArrayList<Mensagem> objects) {
super(c, 0, objects);
this.context = c;
this.mensagens = objects;
}
#Override
public View getView(int position, #Nullable View convertView, ViewGroup parent) {
View view = null;
if(mensagens != null) {
Preferencias preferencias = new Preferencias(context);
String id_remetente = preferencias.getIdentificador();
//Inicializando metódo que traz o layout
LayoutInflater inflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
Mensagem mensagem_index = mensagens.get(position);
if(id_remetente.equals(mensagem_index.getIdUsuario())) {
view = inflater.inflate(R.layout.item_mensagem_enviada, parent, false);
TextView textoMensagem = (TextView) view.findViewById(R.id.id_msg_enviada);
textoMensagem.setText(mensagem_index.getMensagem());
} else {
view = inflater.inflate(R.layout.item_mensagem_recebida, parent, false);
TextView textoMensagem = (TextView) view.findViewById(R.id.id_msg_recebidas);
textoMensagem.setText(mensagem_index.getMensagem());
}
}
return view;
}
}
Firebase "mensagens" branchs are like - added with .push():
mensagens
id_remente
id_destinatario
mensagem_object
mensagem_object
....
It's not getting anything back because you are creating and using your ArrayList and MensagemAdapter outside onDataChange() method which means that by the time at their creation you did not finish getting the data from the database. onDataChange() method has an asynchronous behaviour which means that is called even before your are trying to add those object of Mensagem class to the mensagens list. A quick solution would be to declare both, the ArrayList and MensagemAdapter inside onDataChange() method. Also you need to set the adapter inside that method. If you want to use that list outside, you need to create your own callback and for that I recommend you see the last part of my answer from this post.

Listview not updating after arraylist is updated?

I've seen many other posts in this context, but none helped. Problem is when i click on the addField button, the listview inside dialog adds new view just once. But at other clicks it doesn't get updated though The adapter works correctly (I mean the getView is called and also the arrayList in the adapter is changed in size).
I've used notifyDataSetChanged() in the adapter class. No result! I used an instance of adpater class in activity and called myAdapter.notifyDataSetChanged(). No result!
here is my code:
public class MainActivity extends Activity {
ListView lvfid;
FieldAdapter fAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//some code
showFid();
}
private void showFiD(){
final ArrayList <HashMap<String,String>> al = new ArrayList<HashMap<String,String>>();
final Dialog dialog = new Dialog(MainActivity.this , R.style.DialogTheme);
dialog.setContentView(R.layout.field_dialog);
dialog.setCancelable(true);
dialog.show();
Button addField = (Button) dialog.findViewById(R.id.btnfidField);
lvfid = (ListView) dialog.findViewById(R.id.lvfid);
//Another plan i have tested, but no result:
//fAdapter = new FieldAdapter(dialog.getContext(),al);
//lvfid.setAdapter(fAdapter);
addField.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
HashMap<String,String> h = new HashMap<String,String>();
h.put("name", "");
h.put("value", "");
al.add(h);
lvfid.setAdapter(new FieldAdapter(dialog.getContext(), al));
//fAdapter.notifyDataSetChanged();
}
});
}
public class FieldAdapter extends BaseAdapter{
private ArrayList <HashMap <String,String>> arrayList;
private LayoutInflater inflater;
public FieldAdapter(Context context, ArrayList<HashMap <String,String>> arrayList) {
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.arrayList = arrayList;
}
#Override
public int getCount() {
return arrayList.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup arg2) {
View view = null;
if (convertView == null)
view = inflater.inflate(R.layout.field_inflater, null);
else
view = convertView;
Holder holder = new Holder();
holder.edName = (EditText) view.findViewById(R.id.edfidName);
holder.edValue = (EditText) view.findViewById(R.id.edfidValue);
//holder.edName.setText(arrayList.get(position).get("name"));
//holder.edValue.setText(arrayList.get(position).get("value"));
return view;
}
private class Holder {
private EditText edName;
private EditText edValue;
}
}
}
UPDATE:
I'm sorry i took everybody's time. The stupid problem was that my listview was inside a scrollview where it must not be! I hope this helps others who have the same issue!
Use the notifyDataSetChanged() every time the list is updated.
I had the same problem. I was facing with this problem when I wanted to update the listView after onDateChanged(). I resolved it with an extra ArrayList variable and an extra custom adapter in your case FieldAdapter variable.
Update your listView with a refresh adapter and array list variables after any operations. For example after button clicks.
1. Define a counter.
2. Check when the button is clicked, increase counter by one
3. Every time check the counter, if counter is greater than 1 it means the button is clicked more than once so update the list view with new variables (arrayList, FeildAdapter)
I recommend you to define the variables as a private class fields and name them such as refreshedArrayList and refreshedAdapter
Option
Try to use the ArrayAdapter. And don't create a new adapter every
time you click on the button.
only call the add(T o) function from the ArrayAdapter.
Other Option:
add a add function to your FieldAdapter in the add field adapter add the object to your arraylist and call notifiyDataSetChanged(the adapter has aslo one and the adapter notifies all his observers)
also don't create a new adapter every time you click the button.
public class MainActivity extends Activity {
ListView lvfid;
FieldAdapter fAdapter;
ArrayList <HashMap<String,String>> al ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//some code
al = new ArrayList<HashMap<String,String>>();
lvfid.setAdapter(new FieldAdapter(MainActivity.this , al));
showFid();
}
private void showFiD(){
final Dialog dialog = new Dialog(MainActivity.this , R.style.DialogTheme);
dialog.setContentView(R.layout.field_dialog);
dialog.setCancelable(true);
dialog.show();
Button addField = (Button) dialog.findViewById(R.id.btnfidField);
lvfid = (ListView) dialog.findViewById(R.id.lvfid);
//Another plan i have tested, but no result:
//fAdapter = new FieldAdapter(dialog.getContext(),al);
//lvfid.setAdapter(fAdapter);
addField.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
HashMap<String,String> h = new HashMap<String,String>();
h.put("name", "");
h.put("value", "");
al.add(h);
fAdapter.notifyDataSetChanged();
}
});
}
I'm sorry i took everybody's time! The stupid problem was just my listview was inside a scrollview where it must not be! after getting the listview out of scrollview the problem got solved.

calling remove from custom adapter always removes last item

I have implemented a custom adapter and listItemView. The adapter sets an onlclick listener to a button that is on the listItemView. The onclick listener simply calls a private method I have in the adapter and passes it the position of the item to be removed. I know the position is correct because the database removes the proper item. I have found similar questions but have not been able to adapt the answers to work for me. Ideas and thoughts are greatly appreciated. Thanks.
Here is the full adapter class
public class FoodListAdapter extends ArrayAdapter<FoodListItem> {
//private
private int type;
public FoodListAdapter(Context context, ArrayList<FoodListItem> _objects) {
super(context, 0, _objects);
type = 0;
}
public FoodListAdapter(Context context, ArrayList<FoodListItem> _objects, int _type) {
super(context, 0, _objects);
type = _type;
}
#Override
public View getView(int position, View reusableView, ViewGroup parent)
{
//Cast the reusable view to a listAdpaterItemView
FoodListItemView listItemView = (FoodListItemView) reusableView;
//Check if the listAdapterItem is null
if(listItemView == null)
{
//If it is null, then create a view.
listItemView = FoodListItemView.inflate(parent, this, type);
}
if (type == 2)
{
Button deleteButton = (Button) listItemView.findViewById(R.id.listItemViewDeleteBTN);
deleteButton.setTag(new Integer(position));
}
//Now we need to set the view to display the data.
listItemView.setData(getItem(position));
return listItemView;
}
}
Here is a portion of my code used in fragment. Note that I have a private variable decalred in the class for listAdapter, though I don't think I need that.
private void displayListForDate(Calendar _date)
{
//get the list view
ListView listView = (ListView) getView().findViewById(1);
//Clear the listview by removing the listadapter and setting it to null.
//listView.setAdapter(null);
//First we must get the items.
Global global = (Global) getActivity().getApplicationContext();
DietSQLiteHelper database = global.getDatabase();
//Create a list to hold the items we ate. This list will then be added to the listView.
final ArrayList<FoodListItem> consumedList;
//Add the items to the array.
consumedList = database.getConsumed(_date.getTimeInMillis());
//Create an adapter to be used by the listView
listAdapter = new FoodListAdapter(getActivity().getBaseContext(), consumedList, 2);
//Add the adapter to the listView.
listView.setAdapter(listAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
consumedList.remove(position);
listAdapter.notifyDataSetChanged();
}
});
}
If you didn't implement "equals" method of FoodListItem, try to implements it.
I would suggest,
that you just update the underlying data, in your case its ArrayList<FoodItems>.
In your Adapter make this simple method and change :
private List<FoodListItem> myList = new ArrayList<FoodListItem>();
public FoodListAdapter(Context context, List<FoodListItem> myList) {
super(context, 0, myList);
type = 0;
this.myList = myList;
}
public FoodListAdapter(Context context, List<FoodListItem> myList, int _type) {
super(context, 0, myList);
type = _type;
this.myList = myList;
}
// Also update your getView() method to use myList!
#Override
public View getView(int position, View reusableView, ViewGroup parent)
{
...
listItemView.setData(myList.get(position));
public void removeItem(int positio){
if(myList != null){
myList.remove(position);
}
}
And then in class, you are creating the adapter (Activity/Fragment), just call the method.
// Update the underlying ArrayAdapter
adapter.removeItem(position);
// Notify the adapter, the data has changed
adapter.notifyDataSetChanged();
Also, you shouldnt open connection to your SQLiteDatabase on UI thread, because you are blocking it. You never know, how fast is the reading from disk going to be. If it takes too long, user can think, that your application froze and therefore, he leaves, which you dont want. I would suggest to use AsyncTask, you will find a lot of examples.
I went through and cleaned up my code and it now works, here is the working code. I really don't know exactly the difference other than I updated the IDs that I was using to assign and get views. If anyone can explain the cause for the issue I was having I would appreciate it.
Here is the snippet from my fragment where I create the list view and assign an adapter.
private void displayListForDate(Calendar _date)
{
//get the list view
ListView listView = (ListView) getView().findViewById(R.id.listView);
//Clear the listview by removing the listadapter and setting it to null.
//listView.setAdapter(null);
//First we must get the items.
Global global = (Global) getActivity().getApplicationContext();
DietSQLiteHelper database = global.getDatabase();
//Create a list to hold the items we ate. This list will then be added to the listView.
ArrayList<FoodListItem> consumedList;
//Add the items to the array.
consumedList = database.getConsumed(_date.getTimeInMillis());
//Create an adapter to be used by the listView
listAdapter = new FoodListAdapter(getActivity().getBaseContext(), consumedList, 2);
//Add the adapter to the listView.
listView.setAdapter(listAdapter);
}
and here is my adapter class.
public class FoodListAdapter extends ArrayAdapter<FoodListItem>
{
//private
private int type;
public FoodListAdapter(Context context, ArrayList<FoodListItem> _objects) {
super(context, 0, _objects);
type = 0;
}
public FoodListAdapter(Context context, ArrayList<FoodListItem> _objects, int _type) {
super(context, 0, _objects);
type = _type;
}
#Override
public View getView(int position, View reusableView, ViewGroup parent)
{
//Cast the reusable view to a listAdpaterItemView
FoodListItemView listItemView = (FoodListItemView) reusableView;
//Check if the listAdapterItem is null
if(listItemView == null)
{
//If it is null, then create a view.
listItemView = FoodListItemView.inflate(parent, type);
}
if (type == 2)
{
Button deleteButton = (Button) listItemView.findViewById(R.id.listItemViewDeleteBTN);
deleteButton.setTag(new Integer(position));
deleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Integer tag = (Integer) view.getTag();
deleteItem(tag.intValue());
}
});
}
//Now we need to set the view to display the data.
listItemView.setData(getItem(position));
return listItemView;
}
private void deleteItem(int position)
{
FoodListItem item = getItem(position);
Global global = (Global) getContext().getApplicationContext();
DietSQLiteHelper database = global.getDatabase();
database.removeConsumed(item.getID());
remove(getItem(position));
}
}

Android notifyDatasetChange with SQLite cursor how to?

So I have 2 activities.
The first (ActivityOne) displays a listview with data from SQLite cursor, and a button.
On click of that button, I want to add an item to the listview, so I display the second activity (ActivityTwo), that contains a number of editTexts and a save Button, that does the saving in the Database.
But what I want is:
after saving the new item to the DB, the ActivityTwo should close and the ActivityOne should be displayed with the refreshed content from the DB
.
This seems a reasonable workflow. How do I achieve it?
Code for ActivityOne:
public class ActivityOne extends Activity {
private ArrayList<String> idclient = new ArrayList<String>();
private ArrayList<String> numeclient = new ArrayList<String>();
private ArrayList<String> tipclient = new ArrayList<String>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ListView mylist = (ListView) findViewById(R.id.lv_clienti);
LoadList();
Button btnex = (Button) findViewById(R.id.btnNewCli);
btnex.setOnClickListener(
new View.OnClickListener()
{
public void onClick(View aView)
{
Toast.makeText(getApplicationContext(), "Add new client... " , Toast.LENGTH_SHORT).show();
Intent toAnotherActivity = new Intent(aView.getContext(), NewClientActivity.class);
startActivity(toAnotherActivity);
}
}
);
}
public void LoadList(){
SQLiteDatabase db = new myDbHelper(getApplicationContext()).getWritableDatabase();
Cursor mCursor = db.rawQuery("select idclient,nameclient,typeclient from clienti order by numeclient" , null);
idclient.clear();
numeclient.clear();
tipclient.clear();
if (mCursor.moveToFirst()) {
do {
idclient.add(Integer.toString(mCursor.getInt(0)));
nameclient.add(mCursor.getString(1));
typeclient.add(mCursor.getString(2));
} while (mCursor.moveToNext());
}
DisplayClientiAdapter disadpt = new DisplayClientiAdapter(ClientiActivity.this,idclient,nameclient, typeclient);
ListView lv = (ListView) findViewById(R.id.lv_clienti);
lv.setAdapter(disadpt);
mCursor.close();
db.close();
}
}
And in the ActivityTwo, I have in a button click:
db.execSQL("insert into clients (idclient, nameclient,typeclient,...");
DisplayClientiAdapter da = new DisplayClientiAdapter(getApplicationContext());
da.notifyDataSetChanged();
finish();
Also the displayAdapter is something like:
public class DisplayClientiAdapter extends BaseAdapter {
private Context mContext;
private ArrayList<String> idclient;
private ArrayList<String> numeclient;
private ArrayList<String> tipclient;
public DisplayClientiAdapter(Context c){
this.mContext = c;
}
public DisplayClientiAdapter(Context c, ArrayList<String> idclient, ArrayList<String> numeclient, ArrayList<String> tipclient) {
this.mContext = c;
this.idclient = idclient;
this.numeclient = numeclient;
this.tipclient = tipclient;
}
public int getCount() {
return idclient.size();
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
public View getView(int pos, View child, ViewGroup parent) {
Holder mHolder;
LayoutInflater layoutInflater;
if (child == null) {
layoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
child = layoutInflater.inflate(R.layout.clienti_item, null);
mHolder = new Holder();
mHolder.txt_idclient = (TextView) child.findViewById(R.id.tv_cl_id);
mHolder.txt_numeclient = (TextView) child.findViewById(R.id.tv_cl_nume);
mHolder.txt_tipclient = (TextView) child.findViewById(R.id.tv_cl_tip);
child.setTag(mHolder);
} else {
mHolder = (Holder) child.getTag();
}
mHolder.txt_idclient.setText(idclient.get(pos));
mHolder.txt_numeclient.setText(numeclient.get(pos));
mHolder.txt_tipclient.setText(tipclient.get(pos));
return child;
}
public class Holder {
TextView txt_idclient;
TextView txt_numeclient;
TextView txt_tipclient;
}
Of course it does not work like this. The list is not refreshed... I assume it has to do with the displayAdapter !?!?!
I cannot call the LoadList method since it is static or something like that...
Please help.
Thank you
Its not a problem with your adapter. You have to call Loadlist() in onresume method instead of oncreate method in ActivityOne. It will work then.
First of all, have a look at this two articles:
http://www.doubleencore.com/2013/05/layout-inflation-as-intended/
http://www.doubleencore.com/2013/06/context/
You shouldn't inflate your views with null in your inflate method if you have parent view available.
Also, using application context for inflating may cause strange behaviour, as it may not use correct theme you may've set in app manifest for your Activity.
On the other hand - why don't you use CursorAdapter instead of BaseAdapter?
The problem with your adapter is, that you don't set the data in it! :)
///EDIT:
I checked the wrong activity - why do you create second adapter in there?
The easiest solution would be to move the LoadList() to onStart.
If you want to do it right, you should use ContentObserver and (probably) CursorAdapter.

notifyDataSetChange not working from custom adapter

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<>();
}

Categories

Resources