At first, this is for a step counter.
My initial structure is a service keeps logging step counter value to database.
Then a async task keeps updating the value shown to user when the app is visible to user.
I planed to create a thread to periodically call the async task.
However, after digging into the official document, "async task should be created and invoked within UI thread".
The conflict now is UI thread should not be blocked vs calling async task periodically.
Or there is else a better way to implement?
Thanks for any input.
You need to derive from AsyncTask inside your UI class (service or activity).
Inside your AsyncTask (as described here) there is doInBackground which runs asynchronously and there is onPostExecute which runs inside UI thread after your asynchronous task is over.
Just put your DB operation inside doInBackground and put something like this inside onPostExecute
MyServiceClass.this.RunNextTask();
The RunNextTask method in your UI class could use the same AsyncTask to launch the next task.
Related
My App contains a function that takes time to load ( parsing files).
THe function is called at multiple user case, i.e. from multiple user triggered condition.
Besides, it is called when onCreate is called.
In simple word, the flow is:
User click/OnCreate trigger
Function to parse file
Post to windows
Other postprocessing
I hope the user can click cancel to stop parsing files.
I tried to use asynctask. I know I can put the function to onPostExecute.
But I assume onPostExecute is just for dismiss progress dialog. Or I have to move a lot of codes ( for different cases) to it. Not a good idea.
I do not suppose user to do anything during parsing files.
So, what is the best way to do so? Despite I know it is not good, I think i have to occupy the UI thread.
In simple word, I want to wait for "parsing files", but i do not want to occupy the UI thread, so user can click cancel.
update:
I tried. however, there is a problem:
I use asynctask. I called:
mTask = new YourAsyncTask().execute();
YourAsyncTask.get(); // this force to wait for YourAsyncTask to return.
DoSomethingBaseOnAsyncTaskResult();
YourAsyncTask.get() hold the UI thread. So, there is not loading dialog, and user cannot click cancel from the dialog. It seems I have to move every line after
mTask = new YourAsyncTask().execute();
to
OnPostExecute()
which i did not prefer to do so because DoSomethingBaseOnAsyncTaskResult() can be very different based on the return result. or else, it becomes do everything in YourAsyncTask()
AsyncTasks should ideally be used for short operations (a few seconds at the most.)
When an asynchronous task is executed, the task goes through 4 steps:
onPreExecute(), invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
doInBackground(Params...), invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time.This step can also use publishProgress(Progress...) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...) step.
onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.
onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
CODING
To start an Async task
mTask = new YourAsyncTask().execute();
and to cancel that task
mTask.cancel(true);
More detail is available here
In order to use the AsyncTask API, one has to follow the steps described below:
Create a class which extends AsyncTask.
Fill in the generic types available as generics in the class for:
the task execution array parameters
progress array parameters
result array parameters
Implement the method doInBackground(Parameters... parameters). This
method must execute the job which is supposed to be quite demanding.
Optionally, one can implement methods for:
cancelling the task - onCancelled(...)
executing tasks before the demanding task - onPreExecute(...)
reporting progress - onProgressUpdate(...)
executing activities after the demanding task is finished
-onPostExecute(...).
I am parsing the xml file containing some names using the Async task and populating these names to the listview again via the main thread. But whats happening in my case is, when the Async task is still running, the main thread is already populating the names to the listview which is resulting in no items on the listview. Should i make the main thread wait until the Async task finish the job or is there any other way to solve this prob.? if yes how can i make the main thread wait when i don't know that how long the Async task might take to finish.?
If you want to complete the AsycTask then you can use .get() method from AsyncTask. (Which will block the MainUiThread)
But I think the best approach is without blocking MainUiThread you have to start ProgressDialog on onPreExecute() and after populating ListView in onPostExecute() of AsyncTask finish the ProgressDialog in onPostExecute().
If you have used AsyncTask, then do the xml fetch in doInBackground() and update all your UI elements of the listview inside the onPostExecute(), this runs on the main UI thread and is automatically after doInBackground(). This way you dont have to explicitly make the UI thread wait
You don't want to block your main thread and wait for the async task (this would defeat the purpose of the async task). Instead, the async task should trigger the update when it is finished in the onPostExecute method.
You may also want to have a look at the more recent Loader design.
- First of all Main thread in Android is the Dedicated UI thread.
- What you need to do is to fill the List by parsing the xml with the names and then proceed to Displaying it on the ListView.
- You can use CoundDownLatch from java.util.concurrent package to fill in the data into the list before showing it on the ListView.
- Use the method like await() and countDown() of CoundDownLatch to do this.
use AsyncTask.get() to wait until AsyncTask finish.
NOTE : this will stop execution of Main Thead until result not retrieved from AsyncTask
String str_result= new RunInBackGround().execute().get();
Log.e("","show this");
RunInBackGround is your AsyncTasc class name.
First will run async task and when it finished will show the bellow message!
I have 2 async tasks (which does server requests) running just before i leave my activity.
sometimes the activity which runs this async tasks gets stuck until the async tasks finish, and sometimes the next activity shows and gets stuck until the async tasks finishes.
my question is how do i run this task in a way in which my activity's UI doesn't gets stuck (the UI is not dependable on the responses in the async tasks)
You are probably calling AsyncTask.get() somewhere in your activities code. If you call it before the task has finished executing, it will wait untill it does finish (Thus making your UI get stuck).
Can you try this.
Create a ProgressDialog set it to indeterminate and show it.
Call AsyncTask1 and in its PostExecute call AsyncTask2. Make sure you need to call this onUiThread.
In Postexecute of Asynctask2, dismiss the Progress dialog and start the next Activity.
Make sure you start your next activity on the onPostExecute() of the first Async Task. And if you have an Async task in the new activity ,call it as the last item on your onCreate Method. Following these simple rules should help
Write the code in AsyncTask doInBackground() only and call it. So that you can check whether it is accessing any UI.
eg: TestAsync extends AsyncTask...
TestAsync async = new TestAsync();
async.execute();
Try this.
Normally, AsyncTask should run in separate thread. If you create two instance. and call execute, It should execute independently. But there may be only one thread available, So it should wait(In lower version, pool size is 1.).
#TargetApi(Build.VERSION_CODES.HONEYCOMB) // API 11
void startMyTask(AsyncTask asyncTask) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
else
asyncTask.execute(params);
}
Other way is, You should run it in normal Thread.
you are must be calling 2 activities at a time in your activity
so either you must use synchronized class or function to call asynk task
or you must use singleton class to call that asynk task so that api is called in synchronized manner
as asynk task uses main ui thread to complete the task so that can be the reason that activity is getting stuck
Why can an AsyncTask perform only one job? For example,
task = new SubAsyncTask(...); // assume the parameter is correct.
task.execute(...) //
task.execute(...)// calling once again, it throws exeception.
But a Handler can continously perform more than one task:
hd = new Handler(...); // assume the parameter is correct
hd.sendMessage(...); //
hd.sendMessage(...);// no exeception is thrown.
Is an AasyncTask object for a one-time job only? If I don't want to create multiple object for similar task, should I choose Handler?
Handler and AsyncTasks are way to implement multithreading with UI/Event Thread.
Handler allows to add messages to the thread which creates it and It also enables you to schedule some runnable to execute at some time in future.
Async task enables you to implement MultiThreading without get Hands dirty into threads. Async Task provides some methods which need to be defined to get your code works. in onPreExecute you can define code, which need to be executed before background processing starts. doInBackground have code which needs to be executed in background, in doInBackground we can send results to multiple times to event thread by publishProgress() method, to notify background processing has been completed we can return results simply. onProgressUpdate() method receives progress updates from doInBackground method, which is published via publishProgress method, and this method can use this progress update to update event thread, onPostExecute() method handles results returned by doInBackground method.
So, you dont need to call execute method on AsyncTask multiple TImes, instead you can invoke publishProgress.
Because that is how the class was designed. The idea is: do something with UI (show progress dialog, etc.), do work on background thread and return results, update UI. The Handler is fundamentally different: it lets you post messages, but it does not create a background thread for you. If you don't like how AsyncTask works, build something similar by using threads/executors and handlers.
I have a a service class which includes an Async task. In the doInBackground and onPostExecute I call some methods which are in the service class but outside the Async task. When these methods get called will they still be in the thread created by the Async task and therefore not interfering with the main UI.
To illustrate my lack of understanding a bit more should I try to get almost everything that the service class does into the Async task. For example the service starts up as the result of an alarm and in the onStartCommand sets a repeating alarm (this is as Reto Meire's Earthquake example)and creates a database. Would it make sense to move the code for these two operations into the onPreExecute part of the Async task?
No need to do that.. make sure that the method which you want to run in background is called from doInBavkground().. rest you can put in postExecute.... the snippet which you want to run after the backGround task should be in PostExecute(). If You call methods from doInBackground() they still run on background thread.. does't matter where they are.. and if you call it from onPostExecute() then it will run on other thread which ofcourse can make changes in your display.. just like showing dialog etc...
You should always offload as much work as possible to background threads/tasks. Something like database creation should be done in the doInBackground method. The onPreExecute and onPostExecute methods run on the UI thread and are generally used to inform the user of background activity (e.g. using a ProgressDialog).
From experience, I also suggest not using a background service if you can get away with it. If you use one, you should know how to clean it up properly since users generally get annoyed with an application running in the background.