Refresh Current Fragment (ListView Data) remaining in the same activity
android, android-fragments, android-listview, listview
Solution
You have multiple options to solve this depending on how exactly you implemented your `ListView` and `Adapter`.
- By calling `notifyDataSetChanged()`
- By resetting the `Adapter`
Updating with notifyDataSetChanged()
This is the best solution there is, but you need to modify the `List` the `Adapter` is using for this to work. For example if you use an `ArrayAdapter` like this:
String[] dataSource = new String[] {
"A", "B", "C", ...
};
ArrayAdapter<String> adapter = new ArrayAdapter<String>(context, R.layout.example, dataSource);
As you can see the `String[]` is the dataSource for our `Adapter`. We can modify the array like this, but those changes will not immediately be reflected in the `ListView`:
dataSource[0] = "some new String value";
Only once we call `notifyDataSetChanged()` will the `ListView` be updated:
adapter.notifyDataSetChanged();
From the documentation:
public void notifyDataSetChanged ()
Notifies the attached observers that the underlying data has been changed and any View reflecting the data set should refresh itself.
But DO NOT confuse `notifyDataSetChanged()` with `notifyDataSetInvalidated()`, because `notifyDataSetInvalidated()` does something completely different and would just mess up your `ListView`.
From the documentation:
public void notifyDataSetInvalidated ()
Notifies the attached observers that the underlying data is no longer valid or available. Once invoked this adapter is no longer valid and should not report further data set changes.
Updating by resetting the `Adapter`
This is pretty straight forward. Every time you set a new `Adapter` the `ListView` will update itself. If you cannot use `notifyDataSetChanged()` for some reason then you have to do it like this. Just create a new `Adapter` every time you want to update your `ListView`:
ArrayAdapter<String> adapter = new ArrayAdapter<String>(context, R.layout.example, newData);
And use `setAdapter()` to set it to the `ListView`:
listView.setAdapter(adapter);
This will always update the `ListView` but there are a few problems with this solution. First and foremost every time you update the `ListView` this way it would scroll back to the top which can be quite annoying when there are frequent updates or when there is a lot of content in the `ListView`.
EDIT:
There are a few things in your code that are not quite optimal. First and foremost, your `Adapter` should not contain the code to download the contacts. It just doesn't belong there, the only responsibility of an `Adapter` should be that he creates `Views` from a given data source. So first you should move the `getAllContacts()` method outside of the `Adapter`. I suggest you create static helper method for this, I took the liberty of modifying your code accordingly:
public class ContactsHelper {
public static List<Contact> getAllContacts(Context context) {
List<Contact> contactList = new ArrayList<Contact>();
String URL = "content://com.example.provider.Contacts/contacts";
Uri baseUri1 = Uri.parse(URL);
String[] select = {ContactsContentProvider.PHONE_ID, ContactsContentProvider.STATUS};
String where = "((" + ContactsContentProvider.NEEO_USER + " NOTNULL) AND (" +
ContactsContentProvider.NEEO_USER + " = 1 )AND (" +
ContactsContentProvider.STATUS + " = 1 ))";
Cursor cursor = context.getContentResolver().query(baseUri1, select, where, null, "pid");
for (cursor.moveToFirst(); cursor.moveToNext(); cursor.isAfterLast()) {
Log.w("Filtered IDS", "" + cursor.getString(cursor.getColumnIndex(ContactsContentProvider.PHONE_ID)) +
"" + cursor.getString(cursor.getColumnIndex(ContactsContentProvider.STATUS)));
}
Uri baseUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
String[] projection = new String[]{
ContactsContract.CommonDataKinds.Phone._ID,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER};
String selection = "((" +
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " NOTNULL) AND (" +
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " != ' ' ))";
String[] selectionArgs = null;
String sortOrder = ContactsContract.CommonDataKinds.Phone._ID + " COLLATE LOCALIZED ASC";
Cursor mCursor = context.getContentResolver().query(baseUri, projection, selection, selectionArgs, sortOrder);
// Joinging Both Cursors
CursorJoiner joiner = new CursorJoiner(cursor, new String[]{ContactsContentProvider.PHONE_ID}, mCursor, new String[]{ContactsContract.CommonDataKinds.Phone._ID});
for (CursorJoiner.Result joinerResult : joiner) {
Contact cont = new Contact();
Log.e("Result", joinerResult.toString());
switch (joinerResult) {
case LEFT:
// handle case where a row in cursorA is unique
break;
case RIGHT:
// handle case where a row in cursorB is unique
cont.setID(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID)));
cont.setName(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)));
cont.setPhoneNumber(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
cont.setStatus("0");
contactList.add(cont);
break;
case BOTH:
// handle case where a row with the same key is in both cursors
cont.setID(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID)));
cont.setName(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)));
cont.setPhoneNumber(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
cont.setStatus(cursor.getString(cursor.getColumnIndex(ContactsContentProvider.STATUS)));
contactList.add(cont);
break;
}
}
mCursor.close();
cursor.close();
return contactList;
}
}
With this code you can get all contacts like this:
List<Contact> contacts = ContactsHelper.getAllContacts(getActivity());
After this we need to modify your `Adapter` so that `notifyDateSetChanged()` will work:
private class CustomAdapterForAllContacts extends BaseAdapter {
private final List<Contact> contactsList;
private final LayoutInflater inflater;
public CustomAdapterForAllContacts(Context context, List<Contact> contacts) {
this.inflater = LayoutInflater.from(context);
this.contactsList = contacts;
}
@Override
public int getCount() {
return contactsList.size();
}
@Override
public Contact getItem(int position) {
return contactsList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
// We expose the List so we can modify it from outside
public List<Contact> contacts() {
return this.contactsList;
}
private class SimpleViewHolder {
private final SparseArray<View> viewArray = new SparseArray<View>();
private final View convertView;
public SimpleViewHolder(View convertView) {
this.convertView = convertView;
}
public View get(int id) {
View view = this.viewArray.get(id, null);
if(view == null) {
view = this.convertView.findViewById(id);
this.viewArray.put(id, view);
}
return view;
}
}
@Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
// By implementing the view holder pattern you only need to perform
// findViewById() once. This will improve the performance of `ListView`
// and reduce lag.
SimpleViewHolder viewHolder;
if (convertView == null) {
convertView = this.inflater.inflate(R.layout.list_item, viewGroup, false);
viewHolder = new SimpleViewHolder(convertView);
convertView.setTag(viewHolder);
}
viewHolder = (SimpleViewHolder) convertView.getTag();
TextView contName = (TextView) viewHolder.get(R.id.nameText);
TextView contNumber = (TextView) viewHolder.get(R.id.numberText);
ImageView image = (ImageView) viewHolder.get(R.id.contact_image);
Contact contact = getItem(position);
String status = contact.getStatus();
if (contact.getStatus().equals("1")) {
image.setBackgroundResource(com.example.mycontentprovider.R.drawable.person_empty_online);
} else {
image.setBackgroundResource(com.example.mycontentprovider.R.drawable.person_empty_offline);
}
contName.setText(contact.getName());
contNumber.setText(contact.getPhoneNumber());
return view;
}
}
I have changed multiple things in this `Adapter`. First and foremost the `List` of `Contacts` is now final and I added a method `contacts()` to expose the `List` so we can modify the data in the `Adapter` from the outside. I also implemented the view holder pattern so your `ListView` scrolls faster and smoother!
I hope I haven't forgotten anything, but this should be all the changes you need. You can use the new `Adapter` like this:
List<Contact> contacts = ContactsHelper.getAllContacts(getActivity());
CustomAdapterForAllContacts adapter = new CustomAdapterForAllContacts(getActivity(), contacts);
listView.setAdapter(adapter);
If you want to update the `ListView` later on you need to modify the `List` inside the `Adapter` like this:
List<Contact> newData = ContactsHelper.getAllContacts(getActivity());
adapter.contacts().clear();
adapter.contacts().addAll(newData);
adapter.notifyDataSetChanged();
I hope I could help you and if you have any further questions please feel free to ask!
Problem
Calling a `Fragment` from an `Activity`, I am displaying a `ListView` with two `Buttons`. When I click on a `menu_item` (i.e. Show Online), i am updating the data and so the `ListView`. Now I need to reflect the updated data. How can i refresh the `Fragment` after i click Show Online. Till now, I have used the following code: ``` Intent intent = getIntent(); Intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); finish(); startActivity(intent); ``` But this will restart the whole `Activity`. I just need to refresh the current `Fragment`. Edited : Code Added ACTIVITY CLASS ``` public class ContactListActivity extends ActionBarActivity { ListView listView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final ActionBar actionBar = getActionBar(); MenuButtonUtil.enableMenuButton(this); FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); MyContactsFragment contactListFragment = new MyContactsFragment (); fragmentTransaction.replace(android.R.id.content, contactListFragment); fragmentTransaction.commit(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.show_online) { ContentValues values = new ContentValues(); String where = "((" + ContactsContentProvider.PHONE_ID + " NOTNULL) AND ((" + ContactsContentProvider.PHONE_ID+ " = 17486 )OR (" + ContactsContentProvider.PHONE_ID+ " = 17494 )))"; values.put(ContactsContentProvider.STATUS, true); this.getContentResolver().update(ContactsContentProvider.CONTENT_URI, values, where, null); listView = (ListView) this.findViewById(android.R.id.list); ((BaseAdapter) listView.getAdapter()).notifyDataSetChanged(); return true; } return super.onOptionsItemSelected(item); } } ``` Fragment ``` public class MyContactsFragment extends ListFragment{ Button allContactsBtn; Button neeoContactsBtn; ListView listView; CustomAdapterForAllContacts adapterForAllContacts; CustomAdapterForNeeoContacts adapterForNeeoContacts; @Override public void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); final ActionBar actionBar = getActivity().getActionBar(); MenuButtonUtil.enableMenuButton(getActivity()); adapterForNeeoContacts = new CustomAdapterForNeeoContacts(); adapterForAllContacts = new CustomAdapterForAllContacts(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) { View view = inflater.inflate(R.layout.contactsfragment, container,false); allContactsBtn = (Button) view.findViewById(R.id.allContactsButton); neeoContactsBtn = (Button) view.findViewById(R.id.neeoContactsButton); listView = (ListView) view.findViewById(android.R.id.list); // ==================== Neeo Contacts ============================ neeoContactsBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { listView.setAdapter(adapterForNeeoContacts); } }); // ====================== All Contacts ============================= allContactsBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { listView.setAdapter(adapterForAllContacts); } }); return view; } ``` Adapter: ``` private class CustomAdapterForAllContacts extends BaseAdapter { public CustomAdapterForAllContacts(){ } List<Contact> contactsList = getAllContacts(); @Override public int getCount() { // TODO Auto-generated method stub return contactsList.size(); } @Override public Contact getItem(int arg0) { // TODO Auto-generated method stub return contactsList.get(arg0); } @Override public long getItemId(int arg0) { // TODO Auto-generated method stub return arg0; } @Override public View getView(int position, View view, ViewGroup viewGroup) { if(view==null) { LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater.inflate(R.layout.list_item, viewGroup,false); } TextView contName = (TextView)view.findViewById(R.id.nameText); TextView contNumber = (TextView)view.findViewById(R.id.numberText); ImageView image = (ImageView)view.findViewById(R.id.contact_image); Contact contact = contactsList.get(position); String status = contact.getStatus(); if(contact.getStatus().equals("1")){ image.setBackgroundResource(com.example.mycontentprovider.R.drawable.person_empty_online); }else{ image.setBackgroundResource(com.example.mycontentprovider.R.drawable.person_empty_offline); } contName.setText(contact.getName()); contNumber.setText(contact.getPhoneNumber()); return view; } public Contact getContactPosition(int position) { return contactsList.get(position); } public List<Contact> getAllContacts(){ List<Contact> contactList = new ArrayList<Contact>(); String URL = "content://com.example.provider.Contacts/contacts"; Uri baseUri1 = Uri.parse(URL); String[] select = {ContactsContentProvider.PHONE_ID, ContactsContentProvider.STATUS}; String where = "((" + ContactsContentProvider.NEEO_USER + " NOTNULL) AND (" + ContactsContentProvider.NEEO_USER+ " = 1 )AND (" + ContactsContentProvider.STATUS+ " = 1 ))"; Cursor cursor = getActivity().getContentResolver().query(baseUri1, select, where, null, "pid"); for(cursor.moveToFirst(); cursor.moveToNext(); cursor.isAfterLast()) { Log.w("Filtered IDS",""+ cursor.getString(cursor.getColumnIndex(ContactsContentProvider.PHONE_ID))+ ""+ cursor.getString(cursor.getColumnIndex(ContactsContentProvider.STATUS))); } Uri baseUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI; String[] projection = new String[] { ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER}; String selection = "((" + ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " NOTNULL) AND (" + ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " != ' ' ))"; String[] selectionArgs = null; String sortOrder = ContactsContract.CommonDataKinds.Phone._ID + " COLLATE LOCALIZED ASC"; Cursor mCursor= getActivity().getContentResolver().query(baseUri, projection, selection, selectionArgs, sortOrder); // Joinging Both Cursors CursorJoiner joiner = new CursorJoiner(cursor, new String[] {ContactsContentProvider.PHONE_ID} , mCursor, new String[] {ContactsContract.CommonDataKinds.Phone._ID}); for (CursorJoiner.Result joinerResult : joiner) { Contact cont = new Contact(); Log.e("Result", joinerResult.toString()); switch (joinerResult) { case LEFT: // handle case where a row in cursorA is unique break; case RIGHT: // handle case where a row in cursorB is unique cont.setID(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID))); cont.setName(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME))); cont.setPhoneNumber(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))); cont.setStatus("0"); contactList.add(cont); break; case BOTH: // handle case where a row with the same key is in both cursors cont.setID(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID))); cont.setName(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME))); cont.setPhoneNumber(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))); cont.setStatus(cursor.getString(cursor.getColumnIndex(ContactsContentProvider.STATUS))); contactList.add(cont); break; } } mCursor.close(); cursor.close(); return contactList; } } ```