Android: Spinner does not update after change of dataset - android

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.

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.

How do you amend a row value before displaying it using ListView and SimpleCursorAdaptor?

I'm using SimpleCursorAdaptor and a ListView to display the values in my SQLite database rows. One of the values in my row is a date (column 'date'). Rather than display this date I need to run this through a method that will return another string based on what the date is. This is the value I want displayed in my list rather than the actual value taken straight from the Database.
In short I wish to display all values from my database table row except for one, where I need to change it before displaying it.
Here is my code:
public class BinCollectionDayListActivity extends ListActivity{
//
private static final String fields[] = { "name", "date", BaseColumns._ID };
//
public void onCreate(Bundle savedInstanceState) {
//
super.onCreate(savedInstanceState);
//
DatabaseHelper helper = new DatabaseHelper(this);
SQLiteDatabase database = helper.getWritableDatabase();
Cursor data = database.query("names", fields, null, null, null, null, null);
CursorAdapter dataSource = new SimpleCursorAdapter(this, R.layout.binrow, data, fields, new int[] { R.id.name, R.id.date });
dataSource.getCursor().requery();
//
ListView view = getListView();
view.setHeaderDividersEnabled(true);
setListAdapter(dataSource);
//
helper.close();
database.close();
}
}
As you can tell I am pretty new to Android development and would love to know what the best approach would be to achieving the desired result.
Thanks in advance,
Tony
Two options that I've used before:
Array Adapter (Preferred):
Create an ArrayAdapter and populate the Cursor data into your ArrayAdapter.
http://anujarosha.wordpress.com/2011/11/17/how-to-create-a-listview-using-arrayadapter-in-android/
ViewBinder: On your Cursor, you can setup/specify a ViewBinder where you can check the data that's about to be mapped, perform some logic on it, and spit out a different result if desired. This is probably exactly what you're looking for, but do consider the ArrayAdapter as it tends to give you better control and it's a pain to switch these things later on.
Changing values from Cursor using SimpleCursorAdapter

Android ListView Live Updating

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

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.

Refresh spinner data

I have an application with a Spinner whos data is populated by a cursor from the database. Works great if there is something in the database table on startup. However, if I add something to the database after the app is running my spinner always shows that it has zero choices, even if one was there to begin with.
My code is as follows. The adapter.getCursor().requery(); did no good. I would like the Spinner to update its choices when the user clicks on it and I found a couple posts on StackOverflow that say you have to use the TextView behind the Spinner for the OnClickListener. However, for me that did nothing. Mostly likely because I'm missing one minor
c1 = myDbHelper.readCars();
startManagingCursor(c1);
// create an array to specify which fields we want to display
String[] from = new String[]{"nickname"};
// create an array of the display item we want to bind our data to
int[] to = new int[]{android.R.id.text1};
adapter = new SimpleCursorAdapter(this, android.R.layout.simple_spinner_item, c1, from, to);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinVehicle.setAdapter(adapter);
txtVehiclePrompt.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
adapter.getCursor().requery();
}
});
Just change the underlying data and call notifyDataSetChanged()
list.clear();
//list modify
list.add("A");
list.add("B");
dataAdapter.notifyDataSetChanged();
Ok,
I got it figured out. I needed to close the adapter, stop managing the cursor, close the cursor & close the db helper in the onSuspend() method then set everything back up in the onResume method since I was using a seperate activity to add records to the table.

Categories

Resources