I have two asyncTasks, say A and B. Both are called from different activities. Situations arise when A needs to be called and then my app moves to another activity and B is called. A's duration is greater than B. Now the problem is that when I invoke A and then move to other activity and invoke B, it waits for A to complete and then B is invoked.
Please understand the question and then downvote if you have to. I've searched thoroughly and then finally decided to ask this one.
How do i make these two AsyncTasks independent of each other?
AsyncTasks post HoneyComb execute on a single thread:
When first introduced, AsyncTasks were executed serially on a single
background thread. Starting with DONUT, this was changed to a pool of
threads allowing multiple tasks to operate in parallel. After
HONEYCOMB, it is planned to change this back to a single thread to
avoid common application errors caused by parallel execution. If you
truly want parallel execution, you can use the
executeOnExecutor(Executor, Params...) version of this method with
THREAD_POOL_EXECUTOR; however, see commentary there for warnings on
its use.
To execute them in parallel use:
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
task.execute();
By default AsyncTask uses SERIAL_EXECUTOR i.e. if if you starts an AsyncTask it will use sDefaultExecutor see AsyncTask#execute()
#MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
In your case you need to run your thread in parallel thread pool
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params) for parallel execution
task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, params) for serial execution
task.execute() default/generally used option
runOnUiThread(new Runnable() {
#Override
public void run() {
}
});
Call your another asynctask in this method.
Related
I use AsyncTask to update list from local database(sqlite) as the following :
#Override
public void onResume() {
super.onResume();
new MyAsynctask().execute();
}
I need a clear explanation what happen every time when new MyAsynctask execute and what happen to the previous MyAsynctask that was created earlier, and if this way cost more memory?
Your new async task does nothing.
AsyncTasks are executed after each other.
Only when your old async task ends the new one will start running.
AsyncTask is just a implementation of thread to manage Background task and UI updation . AsyncTask is designed to be a helper class around Thread and Handler in android .From the documentation .
AsyncTask enables proper and easy use of the UI thread. This class allows you to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
So for your question each time you call new MyAsynctask().execute(); A new thread will starts . And the older one will run also if not finished .
To cancel previous task you can use a global instance of task and check if status is RUNNING by getStatus()
if(asyncTask!=null && asyncTask.getStatus()== AsyncTask.Status.RUNNING){
asyncTask.cancel(true);
}
In your case you create new task in onResume() so each time your activity resumes new thread will created and this is not memory efficient solution to refresh screen.
For more detail on cancel task read Section Cancelling a task and cancel(boolean).
If you know how to manage it, then it's not a memory leak.
Your AsyncTask will be executed inside the onResume() function, thus it will run when:
Every-time the Activity is (re)created
You come back from another Activity
You change screen orientantion
You come back from another Application started by an Intent
You close and re-open your App
...
You might want to keep a class field for your AsyncTask and instantiate it in onCreate():
private MyAsyncTask asyncTask;
In case the Activtyis not destroyed (points: 1, 2 (maybe), 4(maybe), 5(maybe)), you can easily check the asyncTask status and cancel it if needed.
The problem is that the old AsyncTask might still be running when you start a new one if the Activity was re-created. And since the Activity instance is new, the asyncTask reference will point to a new Object as well: in that case you will have a savage Thread running in the background.
Unless Android's OS kills Activity's owned Thread (not sure about that), you might still get away by knowing and making sure that your AsyncTask will run for a few seconds at most, without performing any blocking IO operation. But this isn't really an engineered solution.
I'd say, the best and more standard-compliant solution is: by keeping the reference to the AsyncTask in your Activity, just call asyncTask.cancel() in your onPause() method. And you'll be sure that the AsyncTask's thread will be canceled before your Activity is either paused or destroyed.
Your code will then look like this:
private MyAsyncTask asyncTask;
protected void onCreate() {
this.asyncTask = new MyAsyncTask();
}
protected void onResume() {
this.asyncTask.execute();
}
protected void onPause() {
this.asyncTask.cancel();
}
I am not writing my whole code, I have the following simple structure:
public class CreateEventActivity extends ActionBarActivity{
int x;
void onCreate(){
new AsyncTask1().execute();//here I change the value of x
Log.i("000000",String.valueOf(x));
}
public AsyncTask1 extends AsyncTask<Void, Void ,Void>{
// process include changing the vlaue of x to 4
Log.i("111111",String.valueOf(x));
}
}
in the log: the log with the tag 000000 appears before the log with tag 111111 what's going on?
First I thought the problem was because I am chainging the value of x in onPostExecute so I did so in doInBackground and the problem still the same.
what's going on?
AsyncTask is asynchronous. Quoting the documentation:
This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
The reason that you use an AsyncTask is to do work in a background thread (e.g., download some data), followed by some work on the main application thread (e.g., update the UI based upon that data).
is there anyway to avoid this?
Get rid of the AsyncTask, or learn how to use it properly. Among other things:
Do not modify the same data in multiple threads without appropriate synchronization logic
Do not try to fork a background thread, then block the main application thread (which appears to be what you want), as that eliminates the entire point of the background thread in the first place
If you have work that you want to do when doInBackground() ends, put that work in onPostExecute(), not in statements that follow your execute() or executeOnExecutor() call.
That's the nature of an Async task.
Async Tasks are mostly being used for long running operations; like webcalls, I/O operations and so on as they can take a while.
If you want to have a callback when the AsyncTask finishes you can override the OnPostExecute() method
Quick Android question... What happens when you create a new AsyncTask that replaces an existing one? For example you have a simple activity:
public class ExampleActivity extends Activity{
private MyTask myTask;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// first instance
myTask = new MyTask();
myTask.execute();
// immediately replace first instance
// assume the first instance hasn't finished yet
myTask = new MyTask();
myTask.execute();
}
}
What happens to the first instance? does it run to completion? Is it garbage collected?
Both instance will run separately upto task completetion.
When first introduced, AsyncTasks were executed serially on a single background thread.
Starting with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel.
Starting with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution.
The instance won't be garbage collected until it the task finishes. Be aware that this could cause memory leaks.
Suppose that first instance start at 0ms and end at 9 ms, then second instance at 3ms and end up at some other time so if you it will execute your code parallel in stack .
AsyncTasks run serially, meaning they run one after another. When you set myTask to another AsyncTask, that doesn't get rid of the old one you just started, you just lose the reference to it. Now the 2nd AsyncTask is going to run after the first one is finished.
According to the docs:
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
Hence the two instance will run in separate thread without linking with one another and will run until completion.
The issue is initially (in early Android OS versions) the pool size was just 1, meaning no parallel computations for a bunch of AsyncTasks. But later they fixed that and now the size is 5, so at most 5 AsyncTasks can run simultaneously.
https://github.com/vitkhudenko/test_asynctask
AsyncTask run on UI thread and they are executed serially . Yaa, you will be going to get leaks there. Try running Memory analyzer tool here, you will get to know the about the retain heap here.
You can't run execute on single instance of AsyncTask like:
myTask = new MyTask();
myTask.execute();
myTask.execute(); // Illegal
as, stated in the docs
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
ref : http://developer.android.com/reference/android/os/AsyncTask.html
but what you are trying to do is quite legal.
Is there any way on Android to know, if the thread running my code, is the UI Thread or not ? In swing there was SwingUtilities.isEventDispatchThread() to tell me if i am on the UI Thread, or not. Is there any function in the Android SDK that lets me know this ?
Answer borrowed from here: How to check if current thread is not main thread
Looper.myLooper() == Looper.getMainLooper()
Any Android app has only one UI thread, so you could somewhere in the Activity callback like onCreate() check and store its ID and later just compare that thread's ID to the stored one.
mMainThreadId = Thread.currentThread().getId();
Anyway, you can omit checking if you want to do something on the UI thread and have any reference to Activity by using
mActivity.runOnUiThread( new Runnable() {
#Override
public void run() {
...
}
});
which is guaranteed to run on current thread, if it's UI, or queued in UI thread.
Yes, there is a way.
Check the current thread object against main lopper's thread object. Main looper is always in the UI thread.
boolean isOnUiThread = Thread.currentThread() == Looper.getMainLooper().getThread();
Hum actually due to Android architecture, all Activities run in the main thread, ie the UI thread. So when you are coding an activity, everything that is in your Activity is in the UI thread.
That is why in Honeycomb an error have been added when you are making network calls in the main thread : it totally blocks the UI.
So by default you are in fact always working in the UI thread.
Another thing : unless you explicitely ask it to be in another thread, a Service will operate on the same thread as the activities of its application.
So, what to do ?
When you have to do heavy calculation in your activity; one solution is to use an AsyncTask (a class designed to allow you to easily use another thread). The code in onExecute() is run in another thread (but be cautious postExecute runs in your main thread). Another one is to manually start a new thread when AsyncTask is not really adapted.
If you create a service that does costly background tasks, make it run in another thread with the android:process=":my_process" attribute of the manifest. You will need to create an AIDL to communicate with this separated service, but it is not a complicated task.
Many objects, like for example the MediaPlayer, have Async variations of their methods. Try to to always use them.
Put a breakpoint where you want to check and, when it gets hit, check if you can interact with your UI (ie, if the UI is not frozen). If you can't interact with the UI then you are in the UI Thread, otherwise you are in a background thread.
What are the correct ways/practice/implementation/strategies (or whatever we call it as) for not to wait for code block/method to finish execution in Java?
Assume the following method:
private void myMethod()
{
// Some lines of code here
.....
.....
.....
anotherMethod(); // or this could be a code block
// Again some lines of code here
.....
.....
.....
}
In this case, I expect myMethod() should not wait for code to finish execution of anotherMethod(). I can also assure here that subsequent lines of code do not depend on anything getting executed within anotherMethod().
You can start it in another Thread if there is no dependency .
new Thread(new Runnable(){
public void run(){
anotherMethod();
}
}).start();
Use
Executor executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
#Override
public void run() {
anotherMethod();
}
});
// this is called automatically when the object is gc-ed,
// but you should not rely on this, hence the explicit call
executor.shutdown();
To quote Effective Java:
Not only should you refrain from writing your own work queues, but you
should generally refrain from working directly with threads. The key abstraction
is no longer Thread, which served as both the unit of work and the mechanism for
executing it. Now the unit of work and mechanism are separate. The key abstraction is the unit of work, which is called a task. There are two kinds of tasks: Runnable and its close cousin, Callable (which is like Runnable, except that it
returns a value). The general mechanism for executing tasks is the executor ser-
vice. If you think in terms of tasks and let an executor service execute them for
you, you gain great flexibility in terms of selecting appropriate execution policies.
In essence, the Executor Framework does for execution what the Collections
Framework did for aggregation.
Note that you'd better create your executor only once, store it in an instance field and reuse it (and shut it down afterwards)
If you are running in JavaEE 6 or spring, you can annotate your anotherMethod() with #Asynchronous and the container will start a new thread for you.
If you want to invoke the method in the same thread, then the method itself must provide an asynchronous (i.e. non-blocking) implementation. Usually this will involve returning some sort of callback such as a Future, which you can poll/query later to fetch the actual result. An example of this is the ExecutorService.submit() calls - the code you supply will be run, but in a background thread leaving you free to call other methods in the meantime.
I bolded the word invoke before, since fundamentally the only way in Java to have two things happening at once is to use multiple threads. So the method/code block/whatever will have to be executing in a background thread one way or another - usually this is handled for you in an asynchronous method by using some sort of thread pool or whatever is appropriate.
If the method doesn't provide an asynchronous interface, however, the only way to get its logic to run in another thread is to spawn that thread yourself, as org.life.java suggests.