I have a ListActivity and use a CursorLoader to load the data which is stored in a ContentProvider. I use a custom class extending CursorAdapter to display the list items. In the LoaderCallbacks onLoadFinished I have the following:
public void onLoadFinished(Loader<Cursor> loader, Cursor newCursor) {
cursorAdapter.swapCursor(newCursor);
}
I have a custom layout for the ListActivity which includes a TextView with android:id="#android:id/empty".
The problem is that when I open the application for the first time calling swapCursordoes not refresh the ListView even though there is data to show in the ContentProvider. When I add a new item to the ListView, the list is refreshed properly. However, if I comment out the TextView, which displays a simple text when no data is available, the application works as expected. The swapCursor call automagically updates the ListView accordingly.
Any thoughts on why this occurs or if there is a proper way to do this since I believe calling notifyDataSetChanged won't do the work as the refreshing fails on a very particular case?
You're having this problem because ListActivity automatically sets the empty view (if available) to your ListView.
I'd suggest you try one of these:
Extend activity and after swapCursor call
listView.setEmptyView(findViewById(android.R.id.empty);
Make the empty view gone: android:visibility="gone" and after swapCursor call
findViewById(android.R.id.empty).setVisibility(View.VISIBLE);
#onCreate call listView.setEmptyView(null) and after swapCursor call
listView.setEmptyView(findViewById(android.R.id.empty);
Not sure about all of them, but one of em will certainly work :)
Related
I have viewPager() which have 3 pages, it have a recyclerView and each page have three different adapters and i want something like when user clicks on adapter item in first page it adds in a database and second adapter gets its array list from the same database, but it shows in second page's adapter after app restarts, so the question is how to update the second page's adapter without restart.
A regular ListView can use a CursorAdapter which provides some of the functions you need. Alas, there is no existing CursorAdapter class that extends RecyclerView.Adapter.
The quickest solution would be to use RecyclerViewCursorAdapter on GitHub.
Then it would work something like this:
Update your database
Get a reference to your second page fragment. You can store this reference when you create the fragment in getItem(). Note that your fragment could be null depending on what pages the ViewPager has/hasn't created.
Call a method on your fragment that will create a new Cursor to be used by the adapter (with the same query as before). When the adapter receives the new Cursor it will update the RecyclerView.
I have a ListView and an CustomListAdapter that extends CursorAdapter. I'm using a LoaderManager to load the data into my CustomListAdapter when I first load the Fragment containing the ListView. That all works fine. I'm using ContentProviders so any updates or changes to the underlying data in the database are reflected in the Listview.
Now I want to allow the user to search for specific items in the list. So in other words i want to update the list view based on the search query obtains from the SearchDialog. I've got the SearchDialog working and I'm up to the point where I receive the intent in ParentActivity of the ListViewFragment, with the search query. However I'm not really sure what I should be doing now.
I was thinking of detaching and then re-attaching the Fragment to the ParentActivity passing the search query string to the ListViewFragment so that the onCreateLoader() method of the fragment could use the query to do another search. This seemed like an easy way to achieve what I wanted to do.
Is this the correct way to update a ListView based on a search? Or is this overkill for what I'm trying to do? Does anyone have any other suggestions?
Kind Regards
For anyone that wants to know, my requirement changed and instead of using the same Activity to view the results, I sent the results to a new SearchResultActivity that was re-using the ListViewFragment.
I created an instance variable on the ListViewFragement that would store the query string. When creating a new instance of the Fragment, it expects a value for this query string. When I load the Fragment from my first Activity, the string is null and the onCreateLoader() by default loads all the results. When I load the Fragment from SearchResultActivity I pass in the query result from the SearchDialog and the onCreateLoader() will use the query to return a Cursor based on a specific selection.
I didn't need to attach and re-attach the fragment in anyway. However if I was to use the same Activity and ListViewFragment to display the search results, instead of detaching and re-attaching the fragment to the activity, I would probably use the restartLoader method of LoaderManager:
LoaderManager Doc
I am trying to display a list fragment in the middle of my activity. The list fragment adapter is a custom adapter (extended from BaseAdapter) with the typical ViewHolder pattern. It is implemented correctly.
I have the adapter set up with greenrobot Eventbus to receive a new List object from an asynctask which does the query in the background (as not to slow down the UI Main Thread).
The problem is the list fragment doesn't have the results of the database query initially so it defaults to empty (and displays the textview in my xml for the main activity which has the id 'empty').
In the end, my adapter, and listviewfragment don't get instaniated at all because it defaults to empty.
Is there a better method to doing this?
How can I get my listview fragment to wait for the data recieved from the asyncTask?
I am going to just do a fragment with a listview in it, instead of a listview fragment, and I'll see if that will help.
As I understood correctly, you did everything okay so far. What you have to do is to add an "update" method to your adapter, and call this whenever your asynctask finished it's job and got the results for you.
This update method should look something like
public void updateAdapterData(List<String> newList) {
mItems.clear(); // say mItems is the global list you have in the adpater
mItems.addAll(newList);
notifyDataSetChanged(); // This will cause the adpater to re-draw it's rows, so now data should be visible in your list
}
And in your fragment you do somehting like:
adpater.updateAdapterData(newList);
Does this help?
I'm using a CursorAdapter to fill my ListView. I get the Cursor through a basic CursorLoader that gets the data from my ContentProvider. Right now, when the Cursor is loaded in onLoadFinished of my LoaderCallbacks<Cursor>, I call setNotificationUri() on the Cursor and in my ContentProvider, I'm calling getContext().getContentResolver().notifyChange(MY_CONTENT_URI, null) whenever a change to the database has occurred.
The desired behaviour is that I can get notified whenever there's new data in the database and provide an option to the user to reload the Cursor and repopulate the ListView. Any suggestions on how I can handle this?
This may not work with the standard CursorLoader. CursorLoader implements its own ContentObserver that is registered on your behalf. When there is a notification on the Uri, the loader will automatically force a reload of the cursor.
I see two possibilities:
Allow the loader to reload the cursor. In onLoadFinished of your LoaderCallbacks, you can present the user with the option and only change the cursor in the adapter based on their response.
Write your own CursorAdapter implementation that offers some hook at the moment it wants to reload the data. You can start by examining the source code for CursorLoader and its superclasses. In particular, the method onContentChanged, which is called by the internal ContentObserver, seems like a good place to add this extra behavior that your want.
what you want is notifying another Structure instead of ListView, isn't it?
i.e. that would be code to notify a ListView with CursorLoader
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Swap the new cursor in. (The framework will take care of closing the old cursor
// once we return.)
dataAdapter.notifyDataSetChanged(); // <- Here we notify the change to Adapter
listView.setAdapter(dataAdapter); // <- Then we set ListView with Adapter
dataAdapter.swapCursor(data);
}
So, then all you need is overriding notifyDataSetChanged Method of your CursorAdapter, so that, this Class inherits from BaseAdapter and this Class have such a Method. You can perform there in what way and what you notify.
Then you just should replace ListView for you want to be notified in the above code.
Before listview.setAdapter(dataAdapter) you could call a dialog in order to ask User whether ListView should be populated or not. I'd do it like this.
I hope, that could help you.
Kind Regards.
p.s. I chose notifyDataSetChanged, you can use this approach for other notify-Methods, just see whether they are implemented for an Adapter.
I identified a problem in changing one activity using tab. In one tab activity I'm adding data to my SQLite database, and in the other tab activity I am displaying them using listview(array adapter). But when I come back to add data after adding new items to SQLite, the newly added records are not updated in my listview.
How do I fix this?
You seem to be pulling the list data from a DB. Is there a reason why you are using an ArrayAdapter instead of a CursorAdapter?
Anyway, you should call notifyDataSetChanged() on your list adapter when the data has changed so it can refresh the view.
you can add code to update your listview (via notifyDataSetChanged or some such) by overriding the onResume() method in your activity which is called whenever the activity is brought back to the foreground.
See http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle