Why this code runs without error? I am updating UI from doInBackground of AsyncTask

Related searches

I was experimenting with the AsyncTask and found an unusual scenario, here is my code.

class MainActivity : AppCompatActivity() {
    lateinit var textView:TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        textView = findViewById(R.id.textView)
        val task = MyAsyncTask()
        task.execute()
    }

    inner class MyAsyncTask:AsyncTask<Void,Void,String>() {
        override fun doInBackground(vararg params: Void?): String {
            //Thread.sleep(3000)
            textView.text ="From AsyncTask"
            return "hello"
        }
    }
}

It worked!!, see the Thread.sleep is commented but if I uncomment it then the usual error what we know

Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

Why is so, if anybody know please share your feedback. Thanks

It's about the timing. When you comment Thread.sleep(3000), your view is not ready and connected with your activity, thus this version of code just updates a view that is yet to exist in UI.

However, after some time passes, UI would be started and when you update your view in doInBackground(), you will receive the exception that states Only the original thread that created a view hierarchy can touch its views. This also justifies the exception you got when you uncomment Thread.sleep(3000)

AsyncTask, Error � LocaleDisplayNames. AsyncTask was intended to enable proper and easy use of the UI called onPreExecute , doInBackground , onProgressUpdate and that all callback calls are synchronized to ensure the following without continues to run, and care needs to be taken that later updates in� You are using AsyncTask but in doInBackground you are calling // updating UI from Background Thread runOnUiThread(new Runnable() { public void run() { In these strings you run all next code from doInBackground in main UI thread and it removes all AsyncTask effect. Than you run

because when you're calling Thread.sleep in the following code:

inner class MyAsyncTask:AsyncTask<Void,Void,String>() {
    override fun doInBackground(vararg params: Void?): String {

        Thread.sleep(3000)
        textView.text ="From AsyncTask"
        ...
    }
}

it will run on current thread, which is a background thread of AsyncTask. You can see that in the Thread.sleep documentation:

public static void sleep (long millis, int nanos)

Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds plus the specified number of nanoseconds, subject to the precision and accuracy of system timers and schedulers. The thread does not lose ownership of any monitors.

So, the next code will switch to the background thread too:

textView.text ="From AsyncTask"

which will raise the exception.

Better performance through threading, Nearly any block of code your app executes is tied to an event callback, inner class MyAsyncTask : AsyncTask<Unit, Unit, String>() { This approach can be tedious and error prone, however. If the blocks were going to update a UI that no longer exists, there's no reason for the Was this page helpful? Well, I think the problem is because “Service runs in main thread so when it runs, it blocks my AsyncTask to run”… So I think If we can run Service in background thread then that can help . Thats why I tried IntentService for running service in separate thread but I am in doubt… if IntentService can run for indefinite time similar to

When you comment-out Thread.sleep(3000), your app still runs without crashing because at that time, the textView is not visible on screen yet. To make sure the textView is visible on screen you can use addOnGlobalLayoutListener. Now your app is always crashes no matter you comment-out Thread.sleep(3000) or not.

class MainActivity : AppCompatActivity() {
    lateinit var textView: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        textView = findViewById(R.id.textView)

        textView.viewTreeObserver.addOnGlobalLayoutListener {
            // This view is visible on screen
            val task = MyAsyncTask()
            task.execute()
        }
    }

    inner class MyAsyncTask : AsyncTask<Void, Void, String>() {
        override fun doInBackground(vararg params: Void?): String {
            // Thread.sleep(3000)
            textView.text = "From AsyncTask From AsyncTask From AsyncTask"
            return "hello"
        }
    }
}

On the other hand, when you do not comment-out Thread.sleep(3000), your app immediately crashes after 3 seconds because at that time, the textView is already visible on screen, that why your app crash.

So where does this exception come from. Take a look at ViewRootImpl source code

@Override
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        checkThread();
        mLayoutRequested = true;
        scheduleTraversals();
    }
}

void checkThread() {
    if (mThread != Thread.currentThread()) {
        throw new CalledFromWrongThreadException(
                "Only the original thread that created a view hierarchy can touch its views.");
    }
}

From this link

requestLayout()

If something about your view changes that will affect the size, then you should call requestLayout(). This will trigger onMeasure and onLayout not only for this view but all the way up the line for the parent views.

When you update text for the textView, its size will changed, that why requestLayout is called, as a result, it will call checkThread and throw CalledFromWrongThreadException.

AsyncTask | J2ObjC, AsyncTask enables proper and easy use of the UI thread. results on the UI thread without having to manipulate threads and/or handlers. Starting with DONUT, this was changed to a pool of threads allowing Runs on the UI thread after doInBackground(Params. to publish updates on the UI thread. * The doInBackground() method runs on a background thread, so it can run long-running code * (like network activity), without interfering with the responsiveness of the app. * Then onPostExecute() is passed the result of doInBackground() method, but runs on the * UI thread, so it can use the produced data to update the UI. */

As the exception clearly says :

Only the original thread that created a view hierarchy can touch its views.

AsyncTask doInBackground runs in separate background thread which don't have nothing to do with Main Thread now all the UI related work should be done on Main thread so rather then settext on doInBackground do it in onpostexecute.

Android AsyncTask Example Tutorial, package com.journaldev.asynctask; import android.app. protected String doInBackground(String void onPostExecute(String result) { // execution of In the above code we've used AsyncTaskRunner I got this error when I used your code for updating an� I am using an ArrayAdapter to display a list of items, and I have an AsyncTask thread that loads these items via HttpURLConnection. I want this list of items to be the first thing the user sees on launching the app. I know that it is bad practice to have the app wait on launch for this load to complete, which is why I made the load an AsyncTask.

My Android AsyncTask docs and examples (parameters, callbacks , probably get the dreaded, “Application Not Responding” (ANR) error. (No good developer wants an ANR.) AsyncTask creates a background thread for you, and runs the code in is run after doInBackground , and it's run on the main/ui thread, so you (this is the correct way to update ui components.). android,user-interface,android-asynctask I am using AsyncTask to do a background task. The task is in a while loop. The task is in a while loop. How can I update my UI as on post execute dose not work if the background task is still running.

I am facing a problem with my HCL Me U1 tablet. Suddenly it started to give this error: “Unfortunately, the System UI has Stopped”. I have trying formatting the tab. Even wiping the internal storage and factory reset. Still doesn’t work. Last app installed was whatsapp. Android Version: 4.0.3 Help.

Note that onProgressView() is called repeatedly as your AsyncTask runs. Therefore, it should be kept as short as possible. This also means that your current code is creating lots of views and adding them to the UI. Instead, you should add the view just once and then update its data in onProgressView().

Comments
  • you are out of context of Main/ UI thread. When you initialize your task, pass Caller's context in the object initialization too
  • Guys, run the added code (exact code) and give your feedback. please read the question carefully. Thanks
  • changes on UI thread are not allowed in doInBackround(), use preExecute or postExecute for that.
  • don't you think, if the view is not present it will throw null pointer exception? I think view is already created in the onCreate().
  • No. Actually, view is created but it's not binded to UI yet, so it assumes the view is created by background thread(AsynTask in this case) rather than UI thread.
  • when the Thread.sleep is commented, what is happening then , why is it working?
  • that is because textView still attached to UI thread when you're using inner class.