Avoiding ANRs with Cursors - android

I have an activity that runs a query on a Sqlite DB, gets a Cursor, creates a CustomCursorAdapter with that Cursor, and attaches it to the ListView in the activity. It looks like this:
SQLiteDatabase db=new StuffHelper(this).getWritableDatabase();
Cursor c1=db.query(StuffHelper.TABLE,
new String[]{StuffHelper._ID},
StuffHelper.SIZE+">=?",
new String[]{"64"},
null,
null,
null);
startManagingCursor(c1);
StuffAdapter a1 = new StuffAdapter(this, c1);
ListView ll1 = (ListView) findViewById(R.id.ll1);
ll1.setAdapter(a1);
Is this current setup a problem in terms of ANR? When using cursors, how can I tell android to run all the Sqlite stuff on a background thread?

You didn't give much context of when this code is run, but I'll bite anyway...
Yes, it does run the risk of an ANR. It also runs the risk of various other lifecycle problems. Since setListAdapter() needs to be called before various other thing that you'd normally do in onCreate() you probably want to offload the database access to a separate thread (like an AsyncTask) that can be called/cached/managed as needed. AsyncTask gives you a UI-based callback before the thread starts and a UI-based callback when the thread ends. The ListAdapter can be created and assigned without any references to a Cursor (and I'd suggest you fix that asap... there doesn't seem to be a good reason why you're using a custom list adapter, you should be managing your database access better instead).
Managing this task over activity teardown and rebuilding (think changing orientation...) is an entirely different ball of wax and has been covered ad nauseam on SO.

Please separate your UI from background tasks. Write the cursor portion in background and in forground you can show any UI or progress dialog. Use AsyncTask for this
AsyncTask class has following methods
1. doInBackground: Code performing long running operation goes in this method. When onClick method is executed on click of button, it calls execute method which accepts parameters and automatically calls doInBackground method with the parameters passed.
2. onPostExecute: This method is called after doInBackground method completes processing. Result from doInBackground is passed to this method.
3. onPreExecute: This method is called before doInBackground method is called.
4. onProgressUpdate: This method is invoked by calling publishProgress anytime from doInBackground call this method.
How to use AsyncTask
Thanks
Deepak

Related

AsyncTask and CursorLoader [Android]

My AsyncTask for fetching data is a long one, and at the same time, in the midst of constructing my recyclerview I wanted to check if a cursorloader was able to query from my content provider correctly.
Bear with me here, I used Loader Callbacks interface and onLoadFinished to get results. Since the asynctask is still running, the loader still calls the content provider as it gets updated until asynctask ends. I would except that since onLoadFinished primarily deals with filling in the contents of an adapter with cursor data that I shouldn't worry that it prints out log statements simultaneously as the asynctask continues to run, but I wanted to confirm.
I do intend to eventually move this asynctask into an intentservice that only gets called via broadcast.
You can call getLoaderManager().restartLoader(URL_LOADER, null, HomeFragment.this); to restart the loader on you AsyncTask onPostExecute method. You need to init the Loader first on you onCreate() method.
This way, the loader will refresh with the same projection it had when you started it and it will fetch the results of the AsyncTask operations from DB.

Get data from more than one AsyncTask in one class?

My situation is this:
first I call first AsyncTask which fetched required Items from database. After that, I call another AsyncTask, which fetches these Item images.
I am getting data from AsynTasks by using callback.
Here is the issue - since I am using callback, in my class I have method processFinish which returns AsyncTask data when it finishes its computation. The problem is with two Async tasks which depend on each other. What should I do now?
You can use the get() method of asyncTask that will wait for the output and wont proceed further
also you can use it with a timeout.
ex new BackgroundTask().execute.get();
or
new BackgroundTask.execute.get(long timeout);
You could execute one AsyncTask inside another, but you should do it inside onPostExecute() because this method runs on the UI thread.
#Override
protected void onPostExecute(Void args) {
new AsyncTask2.execute(..); // Start second task once you've got first results
}
And you call your method processFinish(..) only once, after the second AsyncTask is completed.
Anyway, is there a reason why you use two AsyncTasks ? With your explanations we could believe that you might be able to use only one task.

Synchronize testing thread, UI thread, and CursorLoader thread

My understanding is that Android instrumented JUnit tests run on their own thread unless annotated with #UiThread or calling Instrumentation.runOnMainSync() or Activity.runOnUiThread(). Now I'm trying to use a CursorLoader to access my app's database and populate a ListView. I also have a test which verifies that the ListView is populated correctly.
My problem is that I need to synchronize three threads: the test thread should wait until the CursorLoader thread finishes and notifies the UI thread to populate the ListView. To create a CursorLoader, I register a LoaderCallbacks with the support LoaderManager and create the instance in onCreateLoader(). Then onLoadFinished() changes the cursor of the ListView's adapter.
Now I need to ensure that my test waits until onLoadFinish() has been called before attempting to access the child views of the ListView. My current idea is to add a waitForData() method to my LoaderCallbacks implementation which the tests can call. However, I'm not sure how to implement this method. Can I simply use a wait() and then notifyAll() in onLoadFinished()? Or do I need to use something more sophisticated like a Semaphore?
Espresso handles this type of synchronization. I have not yet worked with it to figure out the details, but it looks very promising.

How do I query a cursor in another activity from AsyncTask?

I have an AsyncTask called from Activity1 and Activity2 that is visible now. From Activity2 I am making some changes in the running AsyncTask and AsyncTask must requery cursor in my Activity2.
How do I verify that Activity2 is visible and requery cursor within it from AsyncTask?
I am a little confused -> you want to requery a cursor, that is not in your AsyncTask, but in your Activity? Don't you use AsyncTasks, exactly, to do DB Queries in separate Thread? So why would you like to do that? On the subject of how to (try to) detect if your activity is visible, there's already an answer
EDIT:
You should have defined the AsyncTask as private class to an Activity (I assume you did it like that for Activity1). All methods in AsyncTask, except doInBackground() are executed on the UI Thread of the Activity you've defined the task in.
You don't have to call directly onProgressUpdate(), instead you have to use publishProgress(), but I think you cannot call it from your Activity2.
I am not sure what exactly you're trying to achieve, but maybe you should consider looking at Handlers.

Android progressbar thread exception

Question arising from my first attempt at using an Async object.
I have a main activity in which some TextViews have been created programmatically and added to a LinearLayout. Also a button, when this is clicked, an AsyncTask object is instantiated and results are obtained in the doInBackGround method. How should the result strings be transferred to the TextViews?
a) by calling the SetText methods of these TextViews from the onPostExecute method,
b) using intents and an onActivityResult method in the main activity
c) some other way (a clue would be nice!)
Thanks!
I would go for the AsyncTask option. I'm guessing that as you already have one in place, the obtaining results part that happens when you click the button takes time, so it's good design to have that in the doInBackground method of the AsyncTask.
Then you can call each TextView's setText(...) method in the onPostExecute method in your AsyncTask. Or, it's more suitable, you can update each view as you get the result by using the publishProgress(...) and onProgressUpdate(...) methods (see the AsyncTask documentation) during the background calculations, instead of having to wait until the end.
Just bear in mind that you can only call setText(...) from the onPreExecute, onProgressUpdate and onPostExecute methods, as (at least it seems this way from your explanation) the views have been created on the UI thread, so they can only be modified from that same thread, which those methods run on.
When using an AsyncTask, you can use the doInBackground method for processing, and the onPostExecute to update any UI changes. So, if you need to use an AsyncTask, I'd go for option A.
Make the TextViews private and define them in doInBackground, then you can just call the setText method in onPostExecute or as the last thing in doInBackground, but i would recommend onPostExecute.

Categories

Resources