Android ListView Live Updating - android

I have a ListView in a ListActivity that's bound to some data. I have a content provider that's providing the data.
The ListActivity gets the data by querying a content resolver:
Uri uri = Uri.parse("content://my.provider.DocumentProvider/mystuff");
contentCursor = this.getContentResolver().query(uri, null, null, null, null);
So now the activity has the cursor. It creates an adapter and attaches it to the list:
ListAdapter adapter = new DocumentListCursorAdapter(this, R.layout.main_row_layout, contentCursor, new String[] { "titleColumn" }, new int[] { titleColumnIndex });
setListAdapter(adapter);
This works fine; the list shows the data in the cursor.
But now the content provider has new data. I want the list to update to show the new data.
The examples I've seen involve a call to the adapter's notifyDataSetChanged, but it seems to me that this breaks the separation between the content provider and the list, which is consuming the content.
Does the content provider need to know what adapters are attached to the cursor so it can call their notifyDataSetChanged method? Or is there a better way that doesn't see these two things coupled this way.

I found the answer here:
http://mylifewithandroid.blogspot.com/2008/03/observing-content.html
In a nutshell, the provider calls notifyChange to indicate that the content at the URI has changed:
getContext().getContentResolver().notifyChange(uri, null);
And the ListActivity calls setNotificationUri on the cursor to register that it's interested in receiving notification of changes:
contentCursor.setNotificationUri(getContentResolver(), uri);
(Thanks njzk2 for pointing me in the right direction).

asuming that ContentProvider is yours you should add cursor.setNotificationUri(getContext().getContentResolver(), uri); in your query implementation of CP(before you return cursor) and getContext().getContentResolver().notifyChange(uri, null); in update, insert, delete ... SimpleCursorAdapter which is prolly base of your DocumentListCursorAdapter should take care about refreshing listview.

You mean, you want to update list as per data changed.
For that just try this :
when you get new cursor then just put this code instead set new adapter to list..
adapter.notifyDatasetChanged();
and
listview.invalidate()

Related

Android RecyclerView inside Fragment is not updating Loader content

I have Fragment and it uses RecyclerView Adapter with LoaderManager to list items. RecyclerView i use is from this address. I've implemented LoaderManager in Fragment and gave context of its Activity to RecyclerView.
When i add new item to list, it does not refresh and show new item in list. I use same Adapter and structure on another activity and it works good. But here i use RecyclerView with Loader inside Fragment and it does not refresh list when i add item, instead i have to go back(finish fragment) and enter again.
I have 2 tables like this. First I get cursor from student_course table and from that cursor i get student ids of specific class. Then using data of first cursor, i get second cursor from students table which has list of students from same class. Then i send second cursor to adapter. I do below operation on both onCreateView() and onCreateLoader:
String[] projection0 = {
DatabaseOpenHelper.COL_STUDENT_ID,
DatabaseOpenHelper.COL_COURSE_ID};
String selection0=DatabaseOpenHelper.COL_COURSE_ID + "=?";
String selectionArgs0[]={String.valueOf(courseId)};
mDataset0=getActivity().getContentResolver().query(StudentContentProvider.CONTENT_URI2, projection0,selection0,selectionArgs0,null);
if(mDataset0.getCount()!=0) {
//BATCH
List<String> selectionList = new ArrayList<String>();
mDataset0.moveToFirst();
...
String[] projection1 = {
DatabaseOpenHelper.COLUMN_ID,
DatabaseOpenHelper.COL_STUDENT_NUMBER,
DatabaseOpenHelper.COL_STUDENT_NAME,
DatabaseOpenHelper.COL_STUDENT_CARD_ID,
DatabaseOpenHelper.COL_STUDENT_COLOR};
selection1 = selection1.substring(0, selection1.length() - 2) + ")";
mDataset1 = getActivity().getContentResolver().query(StudentContentProvider.CONTENT_URI1, projection1, selection1, selectionArgs1, null);
}else{
mDataset1=null;
}
...
mAdapter = new studentListAdapter(getActivity(),mDataset1,this);
mDataset1 is students of same class.
1) What might be the problem ? 2) Is there any way to implement LoaderManager class inside
Update 1: When i change selection1 and selectionArgs1 to null, it updates list immediately after i add item. But it shows all students from every class because i didn't specify selection.
Update 2: When i check onLoadFinished() i see that new cursor, after loading new content, is still same as old.
1) I realized that cursor is not changing when new data is added, so when i add new data i call getLoaderManager().restartLoader(LOADER_ID,null,this) (by localBrodCastManager in my case) which reloads cursor (calls onCreateLoader()) and new data is shown on list. (as Suggested here). This does trick.
2) I found that the reason cursor does not change when item is added, because on onCreateLoader() i returned cursor with specific id selection of students, which means cursor will not change until there is change on that items with specific ids i have given. So, if there is new item added, my cursoris not changed, but if one of the items(which is listed) is removed or changed, then cursor is changed. Solution is here.

updating listview after inserting row via content provider

I am using custom ContentProvider to insert and query the sqlite database in android. when i query the database i am populating data over listview. but the issue is when i insert the row i want to update the listview also.
i have created custom adapter by extending CursorAdapter and listening to LoaderManager.LoaderCallbacks<Cursor> , now when when i am inserting row by context.getContentResolver().insert() function , i want to update the listview.
i have tried adapter.notifyDataSetChanged(); after inserting the row but listview is not getting updated.
the only option i saw is restartLoader() is there anyother wat to update the listview ?
this is my insert code
context.getContentResolver().insert(
ContentUris.withAppendedId(
Uri.withAppendedPath(Columns.CONTENT_URI,
Columns.INSERT_LOGS ),
Columns.LOGS),
values);
i am inserting the logs of application and showing into listview
here is the code inside content provider
if(rowId > 0 ){
Uri insertUri = ContentUris.withAppendedId(Columns.CONTENT_URI, rowId);
Log.e("inserted " , rowId+"");
getContext().getContentResolver().notifyChange(insertUri,null);
return insertUri;
}
I think, you can see how works this example, because it's also based on Loaders.
Please take a look at it too.
I had troubles like you and the problem was how I did.
It was right like this.
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
...
adapter.swap(cursor)
dataAdapter.notifyDataSetChanged();
listView.SetAdapter(dataAdapter);
...
}

Android: Spinner does not update after change of dataset

In my app the spinne shows the active items (I use Loader of support library to load them). The init of spinner works fine and it shows only the active items.
But I got the followeing problem:
When I edit the items in another activity and store them (active and deactivat some of them) an go back (Back-Button), then I see the "old" list of items in the spinner. The adapter get the new cursor with correct data, but the spinner does not refresh his list.
What can I do to refresh the spinner list?
In onCreate() I initialize the Spinner
_ItemSpinner = (Spinner) getView().findViewById(R.id.spn_itemss);
_ItemAdapter = new AdvancedCursorAdapter(
getActivity(),
R.layout.spinner_2line_item,
null, _ColumnList, _ColumnViews, 0);
_ItemSpinner.setAdapter(_ItemAdapter);
In onResume() I start the loader initialisation
#Override
public void onResume() {
getLoaderManager().initLoader(1, null, this);
super.onStart();
}
In onLoadFinished(Loader<Cursor> loader, Cursor data) I swap the cursor for the adapter
_ItemAdapter.swapCursor(data);
you can call the adapter's notifyDataSetChanged method
Finally I found out, not why, but which, element destroy the refresh of the spinner.
I used two different URIs of the same ContentProvider for updating all items and showing only active items
CONTENT_URI_ITEMS
CONTENT_URI_ACTIVE_ITEMS
If I use the same URI for updating and showing (with needed active filter), the spinner list will be updated. If I use different URIs, the spinner shows old data.
I don't understand this behavior (the cursor returns correct number of items, but the spinner doesn't care), but I have a work around that works.
Store data:
getActivity().getContentResolver().update(
RecordsContentProvider.CONTENT_URI_ITEMS,
_Changes,
COLUMN_ID + " =?",
new String[] { String.valueOf(_ID) });
Before (get data) - doesn't work:
CursorLoader curLoader = new CursorLoader(this.getActivity(),
RecordsContentProvider.CONTENT_URI_ACTIVE_ITEMS,
_ITEMS_PROJECTION,
null, null, null);
After (get data) - work:
CursorLoader curLoader = new CursorLoader(this.getActivity(),
RecordsContentProvider.CONTENT_URI_ITEMS,
_ITEMS_PROJECTION,
COLUMN_IS_ACTIVE + " =1", null, null);
notifyDataSetChanged is not necessary, if the underlying ContentProvider do this for you like this: (getContext().getContentResolver().notifyChange(uri, null);)
Have you tried:
getLoaderManager().restartLoader(0, null, this);
in your activity, just after making changes on a database.

ListView doesn't refresh after using changeCursor() on its adapter

I'm using a database, and there's a list fragment which use a cursor adapter to I get by querying the databse in a loader.
When the user press a list view item long press, he sees a context menu and a option to delete this entry.
When he press delete I'm starting a thread that deletes this entry and then start the loader again to get a new cursor (becuase "requery()" is deprecated).
When the loader finishes to load the new cursor I'm trying to use changeCursor method that suppose to refresh the list view but it doesn't do it, so I tried using notifyDataSetChanged but it doesn't work too.
I've checked and the cursor coming back from the loader and it does change the cursor but the list view doesn't refresh.
What should I do? Restart the fragment?
Here's some code:
case MENU_REMOVE:
final AdapterContextMenuInfo info = (AdapterContextMenuInfo)item.getMenuInfo();
mProgress = ProgressDialog.show(getActivity(), getString(R.string.list_remove_progress_title_text),
getString(R.string.progress_dialog_description));
new Thread(new Runnable() {
#Override
public void run() {
PlacesHandler wph = new PlacesHandler(getActivity());
wph.DeleteEntry(mPlaceName, info.id);
getLoaderManager().initLoader(0, null, ListFragment.this);
}
}).start();
return(true);
When finished loading:
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
if(mProgress == null || !mProgress.isShowing()){
...
}
else{
mProgress.dismiss();
mAdapter.changeCursor(data);
mAdapter.notifyDataSetChanged();
}
}
Thanks!
Thanks everyone but I found my problem!
The cursor that was returned from the loader was the same cursor as what was in the adapter.
This is because I called:
getLoaderManager().initLoader(0, null, this);
instead of:
getLoaderManager().restartLoader(0, null, this);
So because I've already used the loader with the ID 0 when I first loaded the cursor when the fragment was created, it just returned me the cursor immediately.
So if some people face the same problem and read it, just know that initLoader uses an existing loader with the specified ID if there is one. If there isn't, it creates one.
But if you want to discard the loader's old data and start over you should use restartLoader.
Again, thanks for anyone who tried to help!
After deleting a SQLite register, I simply did this:
myAdapter.getFilter().filter("");
Couple of things. I'm not familiar with fragments, so I'll just try to help you out.
Where are you updating the cursor to fetch the new data? Also, try using an AsyncTask to do the deleting. When done, update the adapter in the postexecute method.
I solved the similar problem by creating new curson and new adapter. And then setting new adapter to the list view:
myListView.setAdapter(listViewAdapter);
The ony problem of this approach is that my list view doesn't keep scroll position.

Android ListView update with SimpleCursorAdapter

Hey i use a listview for demonstrate entries which are stored in a database. I also have a EditText element and a button which adds the content of the EditText into the Database. To bind the view to the database content i use the SimpleCursorAdapter and following populate function:
private void populate() {
cursor = dbAdapter.getAllItems();
startManagingCursor(cursor);
String[] from = new String[] { DBAdapter.KEY_TASK };
int[] to = new int[] { android.R.id.text1 };
// Now create an array adapter and set it to display using our row
cursorAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, cursor, from, to);
list.setAdapter(cursorAdapter);
}
If i added a new entry, by clicking on the button i want to refresh the listview but this only works with the populate function and not with the common adapter function notifyDataSetChanged();. Do i have a bug or is this the right way to refresh a listview?
Have you seen this, tried the swap cursor method, or tried just simply calling setAdapter() again?
I had a similar issue where I could not get my list to update, and what I did was just create a refreshListView() method. Now you can call this initially from your onCreate(), AND anytime a user adds something to the DB. All it does is re-bind the listview to a cursor. With all the deprecating methods (requery()), and issues with notifyDataSetChanged(), I decided this was the easiest way.
Please refer this link...it works like charm
Update SimpleCursorAdapter while maintaining scroll position in ListView
for dynamic listview on scroll i added new item from database ..
I did mistake here ..
i was assigning new adapter for each time for same simplecursoradapter .
Instead of creating new adapter.
just use
adapter.changecursor(newcursorValue);
adapter.notifydatasetChanged();
lsMedicine1.setSelectionFromTop(lsMedicine1.getLastVisiblePosition()-20, 0);
You need to call swapcursor() before notifyDataSetChanged() on the adapter.

Categories

Resources