Updating a ListView With CursorAdapter When Querying Database - android

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

Related

How to update adapter items in viewpager

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.

CursorAdapter.swapCursor not refreshing the first time

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

Start loader from another loader. Right or Wrong?

I have listview that is populated through CursorLoader. CursorLoader is created by LoaderManager.LoaderCallback's createLoader method. I have no problems with this. The problem is in that I want to start another task when listview population is completed and fill listviews with additional data.
My current solution is to start a another loader inside onLoadFinished method.
Is this right solution or it can be done in more elegant and efficient way? Could you give some advice, because I don't have much experience in android development.
Thanks in advance.
Loading from onLoadFinished will working without a problem. I did something similar in a pet project I had. I loaded data from my own ContentProvider and from there loaded contacts data from the phone's Contact ContentProvider. Each entry in my db could reference multiple contacts so I had to load my item before I knew which contact info to load. I chained the init/restart LoaderManager call to when I first received my item data in onLoadFinished. It works just fine and I used the contact data as a list afterwards. Granted I didn't use this approach to load data into a view inside an existing list view item. I used the data inside its own list in a detail view for my item. It should still work with what you want to do, but it can get messy appending data to the views and whatnot, especially since the view "lifecycle" is outside your control.
A better approach, IMO, would be to code a custom CursorAdapter that would use an AsyncTask or AsyncQueryHandler to fetch the extra data as the views are being created. Make sure to cache the data for subsequent use as the list scrolls. This second approach has the benefit of being independent of the external/secondary loader. It encapsulates all the logic required to display the data you need which includes loading the missing parts. It keeps the view data and display logic cohesive, safely tucked away inside a reusable module.

Update Custom Fragment from ContentProvider

I am implementing two fragments to display different views on the same table retrieved from a ContentProvider:
1/ A class which extends ListFragment to provide the data in a list
2/ A custom fragment class which itself contains a Google Maps v2 fragment
The list fragment is a standard implementation using a loader and SimpleContentAdapter, so when the name of a list item is edited in a seperate activity, the change is reflected back in the list.
I want to do something similar with my custom fragment so that map markers are created and updated as the data changes.
What is the best practice for doing this?
It appears that using a SimpleCursorAdapter would not work since it returns View objects whereas I need to create/update Marker objects and these are not derived from View. I'm thinking along the lines of creating my own CursorAdapter class, implementing ContentObserver on my map fragment container and registering this with the CursorAdapter. Is this best practice? Does anyone know of any sample code demonstrating best practice?
Sorry if this is a stupid question - I'm new to Android programming so not completely clear on the notification architecture - but I have tried reading around the subject to no avail.
Okay, I've worked out the answer to this. There is no need for a CursorAdapter or a ContentObserver. The steps are as follows:
1/ Create Fragment-derived class (in my case derived from MapFragment)
2/ Implement LoaderCallbacks on this class
3/ Call getLoaderManager.initLoader() in onCreate() override of this class
4/ Create a new CursorLoader() in your LoaderCallbacks.onCreateLoader() override
5/ In LoaderCallbacks.onLoadFinished(), call code to iterate round the cursor and populate your view. But DON'T CLOSE THE CURSOR OTHERWISE YOU WON'T RECEIVE FURTHER UPDATES!!!
My problem arose from adapting some sample code in which the cursor.Close() was called once the list had been populated. I guess good practice is to save the cursor in a private data member and close it when LoaderCallbacks.onLoaderReset() is called.

How to pass data from a LoaderManager to another activity via an Intent?

I'm an Android newbie and I'm trying to update my (working!) code that uses a cursor so that it uses a CursorLoader. My app begins with an Activity with a ListView with three choices, Beginning, Intermediate and Advanced. Depending on which item is chosen, I want to open a second Activity with another ListView. That ListView will be populated from a SQLite database where all the items have a level of e.g., Beginning. Elsewhere on stackoverflow, it was suggested to me that I insert an Activity between these two activities to handle the actual data retrieval. So now I have three Activities. One has a ListView with three choices. That one sends a String to the second Activity via an Intent. The second Activity queries the database and retrieves one column from all the records matching the level chosen into a CursorLoader. And here's my question. I want to pass all this data to my third Activity so that the data can be displayed in a ListView. But how do I get the data out of the CursorLoader? I'm thinking I want to do something like:
Intent data = new Intent(getApplicationContext(), com.MyKnitCards.project.StitchList.class);
Bundle dataBundle = new Bundle();
dataBundle.getStringArrayList(myData);
where myData is an ArrayList of data from the CursorLoader. I have no idea how to do this. I'm wondering if I want to use LoaderManager to accomplish this, but I have no idea how to do this either.
Thanks in advance!
I would get rid of the middle man Activity that does the data retrieval and just do it in the Activity that displays the data. CursorLoader that automatically loads in the background so it won't freeze your UI, and that way you don't have to worry about passing data between activities.

Categories

Resources