Safely add/remove ListView item from different thread - android

After filling a ListView from local SQLite I want to fetch data over the network from a remote Database in order to retrieve new Data, and show it in the ListView so that the local SQLite Database is just a fallback method in case of no internet.
I was using a different Thread to insert the network-fetched data into the SQLite and then re-fill the ListView list.
Naturally, the app crashes because at some point the second Thread is removing every item on the list (to add new ones) and at the time, the UI Thread is trying to access an index who's been deleted by the secondary thread.
Since this is for academical purpose, the idea is not using external/custom libraries, so what'd be a good approach that doesn't include custom libraries?

Wrap the database in a content provider. Not difficult to do, since you already have the database. Instead of writing your own Thread, use an IntentService to fetch the network data and write it into the content provider.
In your Activity, use a CursorLoader to load the data from the content provider in the background. CursorLoader includes an implementation of onDataSetChanged(), so every time the content provider is updated, the Cursor will be reloaded. Every time the Cursor reloads, swap the new Cursor into the CursorAdapter that backs your ListView.
To communicate between the IntentService and your Activity, do two things:
Send a local broadcast Intent (using LocalBroadcastManager) from the IntentService to the
Activity when the network download completes. If your Activity is in the foreground, it
will get the broadcast immediately, and you can fire off CursorLoader for the first time.
Also post a notification from the IntentService. In this notification, include a content
Intent. If your Activity is in the background and the IntentService completes, the user
sees the notification. He or she can then click the notification to go back to your
Activity. You can fire off CursorLoader if you need to, or what until CursorLoader restarts automatically.
Your issue points out the desirability of rethinking app structure when you're programming in Android. Android apps aren't linear; they're more like mega-objects that interact with each other according to their current state. For this reason, you should avoid writing your entire app in one Activity, or writing it from the top down.
Also, there's hardly ever a reason to create a new Thread() on your own. Android offers plenty of classes that handle asynchronous processing for you. If you find yourself coding a Thread() or run(), be wary.

Only update the ListView on the main application thread. For example, instead of a Thread, use an AsyncTask, where you do your disk and network I/O in doInBackground() and update the ListView in onPostExecute().

Because the data shown in ListView is shared, you have to protect it via synchronization. You should write the code synchronized (data) {// data operation} in different thread in case of crash

Related

Where to call IntentService to populate data into SQLite for RecyclerView Adapters in Android

I have an Activity that has a fragment which is full screen RecyclerView. The fragment implements LoaderManager.LoaderCallbacks<Cursor>.
I have an IntentService that goes out and fetches data from an API, deletes any existing data in the local SQLite database, and then stores the new data all via a content provider.
The Loader then Loads whatever data was put into SQLite into the RecyclerView.
My question is:
Where would be the most efficient place to put my code to fire off the IntentService?
Just wondering if there are any conflicts that could arise if placed in an inappropriate place.
Currently, I have it as the last lines in OnCreate() in the Activity:
// Fire off service to get data
Intent i = new Intent(this, MyService.class);
startService(i);
Other places I was considering putting it:
In the OnCreate() in the fragment.
In the OnActivityCreated() in the fragment.
In my opinion, running it in onCreate of your activity is just fine, however in this case, your RecyclerView may present outdated contents to the user. So you should somehow notify your RecyclerView from inside that IntentService and make it to re-query the database.
Running that service in onCreate of that fragment or OnActivityCreated() wouldn't give you any performance gains.
To bring a better user experience to your users, I would suggest you that use pull-to-update libraries to fire off that service and update the list whenever the user drags it down. Just like Instagram app.
First, I would like you to take a look at this answer in SO that also has links to android documentations.
Also from the documentations, an IntentService has few limitations:
An IntentService has a few limitations:
It can't interact directly with your user interface. To put its results in the UI, you have to send them to an Activity.
Work requests run sequentially. If an operation is running in an IntentService, and you send it another request, the request waits until the first operation is finished.
An operation running on an IntentService can't be interrupted.
However, in most cases an IntentService is the preferred way to perform simple background operations.

What's practical purpose of cursorLoader?

I saw some articles about CursorLoader like this, but I still don't understand the particular purpose of using it.
I developed apps with SQL and cursor retrieving. The point is it was very fast. I queried and parsed cursor with >500 record and 8 columns by a few millisecond. So didn't notice any delay event on old phones. So why do I need to use it?
A CursorLoader is used ostensibly to query a ContentProvider with LoaderManager.LoaderCallbacks<Cursor>.
There are two things that you need to keep in mind for understanding the CursorLoader:
It loads data on a separate thread.
It monitors the underlying data source for updates, re-querying when changes are detected.
Now coming to the LoaderManager. Simply stated, the LoaderManager is responsible for managing one or more Loaders associated with an Activity or Fragment. Each Activity and each Fragment has exactly one LoaderManager instance that is in charge of starting, stopping, retaining, restarting, and destroying its Loaders. These events are sometimes initiated directly by the client, by calling initLoader(), restartLoader(), or destroyLoader(). Just as often, however, these events are triggered by major Activity/Fragment lifecycle events. For example, when an Activity is destroyed, the Activity instructs its LoaderManager to destroy and close its Loaders (as well as any resources associated with them, such as a Cursor).
The LoaderManager does not know how data is loaded, nor does it need to. Rather, the LoaderManager instructs its Loaders when to start/stop/reset their load, retaining their state across configuration changes and providing a simple interface for delivering results back to the client.
So you see, all this is not easily possible when you use a simple AsyncTask and query an SQLite database. This is why the framework provides CursorLoader and LoaderManager:
To perform queries on a separate thread.
To monitor the data source for changes and update the UI.
To integrate easily with the life cycle of Activity and Fragment.
The practical purpose is simply how Android handles UI elements (that is on the main thread). Basically, anything that may be a long running process, run it in a background thread so you don't lockup the main thread. This can't be said enough. After Gingerbread this has been more enforced by Android itself. Check out SQL helper. To get to the point in regards to opening an SQLite connection and its "speed":
Because they can be long-running, be sure that you call getWritableDatabase() or getReadableDatabase() in a background thread, such as with AsyncTask or IntentService.
By using CursorLoader, it makes your life easier if you need ContentResolver and are using SQLite DB. More importantly, it runs on the background. Just because you've never seen the DB lock up doesn't mean it doesn't happen. Better safe than sorry, and the main thread will thank you :)
Use the CursorLoader from Support Library to run asynchronous queries in the background. In this way, you ensure that data loading does not cause “Application Not Responding” messages.
A CursorLoader runs a asynchronous query in the background against a ContentProvider and then it returns the result back to the Activity or the Fragment from where it is called.
The main advantage is that it helps the user to interact with Activity or Fragment while the query is still running in the background.

Check SQLite database for duplicate entries, CursorLoader/Loader/AsyncTaskLoader? Confusion

As I posted here Need SQLite to replace only rows with new information, I need to get information from a webserver and compare it with what I have in my SQLite database. (Android App)
I currently have an AsyncTask implemented that gives me a HashMap.
I was in the process of coding an SQLite database when I came across Loaders.
I am confused about how to do this.
Do I want to use CursorLoader or AsyncTaskLoader in this case? Do I replace the current AsyncTask subclass that I have now?
private class getFleetList extends
AsyncTask<String, Integer, HashMap<String, ArrayList<Vehicle>>> {
#Override
protected HashMap<String, ArrayList<Vehicle>> doInBackground(
String... params) {
//...implemented AsyncTask
}
My current guess is that I will replace my AsyncTask. A tutorial link or something would be very helpful. All tutorials that I have found use broadcast receivers or post to ListViews and that is not what I am doing.
Thanks
An AsyncTask runs code on a non-UI (usually called a "background") thread. An AsyncTask can do anything, but it's a bit fragile because it disappears if the system restarts the Activity that started the AsyncTask. This can happen quite easily, because the system restarts the current Activity if the user rotates the device (unless you trap onSystemConfigurationChanged).
Formally, an AsyncTaskLoader is a Loader that uses AsyncTask to run its code. This means in real terms that an AsyncTaskLoader gets data from somewhere by using a non-UI thread (the AsyncTask part). The loader part just gives you convenience methods for dealing with the process of getting data, which may take a long time. The loader part also lets you track the data and restart the load if the data changes.
Based on what you've said, your current implementation can use either AsyncTask or AsyncTaskLoader. If you need the features of Loader, choose AsyncTaskLoader; otherwise, stick with AsyncTask.
You can't use CursorLoader. Although it's not immediately obvious, you need a content URI to create a CursorLoader, which means you need a content provider. In your situation, there's no obvious advantage in using a CursorLoader. A CursorLoader adds stuff on top of AsyncTaskLoader, such as a built-in ContentObserver that automatically triggers reloads when data for the original CursorLoader query's content URI changes.
Basically, you're just looking at layers of class definition that add functionality for more and more specific situations.
Having said all this, I see that you want to ensure that a web server's database and the device's database are always "in sync". Correct?
You can always tell when a row has changed in a content provider, because you can register a ContentObserver for the provider. When something in an app tries to mutate the data being "observed", you get a callback. The system detects the mutation by comparing the URI passed to the ContentResolver call to the URI you register to observe. Unfortunately, you can't do this for an SQLite database.
If data on the web server changes, you can notify a device using Google Cloud Messaging.
In both cases, you can create a sync adapter to handle the data transfer and synchronization tasks, and run it when the data changes.
The tricky part is deciding how to handle conflicts, but you're only looking for updates and additions (and deletions?).

Android Querying Web Service in Real Time

I have written an application that queries a web service I wrote (which returns JSON data). My app currently processes the web service call using an AsyncTask and updates a TableLayout with the data it receives. I want my app to regularly (every second or so) call this web service and display the data in the DB, as it is continuously being updated. How can I go about doing this without having the UI thread block?
Currently the way things work is the user presses a "go" button, and the AsyncTask displays a "loading" dialog while the request processes. I would like for them to press the go button once and have the data refresh in the layout. I'm not sure what the best way to architect this is.
I wouldn't recommend that you create a new AsyncTask every second since this is going to result in a lot of object creation and corresponding memory collection.
What you can do instead is create an AsyncTask that after each request returns from the web service updates some internal data structures and then calls publishProgress(), waits the appropriate amount of time, then makes a new request to the web service. In onPublishProgress() the code should then get the new information from the request from whatever internal structures are being used (don't forget to use a lock here to synchronize access) and refresh the UI.
You'll also want the AsyncTask to have a method or variable that the Activity can call to tell it to break out of the loop.
You can use a Handler which can initiate a new AsyncTask request after every second.

Do I need a handler?

I am working on an Android application and I have a question. I have a listener class that runs on back ground periodically and get data from my server. I want to add that data into a data structure in the main thread. In this case, I am not touch the main U.I. but I was wondering if I should use a handler to add the data into the data structure in the main thread. Or can I just set the data structure as static and access from the listener class to insert the data. Which way should I do? Thanks in advance.
One way to do that (but there are others) is to use a list view and a cursor (it means you should use a database).
When you receive data from server (in your background thread), you add them to the database.
On the UI thread, you register a ContentObserver to be notified when data is added. When you're notified, you just have to requery
If you don't want to use a database, you can then send a Broadcast (see BroadcastReceiver) in which you can add data.

Categories

Resources