Android ListView not updating with changes to adapter - android

I am having trouble with an update to the data in an ArrayAdapter in a ListView and even on listAdapter.notifyDataSetChanged() the changes are not being reflected in the ListView.
Whats interesting is that the initial load is fine, i get the full list of data rendered in the ListView. It is when i load the activity for the second time, where the cached ArrayList gets passed to the setDataList() method doesn't get rendered. The resulting ListView only contains the single default entry setup in the onCreate() method.
I have debugged the code and stepped through the runnable and it appears to run as i would have expected, just without the end result.
If anyone could help with this i would really appreciate it, i have googled it to death!
My code snippets:
public class CriteriaOriginIncludeActivity extends Activity {
private CriteriaOriginIncludeController m_controller;
private CriteriaOriginIncludesAdapter m_listAdapter;
private ArrayList<OriginRowData> m_listData;
private ListView m_originList;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.criteria_origin_includes);
ArrayList<OriginRowData> list = new ArrayList<OriginRowData>();
list.add(new OriginRowData(new Origin(0,""), false));
m_listAdapter = new CriteriaOriginIncludesAdapter(this,
R.layout.origin_include_list_row,
R.id.lst_origin_include,
list);
m_originList = (ListView) this.findViewById(R.id.lst_origin_include);
m_originList.setAdapter(m_listAdapter);
m_controller = new CriteriaOriginIncludeController(this);
}
public void setOriginList(ArrayList<OriginRowData> list) {
if (list != null && list.size() > 0) {
m_listData = list;
} else {
m_listData = new ArrayList<OriginRowData>();
}
runOnUiThread(returnRes);
}
private Runnable returnRes = new Runnable() {
public void run() {
m_listAdapter.clear();
if(m_listData != null && m_listData.size() > 0){
m_listAdapter.notifyDataSetChanged();
for(int i=0;i<m_listData.size();i++)
m_listAdapter.add(m_listData.get(i));
}
m_listAdapter.notifyDataSetChanged();
}
};
}
And the adapter:
public class CriteriaOriginIncludesAdapter extends ArrayAdapter<OriginRowData> {
private ArrayList<OriginRowData> m_items;
private Context m_context;
public CriteriaOriginIncludesAdapter(Context context, int resourceId, int textViewResourceId, ArrayList<OriginRowData> list) {
super(context, resourceId, textViewResourceId, list);
this.m_context = context;
m_items = list;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)m_context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.origin_include_list_row, null);
}
OriginRowData o = m_items.get(position);
if (o != null) {
TextView txtName = (TextView) v.findViewById(R.id.txt_origin_include_name);
TextView txtId = (TextView) v.findViewById(R.id.txt_origin_include_id);
CheckBox chkOrigin = (CheckBox) v.findViewById(R.id.chk_origin);
if (txtName != null) {
txtName.setText(o.getOrigin().getOrigin());
}
if (txtId != null) {
txtId.setText(Integer.toString(o.getOrigin().getId()));
}
if (chkOrigin != null) {
chkOrigin.setChecked(o.getInclude());
chkOrigin.setOnClickListener(new OriginIncludeOnClickListener(position));
}
}
return v;
}
}

You need to override ArrayAdapter's Add() method.
Since you are using your own private private ArrayList<OriginRowData> m_items;, default Add() method does not know that it has to add the data into this array list.
And in your getView you are using m_items array, So this needs to be updated. The default Add() method will add the items to the ArrayAdapter's inbuilt

Related

How to add multiple items in Listview Android

I'm working on an Android application of booking medicine offline. I have used ListView for Cart, but whenever I add a new item in cart, my previous item get replaced.
L1 = imageacidity
L2 = imagecough
if(msg.toString().equals("L1")) {
adapter = new ContactImageAdapter(this, R.layout.list, imageacidity);
ListView dataList = (ListView) findViewById(R.id.list);
dataList.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
if(msg.toString().equals("L2"))
{
adapter = new ContactImageAdapter(this, R.layout.list, imagecough);
ListView dataList = (ListView) findViewById(R.id.list);
dataList.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
Here I have 5 elements in imageacidity and Imagecough Array. Whenever I select 1 item, it gets added in cart, but when I try to select another item it get replaced with new one.
You have to Add the element inside your adapter.
I will post a custom Adapter and show you how to add elements properly.
Adapter:
public class YourAdapter extends BaseAdapter {
List<String> itens;
private Context mContext;
private static LayoutInflater inflater = null;
public YourAdapter(Context context, List<String> itens){
this.itens = itens;
mContext = context;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public int getCount() {
return itens.size();
}
public String getItem(int position) {
return itens.get(position);
}
public long getItemId(int position) {
return 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
if (convertView == null)
vi = inflater.inflate(R.layout.list_row, parent, false);
String msg = itens.get(position);
TextView tx = vi.findViewById(R.id.your_id);
tx.setText(msg);
return vi;
}
public void addItem(String item){
itens.add(item);
}
public void addItens(List<String> itens){
this.itens.addAll(itens);
}
}
ListView:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
adapter = new CustomAdapter(this,yourListOfItens);
listView = (ListView) findViewById(R.id.list_view);
listView.setAdapter(adapter);
}
You can set initial data on constructor of adapter, or use methods addItem and addAll on a click button for example.
The problem you are describing of the data being removed is happening because making a new ContactImageAdapter and calling setAdapter, which will completely remove the data that was already in the ListView.
If you want to properly implement the code in the question, you need something like this.
String msg = ""; // TODO: get this String value
ListView dataList = (ListView) findViewById(R.id.list);
// TODO: Define a single List to store the data and use that in *one* adapter
List<Contact> contacts = new ArrayList<Contact>();
adapter = new ContactImageAdapter(this, R.layout.list, contacts);
dataList.setAdapter(adapter);
// TODO: Replace this with the object to add to the adapter
Contact contact = null;
if(msg.equals("L1")) {
// TODO: Use whatever values you want for "L1"
int img = R.drawable.bati_acidity_1;
String name = "Amlapitta";
String price = "price 170";
contact = new Contact(img, name, price);
}
else if(msg.equals("L2")) {
// TODO: Use whatever values you want for "L2"
int img = R.drawable.bati_acidity_2;
String name = "Amlapitta2";
String price = "price 270";
contact = new Contact(img, name, price);
}
if (contact != null) {
contacts.add(contact);
adapter.notifyDataSetChanged();
}
Another problem is that you are calling notifyDataSetChanged without actually changing the datasets of imageacidity or imagecough.
You can use an algorithm (logic) on the InputListAdapter checking and verifying if there is a MedicineVO (Value Object Pattern) item on old list before the calling notyChange(..) method. In addition, you can wrapping the logic in other class such as MedicineLogic to improve the adapter readability.
See the sample code below:
public class MedicineInputListAdapter extends ArrayAdapter<MedicineVo> {
public static final int[] COLORS = new int[] { Color.WHITE, Color.BLUE };
private Context mContext;
private List<MedicineVo> medicineVos;
private MedicineVo medicineVoActual;
public BasePreOSPreventivaCorretivaInputListAdapter(Context context, int resource, List<MedicineVo> medicineVos) {
super(context, resource, medicineVos);
this.medicineVoActual = new MedicineVo();
this.medicineVos = new ArrayList<MedicineVo>();
this.medicineVos.addAll(medicineVos);
this.mContext = context;
}
private static class ViewHolder {
TextView mMedicineTextView;
//------------------------------------------------------
// others Android view components
//------------------------------------------------------
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if (convertView == null) {
//------------------------------------------------------
// mapper from xml to view and add itens to holder
//------------------------------------------------------
//------------------------------------------------------
// add event action to the mMedicineTextView
//------------------------------------------------------
viewHolder.mMedicineTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
TextView textView = (TextView) view;
MedicineVo medicineVo = (MedicineVo) textView.getTag();
boolean selected = medicineVo.getSelected();
if (selected) {
/*do it*/
}
refreshPreOSMaterialWhenUpdate(preOSMaterialVo);
}
});
convertView.setTag(viewHolder);
}
else {
viewHolder = (ViewHolder) convertView.getTag();
}
//------------------------------------------------------
// get item and adjust color
//------------------------------------------------------
MedicineVo item = getItem(position);
/*do it*/
return convertView;
}
public void refreshMedicineListWhenUpdate(MedicineVo medicineVo){
List<MedicineVo> newMedicineVos = new ArrayList<MedicineVo>();
for (MedicineVo medicineVoOnList : medicineVos) {
if( StringUtils.isNull(medicineVoOnList.getId()) )
continue;
if( MedicineLogic.existsOnList(medicineVos, medicineVoOnList) )
continue;
/* others checks if necessary */
newMedicineVos.add(medicineVoOnList);
}
medicineVos.addAll(newMedicineVos);
}
}
If you can't select more but only one item of your ListView, this might help.As others have commented on the question, changing the adapter of a ListView can clear the selection too, but as I supposed the code you've posted is inside onCreate (or other kind of initialization) so setting the adapter there won't affect the selection (since there can't be selection without items... :) )

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.

ListView not refreshed until user interaction

I have a ListView and a custom adapter. When the user changes the sort type from a spinner, I want to redraw the list with the new items. The problem is that the ListView is re-drawn only after I interact with it on the device (start scrolling for example).
if (update) {
mOfferList = (ArrayList<PositionSearchItem>) psr
.getPositionSearchItem();
mAdapter.clear();
mAdapter.addAll(mOfferList);
mAdapter.notifydataSetChanged()
mList.invalidate();
mList.invalidateViews();
}
I have also tried to fully reset a new instance of my adapter to the list, it is giving the same result except that the list becomes blank at first and appears on user interaction.
I'm using HoloEveryWhere maybe this is an important info.
EDIT : Here is some more code
#EFragment(R.layout.list_fragment_results)
public class ResultsListFragment extends Fragment {
#ViewById(R.id.search_results_list)
ListView mList;
#ViewById(R.id.search_result_list_spinner)
Spinner mSpinner;
MainActivity mActivity;
private String mTypedText;
private List<String> mSortType;
private ResultsListFragment mFrag;
private Bundle mOffersPageBundle;
private SearchResultsListAdapter mAdapter;
private ArrayList<PositionSearchItem> mOfferList;
#AfterViews
public void afterViews() {
mFrag = this;
mActivity = (MainActivity) getActivity();
mSortType = new ArrayList<String>();
mSortType.add(SearchResultSortType.SCORE_DESCENDING);
mOfferList = new ArrayList<PositionSearchItem>();
mOffersPageBundle = getArguments();
PositionSearchResponse psr = mOffersPageBundle.getParcelable("offers");
mTypedText = mOffersPageBundle.getString("typedText");
mOfferList = (ArrayList<PositionSearchItem>) psr.getPositionSearchItem();
mAdapter = new SearchResultsListAdapter(this,
android.R.layout.simple_list_item_1, mOfferList, mTypedText,
mSortType, mActivity.getLat(), mActivity.getLon());
mList.setAdapter(mAdapter);
this.setListeners();
}
private void setListeners() {
mSpinner.setOnItemSelectedListener(new org.holoeverywhere.widget.AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(
org.holoeverywhere.widget.AdapterView<?> parent, View view,
int pos, long id) {
Boolean update = false;
PositionSearchResponse psr = null;
switch (pos) {
case 0:
if (mSortType.get(0) != SearchResultSortType.SCORE_DESCENDING) {
mSortType.clear();
mSortType.add(SearchResultSortType.SCORE_DESCENDING);
psr = processSearch(mTypedText, mSortType, 0, mActivity);
update = true;
}
break;
case 1:
if (mSortType.get(0) != SearchResultSortType.DATE) {
mSortType.clear();
mSortType.add(SearchResultSortType.DATE);
psr = processSearch(mTypedText, mSortType, 0, mActivity);
update = true;
}
break;
default:
break;
}
if (update) {
mOffersPageBundle.putParcelable("offers", psr);
mOfferList = (ArrayList<PositionSearchItem>) psr
.getPositionSearchItem();
mAdapter.mIdMap.clear();
for (int i = 0; i < mOfferList.size(); ++i) {
mAdapter.mIdMap.put(mOfferList.get(i), i);
}
mOfferList = (ArrayList<PositionSearchItem>) psr
.getPositionSearchItem();
mAdapter.clear();
mAdapter.addAll(mOfferList);
mAdapter.notifydataSetChanged()
mList.invalidate();
mList.invalidateViews();
}
}
#Override
public void onNothingSelected(
org.holoeverywhere.widget.AdapterView<?> parent) {
// TODO Auto-generated method stub
}
});
}
}
EDIT : the getView method from custom adapter
#Override
public View getView(int pos, View convertView, ViewGroup parent) {
this.v = convertView;
LayoutInflater vi = (LayoutInflater) getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
PositionSearchItem psr = getItem(pos);
v = vi.inflate(R.layout.result_list_item, parent, false);
v.setTag(pos);
// Inject text into view
((TextView) v.findViewById(R.id.result_title_textview))
.setText(getItem(pos).getTitle());
// Disable hardware acceleration for the view (it brakes dotted lines on
// some devices)
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
v.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
// reload list if scrolled to bottom
int page = 0;
if (pos > mLastViewed && pos == getCount() - 1) {
mLastViewed = pos;
ResultsListFragment frag = new ResultsListFragment_();
PositionSearchResponse newSearch = frag.processSearch(mTypedText, mSortType, mPage,
mActivity);
mPage = mPage + 12;
if(newSearch != null && newSearch.getPositionSearchItem() != null && newSearch.getPositionSearchItem().size() > 0){
for (int i = 0; i < newSearch.getPositionSearchItem().size(); ++i) {
mIdMap.put(newSearch.getPositionSearchItem().get(i), i);
}
this.addAll(newSearch.getPositionSearchItem());
}
}
return v;
}
Use
if (update) {
mAdapter.NotifyDataSetChanged();
}
this may solve your problem.
Try to set the adatpter again.Place the below code in all the places you wrote the code to update listview
mAdapter = new YourAdapter();
mList.setAdapet(mAdapter)
I hope you have created custom list view using adapter and model.
Now each time when you need to update your list view dynamically then you need to clear your previously created list view. Then after you need to fetch all new values and then update same over custom list view.
Hope it helps!

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

arrayadapter error when created outside onCreate

I have an ArrayAdapter that I use to fill a listview, but I'm unable to create it outside the oncreate event, but at that time I don't have the data.
public class CusPickup extends Activity {
private OrdersReady orderready_data[];
private ListView lView;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.orders);
Here I will get a null point exception.
OrderReadyAdapter adapter = new OrderReadyAdapter(this,R.layout.listview_item_row, orderready_data);
lView = (ListView)findViewById(R.id.listView1);
View header = (View)getLayoutInflater().inflate(R.layout.listview_header_row, null);
lView.addHeaderView(header);
lView.setAdapter(adapter);
getData();
}
}
Here I get the data from HTTP get.
private final Handler handler = new Handler() {
#Override
public void handleMessage(final Message msg) {
progressDialog.dismiss();
String bundleResult = msg.getData().getString("RESPONSE");
int TotalRecords = myResult.d.results.size();
for (int i = x; i < TotalRecords; i++ ) {
orderready_data[i] = new OrdersReady(myResult.d.results.get(i).myStr, myDate ,invResult.d.results.get(i).numberStr, invResult.d.results.get(i).qtyInt, myAmount)
}
}
}
If I place the OrderReadyAdapter her I get a code error with a fix "change OrderReadyAdapter(Context, Int, OrdersReady[]) to OrderReadyAdapter(Handle, Int, OrdersReady[]) if I change it I will get more errors.
Also I'm not sure if my declaration of the private OrdersReady orderready_data[] is correct, because if I declare it in code I would declare it like this: OrdersReady orderready_data[] = new OrdersReady[TotalRecords];
Thanks for any help.
New Adapter
public class OrderReadyAdapter extends ArrayAdapter<OrdersReady>{
Context context;
int layoutResourceId;
ArrayList<OrdersReady> data = null;
public OrderReadyAdapter(Context context, int layoutResourceId, ArrayList<OrdersReady> orderReadyArray) {
super(context, layoutResourceId, orderReadyArray);
this.layoutResourceId = layoutResourceId;
this.context = context;
this.data = orderReadyArray;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
OrderHolder holder = null;
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new OrderHolder();
holder.mytxt1 = (TextView)row.findViewById(R.id.mytxt1);
holder.mytxt2 = (TextView)row.findViewById(R.id.mytxt2);
holder.mytxt3 = (TextView)row.findViewById(R.id.mytxt3);
holder.mytxt4 = (TextView)row.findViewById(R.id.mytxt4);
holder.mytxt5 = (TextView)row.findViewById(R.id.mytxt5);
row.setTag(holder);
}
else
{
holder = (OrderHolder)row.getTag();
}
OrdersReady orderready = data.get(position);
holder.mytxt1.setText(orderready.place);
holder.mytxt2.setText(orderready.Date);
holder.mytxt3.setText(orderready.invoice);
holder.mytxt4.setText(String.valueOf(orderready.Qty));
holder.mytxt5.setText(String.valueOf(orderready.Amount));
return row;
}
static class OrderHolder
{
TextView mytxt1;
TextView mytxt2;
TextView mytxt3;
TextView mytxt4;
TextView mytxt5;
}
}
I suggest you change the OrdersReady[] into ArrayList. Initialize it in your onCreate method. Also make the orderReady adapter into a class field.
orderReadyArray = new ArrayList<OrderReady>();
ordersReadyAdapter = new OrderReadyAdapter(this,R.layout.listview_item_row, orderReadyArray);
lView = (ListView)findViewById(R.id.listView1);
View header = (View)getLayoutInflater().inflate(R.layout.listview_header_row, null);
lView.addHeaderView(header);
lView.setAdapter(ordersReadyAdapter);
This should initialize an empty listview as you don't have the data yet.
When you receive OrdersReady data from the server, update orderReadyArray as such:
orderReadyArray.clear(); // remove old data
for (int i = x; i < TotalRecords; i++ ) {
orderReadyArray.add(data); // add new data one by one
}
ordersReadyAdapter.notifyDataSetChanged(); // this forces the listview to repaint
Alternatively:
You can create a new adapter and assign it to the listview once you receive the data:
List<OrderReady> orderReadyArray = new ArrayList<OrderReady>(); // create a new array to hold data
for (int i = x; i < TotalRecords; i++ ) {
orderReadyArray.add(data); // add new data one by one
}
OrderReadyAdapter ordersReadyAdapter = new OrderReadyAdapter(this,R.layout.listview_item_row, orderReadyArray);
lView.setAdapter(ordersReadyAdapter);
This should update your list. If you still do not see the items, the problem is in the adapter, perhaps you are inflating the row incorrectly in getView() method.

Categories

Resources