Android AsyncTask onPostExecute off of main ui thread - android

I'm having an issue with AsyncTask and onPostExecute. I am finding that onPostExecute is executing on a different thread than the main ui thread, which is causing a CalledFromWrongThreadException to happen when I modify any views.
I put in some logging to see what threads onPreExecute, doInBackground, and onPostExecute are running on. I would see a result like this...
onPreExecute ThreadId: 1
doInBackground ThreadId: 25
onPostExecute ThreadId: 18
I believe the main ui thread id is 1 and I would expect both onPre and onPost to both execute on thread 1. I am making sure to create and also call the execute method from the ui thread (for example in onCreate of an Activity).
Another thing to note that I have noticed is that later async tasks will run their onPostExecute method on the same thread as previous async task onPostExecute methods (in this case thread 18).
Right now in order to get around this I am wrapping the code in my onPostExecute methods in a call to runOnUiThread, but I think this is hacky and would like to get to the real issue.
I am out of ideas! Any one have any insight? I'm happy to answer any questions that could helper with further investigation!
EDIT:
There are two ways that async tasks are being run in the code. I am wondering if the latter in these examples is causing something weird to happen?
public class SomeActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
new SomeAsyncTask().execute();
}
private class SomeAsyncTask extends AsyncTask<String, Void, Integer> {
#Override
public void onPreExecute() {
Thread.currentThread().getId() // 1
//Show a dialog
}
#Override
public Integer doInBackground(String... params) {
Thread.currentThread().getId() // 25
return 0;
}
#Override
public void onPostExecute(Integer result) {
Thread.currentThread().getId() // 18
//hide dialog
//update text view -> CalledFromWrongThreadException!!!
}
}
}
The above seems like a vanilla use of AsyncTask, but I still see this issue occurring even in simple cases like this. The next example uses an async task to run other async tasks. Maybe there is something I don't know about what happens when an async task gets constructed that is causing some weird behavior?
public class SomeActivity extends Activity implements TaskRunner.OnFinishListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
TaskRunner taskRunner = new TaskRunner();
taskRunner.setOnFinishListener(this);
taskRunner.addTask(new SingleTask());
taskRunner.addTask(new SingleTask());
taskRunner.execute();
}
#Override
public void onTaskFinish(List<Integer> results) {
//Thread id is 18 when it should be 1
//do something to a view - CalledFromWrongThreadException!!
}
}
//In a different file
public class SingleTask extends AsyncTask<String, Void, Integer> {
//This is a an async task so we can run it separately as an asynctask
//Or run it on whatever thread runnerExecute is called on
#Override
public Integer doInBackground(String... params) {
return runnerExecute(params);
}
//Can be called outside of doInBackground
public Integer runnerExecute(String... params) {
//some long running task
return 0;
}
}
//In a different file
public class TaskRunner {
private List<SingleTask> tasks;
private OnFinishListener onFinishListener;
public interface OnFinishListener {
public void onTaskFinish(List<Integer> results);
}
public TaskRunner() {
this.tasks = new ArrayList<SingleTask>();
}
public void setOnFinishListener(OnFinishListener listener) {
this.onFinishListener = listener;
}
public void addTask(SingleTask task) {
tasks.add(task);
}
public void executeTasks() {
new RunnerTask().execute((SingleTask[]) tasks.toArray());
}
//Calls the runnerExecute method on each SingleTask
private class RunnerTask extends AsyncTask<SingleTask, Integer, List<Integer>> {
#Override
public void onPreExecute() {
//Runs on thread 1
}
#Override
public List<Integer> doInBackground(SingleTask... params) {
//Runs on arbitrary thread
List<Integer> results = new ArrayList<Integer>();
for(SingleTask task : params) {
int result =task.runnerExecute(task.getParams());
results.add(result);
}
return results;
}
#Override
public void onPostExecute(List<Integer> results) {
//Runs on thread 18
onFinishListener.onTaskFinish(results);
}
}
}
Maybe what is going on here is just super weird, and not at all how async tasks are meant to be used, either way it would be nice to get to the bottom of the issue.
Let me know if you need any more context.

I have been experiencing the same problem and it turned out the the issue was using Flurry 3.2.1. However, the issue is not limited to the Flurry library.
The issue behind the scenes is having the first ever (when the app is loaded for the first time) AsyncTask call from a looper thread which is not the Main UI thread. This call initializes a sHandler static variable in AsyncTask to the wrong thread id, and this id is then used in all subsequent AsyncTask$onPostExecute() calls.
To solve the problem, I call an empty (do-nothing) AsyncTask on first app load, just to initialize AsyncTask correctly.

try using:
getBaseContext().runOnUiThread(new Runnable()
{
#override
public void run()
{
}
});
and write your code inside the run function

The AsyncTask is designed to be used from the main thread. Your problem is the second case, and is that you call execute on the SingleTask from a background thread. You call it in the doInBackground method of RunnerTask. The onPostExecute is then run from the backgroundthread of RunnerTask
Two options for you.
1: Trash RunnerTask, and execute the SingleTasks from you main thread, they'll all run in parallell and you won't know which finishes first, but onPreExecute and onPostExecute is called on the main thread
2: Trash the SingleTask and define them as Runnables instead, then you can run them in sequence in the RunnerTask's doInBackground. They'll all run in the background thread of RunnerTask, in the order you call Run. When it is finished, the onPostExecute of RunnerTask is run on the main thread.

i just tried your code and onPreExecute and onPostExecute does run on the same thread, how do you output the thread id ? try:
Log.d("THREADTEST","PRE"+Long.toString(Thread.currentThread().getId()));
Log.d("THREADTEST","BACKGROUND"+Long.toString(Thread.currentThread().getId()));
Log.d("THREADTEST","POST"+Long.toString(Thread.currentThread().getId()));
P.S. it should be:
new SomeAsyncTask().execute();
and
private class SomeAsyncTask extends AsyncTask<String, Void, Integer> { ... }

you are actually executing the SingleTask from RunnerTask's doinbackground method which is incorrect as asynctask should be executed from a main thread only. You need to relook into the logic which runs the set of SingleTasks from RunnerTask.

Related

Can't touch views from onPostExecute's AsyncTask

I have already read all questions about this. And it's not the same case. Believe me.
I know an AsyncTask doInBackground function has his own thread, and you must touch the view in onPreExecute and onPostExecute.
Besides, I'm using isCancelled and isFinishing to really be sure the task is alive. And with all these things, the app is still crashing.
This is the code:
public class MainActivity {
private Activity activity;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.Main);
activity = this;
new MyTask(activity).execute();
}
private class MyTask extends AsyncTask<Void, Void, User[]> {
// ...
#Override
protected void onPreExecute() {
}
#Override
protected User[] doInBackground(String... params) {
// Api call
// return results
}
#Override
protected void onPostExecute(User[] users) {
if (isCancelled() || isFinishing()) return;
findViewById(R.id.panelViews).removeAllViews();
findViewById(R.id.element).setText("something");
// ... more
}
}
}
As you can see:
the touch of the view is in the onPostExecute
I use the "isCancelled" in case the user cancels the task exiting the screen
The same with "isFinishing"
And even now I'm getting the error "Only the original thread that created a view hierarchy can touch its views" in the line when I try to change something of the view (in the example a simple text)
If I cancel (pressing back for example) when it's trying to get the API results is OK, and it works.
If I cancel exactly when the API results come, and before it starts changing things, it crashes (I inserted a "sleep" in the onPostExecute to accomplish this test).
The error code is in line 112, that is the "findViewById(R.id.panelViews).removeAllViews();" described above:
android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRoot.checkThread(ViewRoot.java:2988)
at android.view.ViewRoot.requestLayout(ViewRoot.java:648)
at android.view.View.requestLayout(View.java:8416)
at android.view.View.requestLayout(View.java:8416)
at android.view.View.requestLayout(View.java:8416)
at android.view.View.requestLayout(View.java:8416)
at android.view.View.requestLayout(View.java:8416)
at android.widget.ScrollView.requestLayout(ScrollView.java:1303)
at android.view.View.requestLayout(View.java:8416)
at android.view.View.requestLayout(View.java:8416)
at android.view.ViewGroup.removeAllViews(ViewGroup.java:2354)
at com.test.activities.MainActivity$MyTask.onPostExecute(MainActivity.java:112)
at com.test.activities.MainActivity$MyTask.onPostExecute(MainActivity.java:1)
at android.os.AsyncTask.finish(AsyncTask.java:417)
at android.os.AsyncTask.access$300(AsyncTask.java:127)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:130)
at android.os.HandlerThread.run(HandlerThread.java:60)
Looking at the call stack, following call indicates that AsyncTask class was loaded on non-UI thread.
at android.os.HandlerThread.run(HandlerThread.java:60)
One of the Threading Rules mentioned in AsyncTask reference documentation is:
The AsyncTask class must be loaded on the UI thread. This is done
automatically as of JELLY_BEAN.
Here is a bug related to this issue.
One of the solution is, load the AsyncTask class manually in Application onCreate method. This ensures the class gets loaded on main thread, before any application components uses it.
public class MyApplication extends Application {
#Override
public void onCreate() {
try {
Class.forName("android.os.AsyncTask");
} catch (ClassNotFoundException e) {
}
super.onCreate();
}
}
Remember to specify MyApplication in AndroidManifest file.
The solution in this answer should force the code to be run on the ui thread. It uses the Activity#runOnUiThread(Runnable) function. Your code would end up like this:
#Override
protected void onPostExecute(User[] users) {
if (isCancelled() || isFinishing()) return;
runOnUiThread(new Runnable() {
#Override
public void run() {
findViewById(R.id.panelViews).removeAllViews();
findViewById(R.id.element).setText("something");
// ... more
}
});
}
This occurs when you start an AsyncTask from a background thread. The onPreExecute and onPostExecute don't automatically run on the main thread but in reality the thread the AsyncTask was started from.
In other words, if you were already within a background thread when you called execute on the AsyncTask then that same thread is where the onPostExecute method is called from meaning you would get that exception.
Try this, This should solve your problem, perform your task in runOnUiThread()
#Override
protected void onPostExecute(User[] users) {
runOnUiThread(new Runnable() {
public void run() {
if (isCancelled() || isFinishing()) return;
findViewById(R.id.panelViews).removeAllViews();
findViewById(R.id.element).setText("something");
}//run
}//runOnUiThread
}//onPostExecute

Thread is stopping until the execution of a method is complete. (Android)

I'm trying to do an Android game using a Thread which repeats a loop for draw, move and others.
I have a problem with the execution of a method, which searches a value with a "do while" loop. When this method is executed, the thread does not continue until this process does not end.
What would be the best option for avoid this? Make another thread within that method? If you can give an example I'd really appreciate it.
Here's some pseudocode:
void mainLoop(){
drawElements();
moveElements();
//...
//...
reposition();
}
void reposition(){
// this stops my thread
do{
// do stuff
}while(!end);
// do stuff
}
As wqrahd suggested use AsyncTask.
I assume mainLoop is a main UI thread.
public class RepositionClass extends AsyncTask {
private Context mContext;
public RepositionClass(Context context) {
mContext = context;
}
#Override
protected void onPreExecute() {
// do UI related here, this function will run in main thread context.
}
#Override
protected Boolean doInBackground(String... params) {
// call non-ui(computation intensive) part of reposition function here.
return true;
}
#Override
protected void onPostExecute(Boolean result) {
// do UI related part of reposition function here.
}
}
Creating another thread won't help you if you still have to block and wait for the loop to complete the search. The problem really is what is happening in the "do stuff" loop, you just need to optimize that to solve the issue.
use asyntask and in asyntask's doInBackground , do your thread work and in asyntask's onPostExecute call your repositionMethod.

AsyncTask not call doInBackground methods

Here is my code:
new Loading.LoadTast(ctx) {
#Override
protected String doInBackground(Integer... params) {
Looper.prepare();
String msg=changePwd();
closeProgressDialog();
if(msg == null) {
SmartNgApplication.getInstance().exit();
} else {
BaseHelper.showToast(ctx, msg);
}
Looper.loop();
return null;
}
}.execute();
public abstract static class LoadTast extends AsyncTask<Integer, Integer, String> {
private ProgressDialog progressDialog;
private Context ctx;
public LoadTast(Context ctx) {
this.ctx=ctx;
}
protected abstract String doInBackground(Integer... params);
public void onPreExecute() {
super.onPreExecute();
progressDialog=ProgressDialog.show(ctx, "", "loading...", true, false);
}
public void onPostExecute(String result) {
super.onPostExecute(result);
progressDialog.dismiss();
BaseHelper.showToast(ctx, result);
}
}
Click the button to run the method. Clicking it 5 times AsyncTask.onPreExecute is called but not call doInBackground so the screen still show a dialog.
I think have something wrong for AsyncTask THREAD_POOL_EXECUTOR
You should not call any UI changing methods in doInBackground. Thats what onPostExecute is there for. Do only whats not allowed on the UI thread in doInBackground.
To check why doInBackground is not called, please try putting the implementation (from the anonymous inner class) into LoadTast just too see if it is called then.
I have implemented an AsyncWrapper by having subclasses call renamed onPostExecute and doInBackground. It should be possible to overwrite the wrapped Methods in an anonymous inner class like the one you are using in your example.
This is the short version. My real code involves some genral exception handling not only the call to the wrapped methods.
public abstract class AsyncTaskWrapper<Params, Progress, Result>
extends AsyncTask<Params, Progress, Result> {
#Override
final protected Result doInBackground(Params... params) {
return wrappedDoInBackground(params);
}
protected abstract Result wrappedDoInBackground(Params... params);
protected abstract void wrappedOnPostExecute(Result result);
final protected void onPostExecute(Result result) {
wrappedOnPostExecute(result);
}
}
As Todd Sjolander said in this thread ...
The multi-threading model changed between 2.3.5 and 4.0.4. AsyncTask
now defaults to having all subclasses in an application using the same
thread (i.e. only one AsyncTask can run at a time!). It's explained
here:
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.
If you truly want parallel execution, you can invoke
executeOnExecutor(java.util.concurrent.Executor, Object[]) with
THREAD_POOL_EXECUTOR.
With that in mind, it could be that another AsyncTask is running in
your app, thereby preventing this one from ever starting. That would
explain why it works fine on your 2.3.5 device, but not your 4.0.4
tablet.

AsyncTask cannot work in thread android

I use AsyncTask to change text of TextView like this:
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String response = "";
for (String url : urls) {
response += url;
}
return response;
}
#Override
protected void onPostExecute(String result) {
textView.setText(result);
}
}
Everything will fine if I call it in OnClick event:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
textView = (TextView) findViewById(R.id.txt);
Button button = (Button)this.findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
new LongOperation().execute(new String[]{"Hello"});
}
});
}
But the problem when I called it in my thread, the program forced close
this.closeButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Thread t= new Thread(){
#Override
public void run(){
try{
//Do something
//Then call AsyncTask
new LongOperation().execute(new String[]{"Hello"});
}catch(Exception e){}
}
};
t.start();
}
});
Where am I wrong? I dont' understand how difference call AsyncTask in thread or not.
I recommend you consult the AsyncTask documentation and Processes and Threads for a better understanding of how it works. Essentially, you should create your AsyncTask subclass on the main thread.
When you call AsyncTask.execute(), your provided, AsyncTask.onPreExecute is called on the main thread, so you can do UI setup.
Next AsyncTask.doInBackground method is called, and runs in its own thread.
Finally, when your AsyncTask.doInBackground method completes, a call is made to AsyncTask.onPostExecute on the main thread, and you can do any UI cleanup.
If you need to update the UI from within your AsyncTask.doInBackground method, call AsyncTask.publishProgress, which will invoke onProgressUpdate in the main thread.
When you call it from the UI thread, the associated Context is the running Activity. When you call it from a regular thread, there is no valid Context associated with that thread. AsyncTask executes in its own thread, you shouldn't be creating its own thread. If that is actual code, then you have missunderstood the point of AsyncTask. Search for tutorials on how to use it.
Adding to what the others have said: I think you can use AsyncTask to launch off a task in another thread, even if you start the AsyncTask from a different thread than the UI already.
But in that case, the only way you'll only be able to modify the UI indirectly, for example: pass the handler of the current Activity somehow to this AsyncTask instance, and send messages to it (handler messages get processed on the UI thread). Or use broadcast intents that the Activity catches and updates the UI accordingly, etc. These solutions seem to be overkills though.

use of asynctask inside asynctask

I wanted to use AsyncTask to load images to the ListView.
private class LoadImageTask extends AsyncTask<HashMap<String,Bitmap>,Void,Bitmap>{
#SuppressWarnings("unchecked")
#Override
protected void onPostExecute(Bitmap result) {
if(model.getIconCache().get(cellIcon)!=null){
icon.setImageBitmap(model.getIconCache().get(cellIcon));
}else{
new LoadImageTask().execute(model.getIconCache());
}
}
#Override
protected Bitmap doInBackground(HashMap<String, Bitmap>... params) {
//return model.getIconCache().get(cellIcon);
return null;
}
}
Ok, I know that this not an affective code. However it works well but with a lot of memory allocation. When reading the documentation about AsyncTask it said that Asynctask can be called only from UI thread, how could it let to use inside itself? And of course I want to make my code work inside a single AsyncTask. "model" in the code is an object that is updated at runtime through another thread. So I need to find a way to use a single Asynctask with periodically control the state of an object. How do I do that? Thanks
only do in backGround runs on backGround thread and postExecute and preExecute run on UI thread itself.. For the same reason u can show and dismiss dialogs in it..
if u want to use single Asynctask for multiple purpose u can play around by passing Different constants.. in .execute() method..
I mean something like this.
Integer Constant1 = 1;
int Constant2 = 2;
and while calling,,
new Background.execute(Constan1 or 2)
and in AsyncTask
doInBackground(Object.. arg0)
{
if(arg0.equals())
{
}
else if(arg0.equals())
{
}
}
Take a look at the asynctask documentation: http://developer.android.com/reference/android/os/AsyncTask.html
private class MyTask extends AsyncTask<Void, Integer, Boolean> {
protected Boolean doInBackground(Void...) {
int i = 0;
while(true){
publishProgress(i++);
}
}
protected void onProgressUpdate(Integer... progress) {
myObject.setState(progress[0]);
}
}
You do your background stuff in the doInBackground method (which runs in the background thread).
You control the state of your object in the onProgressUpdate (which runs on the ui thread)
You send messages between the background thread and the ui thread using publishProgress. These messages could contain the state of your object.

Categories

Resources