Android "Only the original thread that created a view hierarchy can touch its views."
Asked Answered
W

35

1202

I've built a simple music player in Android. The view for each song contains a SeekBar, implemented like this:

public class Song extends Activity implements OnClickListener,Runnable {
    private SeekBar progress;
    private MediaPlayer mp;

    // ...

    private ServiceConnection onService = new ServiceConnection() {
          public void onServiceConnected(ComponentName className,
            IBinder rawBinder) {
              appService = ((MPService.LocalBinder)rawBinder).getService(); // service that handles the MediaPlayer
              progress.setVisibility(SeekBar.VISIBLE);
              progress.setProgress(0);
              mp = appService.getMP();
              appService.playSong(title);
              progress.setMax(mp.getDuration());
              new Thread(Song.this).start();
          }
          public void onServiceDisconnected(ComponentName classname) {
              appService = null;
          }
    };

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.song);

        // ...

        progress = (SeekBar) findViewById(R.id.progress);

        // ...
    }

    public void run() {
    int pos = 0;
    int total = mp.getDuration();
    while (mp != null && pos<total) {
        try {
            Thread.sleep(1000);
            pos = appService.getSongPosition();
        } catch (InterruptedException e) {
            return;
        } catch (Exception e) {
            return;
        }
        progress.setProgress(pos);
    }
}

This works fine. Now I want a timer counting the seconds/minutes of the progress of the song. So I put a TextView in the layout, get it with findViewById() in onCreate(), and put this in run() after progress.setProgress(pos):

String time = String.format("%d:%d",
            TimeUnit.MILLISECONDS.toMinutes(pos),
            TimeUnit.MILLISECONDS.toSeconds(pos),
            TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(
                    pos))
            );
currentTime.setText(time);  // currentTime = (TextView) findViewById(R.id.current_time);

But that last line gives me the exception:

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

Yet I'm doing basically the same thing here as I'm doing with the SeekBar - creating the view in onCreate, then touching it in run() - and it doesn't give me this complaint.

Wu answered 2/3, 2011 at 0:7 Comment(2)
In kotlin Add the code inside runOnUiThread { }Exosmosis
I don't understand why their behaviors are different? Did you declared the TextView as a global variable? If so, why does the SeekBar work but the TextView doesn't? No one answered this question.Antifederalist
P
2291

You have to move the portion of the background task that updates the UI onto the main thread. There is a simple piece of code for this:

runOnUiThread(new Runnable() {

    @Override
    public void run() {

        // Stuff that updates the UI

    }
});

Documentation for Activity.runOnUiThread.

Just nest this inside the method that is running in the background, and then copy paste the code that implements any updates in the middle of the block. Include only the smallest amount of code possible, otherwise you start to defeat the purpose of the background thread.

Panarabism answered 2/3, 2011 at 0:29 Comment(10)
worked like a charm. for me the only problem here is that I wanted to do an error.setText(res.toString()); inside the run() method, but I couldn't use the res because it wasn't final.. too badBraun
One brief comment on this. I had a separate thread that was trying to modify the UI, and the above code worked, but I had call runOnUiThread from the Activity object. I had to do something like myActivityObject.runOnUiThread(etc)Dowzall
@Dowzall Thank you for this reference. You can simply do 'MainActivity.this' and it should work as well so you don't have to keep reference to your activity class.Castor
It took me a while to figure out that runOnUiThread() is a method of Activity. I was running my code in a fragment. I ended up doing getActivity().runOnUiThread(etc) and it worked. Fantastic!;Chronister
Can we stop the task being performed that is written in the body of 'runOnUiThread' method ?Idaliaidalina
I was using runOnUiThread() and still getting the error. Then I found I was updating an UI element in runOnUiThread(). Removed the update portion and added mechanism to update that UI element later - fixed my problem.Tempe
This fixed 2 of my problems. 1) the same as in the question 2) a ListView not actually updating when calling adapter.notifyDataSetChanged(). Also, I got to up vote this answer to 1667. My OCD says this is a good thing, but I can't even remember why... :-)Irenairene
Simple and effective solution for your use case is runOnUiThread / handlerIncomprehensible
Thank you! I ran into this when using a ProgressDialog. It launched and did everything fine but would crash when trying to update the progress in onProgressUpdate. Wrapping this in runOnUiThread fixed it. Thanks again!Spider
This might help for new comers..https://mcmap.net/q/14511/-running-code-in-main-thread-from-another-threadBungle
H
162

I solved this by putting runOnUiThread( new Runnable(){ .. inside run():

thread = new Thread(){
        @Override
        public void run() {
            try {
                synchronized (this) {
                    wait(5000);

                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            dbloadingInfo.setVisibility(View.VISIBLE);
                            bar.setVisibility(View.INVISIBLE);
                            loadingText.setVisibility(View.INVISIBLE);
                        }
                    });

                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Intent mainActivity = new Intent(getApplicationContext(),MainActivity.class);
            startActivity(mainActivity);
        };
    };  
    thread.start();
Hypnotize answered 1/1, 2013 at 21:50 Comment(5)
This one rocked. Thanks for information that, this can also be used inside any other thread.Forerunner
Thank you, it's really sad to create a thread in order to go back to the UI Thread but only this solution saved my case.Maelstrom
One important aspect is that wait(5000); isn't inside the Runnable, otherwise your UI will freeze during the wait period. You should consider using AsyncTask instead of Thread for operations like these.Pasteurizer
this is so bad for memory leakJimenez
Why bother with the synchronized block? The code inside it looks reasonably thread safe (although I'm fully prepared to eat my words).Airiness
B
89

My solution to this:

private void setText(final TextView text,final String value){
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            text.setText(value);
        }
    });
}

Call this method on a background thread.

Boodle answered 25/8, 2014 at 14:34 Comment(2)
Error:(73, 67) error: non-static method set(String) cannot be referenced from a static contextRiptide
I have the same issue with my test classes. This worked like a charm for me. However, replacing runOnUiThread with runTestOnUiThread. ThanksHackbut
H
50

Kotlin coroutines can make your code more concise and readable like this:

MainScope().launch {
    withContext(Dispatchers.Default) {
        //TODO("Background processing...")
    }
    TODO("Update UI here!")
}

Or vice versa:

GlobalScope.launch {
    //TODO("Background processing...")
    withContext(Dispatchers.Main) {
        // TODO("Update UI here!")
    }
    TODO("Continue background processing...")
}

Update 2023/06:

Consider carefully when using GlobalScope. If possible, create a new scope so you are able to cancel it, for ex.:

val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
Hibachi answered 7/1, 2020 at 9:6 Comment(3)
Perfect! Thank you!Swish
Thank you so much for saving my dayGudren
Thanks for saving my time.Diagraph
P
34

Usually, any action involving the user interface must be done in the main or UI thread, that is the one in which onCreate() and event handling are executed. One way to be sure of that is using runOnUiThread(), another is using Handlers.

ProgressBar.setProgress() has a mechanism for which it will always execute on the main thread, so that's why it worked.

See Painless Threading.

Pekoe answered 2/3, 2011 at 0:29 Comment(1)
The Painless Threading article at that link is now a 404. Here is a link to an (older?) blog piece on Painless Threading - android-developers.blogspot.com/2009/05/painless-threading.htmlChromatid
B
27

You can use Handler to Delete View without disturbing the main UI Thread. Here is example code

new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
          //do stuff like remove view etc
          adapter.remove(selecteditem);
          }
    });
Bellda answered 27/6, 2018 at 9:2 Comment(0)
C
27

Kotlin Answer

We have to use UI Thread for the job with true way. We can use UI Thread in Kotlin, such as:

runOnUiThread(Runnable {
   //TODO: Your job is here..!
})
Capuano answered 4/3, 2020 at 16:13 Comment(0)
A
22

I've been in this situation, but I found a solution with the Handler Object.

In my case, I want to update a ProgressDialog with the observer pattern. My view implements observer and overrides the update method.

So, my main thread create the view and another thread call the update method that update the ProgressDialop and....:

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

It's possible to solve the problem with the Handler Object.

Below, different parts of my code:

public class ViewExecution extends Activity implements Observer{

    static final int PROGRESS_DIALOG = 0;
    ProgressDialog progressDialog;
    int currentNumber;

    public void onCreate(Bundle savedInstanceState) {

        currentNumber = 0;
        final Button launchPolicyButton =  ((Button) this.findViewById(R.id.launchButton));
        launchPolicyButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                showDialog(PROGRESS_DIALOG);
            }
        });
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        switch(id) {
        case PROGRESS_DIALOG:
            progressDialog = new ProgressDialog(this);
            progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            progressDialog.setMessage("Loading");
            progressDialog.setCancelable(true);
            return progressDialog;
        default:
            return null;
        }
    }

    @Override
    protected void onPrepareDialog(int id, Dialog dialog) {
        switch(id) {
        case PROGRESS_DIALOG:
            progressDialog.setProgress(0);
        }

    }

    // Define the Handler that receives messages from the thread and update the progress
    final Handler handler = new Handler() {
        public void handleMessage(Message msg) {
            int current = msg.arg1;
            progressDialog.setProgress(current);
            if (current >= 100){
                removeDialog (PROGRESS_DIALOG);
            }
        }
    };

    // The method called by the observer (the second thread)
    @Override
    public void update(Observable obs, Object arg1) {

        Message msg = handler.obtainMessage();
        msg.arg1 = ++currentPluginNumber;
        handler.sendMessage(msg);
    }
}

This explanation can be found on this page, and you must read the "Example ProgressDialog with a second thread".

Arsphenamine answered 7/4, 2011 at 12:3 Comment(0)
S
8

I see that you have accepted @providence's answer. Just in case, you can also use the handler too! First, do the int fields.

    private static final int SHOW_LOG = 1;
    private static final int HIDE_LOG = 0;

Next, make a handler instance as a field.

    //TODO __________[ Handler ]__________
    @SuppressLint("HandlerLeak")
    protected Handler handler = new Handler()
    {
        @Override
        public void handleMessage(Message msg)
        {
            // Put code here...

            // Set a switch statement to toggle it on or off.
            switch(msg.what)
            {
            case SHOW_LOG:
            {
                ads.setVisibility(View.VISIBLE);
                break;
            }
            case HIDE_LOG:
            {
                ads.setVisibility(View.GONE);
                break;
            }
            }
        }
    };

Make a method.

//TODO __________[ Callbacks ]__________
@Override
public void showHandler(boolean show)
{
    handler.sendEmptyMessage(show ? SHOW_LOG : HIDE_LOG);
}

Finally, put this at onCreate() method.

showHandler(true);
Saharanpur answered 20/5, 2013 at 6:55 Comment(0)
E
8

I had a similar issue, and my solution is ugly, but it works:

void showCode() {
    hideRegisterMessage(); // Hides view 
    final Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            showRegisterMessage(); // Shows view
        }
    }, 3000); // After 3 seconds
}
Ephah answered 14/9, 2015 at 14:17 Comment(1)
@R.jzadeh it's nice to hear that. Since the moment I did wrote that answer, probably now you can do it better :)Goodrow
L
8

Use this code, and no need to runOnUiThread function:

private Handler handler;
private Runnable handlerTask;

void StartTimer(){
    handler = new Handler();   
    handlerTask = new Runnable()
    {
        @Override 
        public void run() { 
            // do something  
            textView.setText("some text");
            handler.postDelayed(handlerTask, 1000);    
        }
    };
    handlerTask.run();
}
Lindalindahl answered 24/7, 2016 at 20:6 Comment(0)
E
8

I was facing a similar problem and none of the methods mentioned above worked for me. In the end, this did the trick for me:

Device.BeginInvokeOnMainThread(() =>
    {
        myMethod();
    });

I found this gem here.

Emotional answered 19/11, 2018 at 16:6 Comment(0)
P
7

I use Handler with Looper.getMainLooper(). It worked fine for me.

    Handler handler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
              // Any UI task, example
              textView.setText("your text");
        }
    };
    handler.sendEmptyMessage(1);
Puling answered 5/4, 2017 at 15:25 Comment(0)
G
7

This is explicitly throwing an error. It says whichever thread created a view, only that can touch its views. It is because the created view is inside that thread's space. The view creation (GUI) happens in the UI (main) thread. So, you always use the UI thread to access those methods.

Enter image description here

In the above picture, the progress variable is inside the space of the UI thread. So, only the UI thread can access this variable. Here, you're accessing progress via new Thread(), and that's why you got an error.

Grimbald answered 5/8, 2017 at 2:4 Comment(0)
B
7

For a one-liner version of the runOnUiThread() approach, you can use a lambda function, i.e.:

runOnUiThread(() -> doStuff(Object, myValue));

where doStuff() can represents some method used to modify the value of some UI Object (setting text, changing colors, etc.).

I find this to be much neater when trying to update several UI objects without the need for a 6 line Runnable definition at each as mentioned in the most upvoted answer, which is by no means incorrect, it just takes up a lot more space and I find to be less readable.

So this:

runOnUiThread(new Runnable() {
    @Override
    public void run() {
        doStuff(myTextView, "myNewText");
    }
});

can become this:

runOnUiThread(() -> doStuff(myTextView, "myNewText"));

where the definition of doStuff lies elsewhere.

Or if you don't need to be so generalizable, and just need to set the text of a TextView object:

runOnUiThread(() -> myTextView.setText("myNewText"));
Bookcraft answered 25/5, 2021 at 6:23 Comment(0)
P
6

For anyone using fragment:

(context as Activity).runOnUiThread {
    //TODO
}
Phyle answered 2/6, 2022 at 13:10 Comment(0)
F
5

This happened to my when I called for an UI change from a doInBackground from Asynctask instead of using onPostExecute.

Dealing with the UI in onPostExecute solved my problem.

Fetial answered 3/11, 2017 at 22:45 Comment(1)
Thanks Jonathan. This was my issue too but I had to do a bit more reading to understand what you meant here. For anyone else, onPostExecute is also a method of AsyncTask but it runs on the UI thread. See here: blog.teamtreehouse.com/all-about-android-asynctasksMatteroffact
K
5

I was working with a class that did not contain a reference to the context. So it was not possible for me to use runOnUIThread(); I used view.post(); and it was solved.

timer.scheduleAtFixedRate(new TimerTask() {

    @Override
    public void run() {
        final int currentPosition = mediaPlayer.getCurrentPosition();
        audioMessage.seekBar.setProgress(currentPosition / 1000);
        audioMessage.tvPlayDuration.post(new Runnable() {
            @Override
            public void run() {
                audioMessage.tvPlayDuration.setText(ChatDateTimeFormatter.getDuration(currentPosition));
            }
        });
    }
}, 0, 1000);
Kneehole answered 9/1, 2018 at 12:23 Comment(2)
What is the analogy of audioMessage and tvPlayDuration to the questions code?Crosscheck
audioMessage is a holder object of the text view. tvPlayDuration is the text view we want to update from a non UI thread. In the question above, currentTime is the text view but it does not have a holder object.Kneehole
Z
4

When using AsyncTask Update the UI in onPostExecute method

    @Override
    protected void onPostExecute(String s) {
   // Update UI here

     }
Zamindar answered 10/5, 2018 at 13:30 Comment(1)
this happened to me. i was updating ui in doinbackground of asynk task.Dramatic
L
3

If you are using Kotlin Coroutine, please try this code:

GlobalScope.launch {
        
       //Write a background operation
    withContext(Dispatchers.Main) {
    
                 // write a UI operation
    
             }
     
      `enter code here`}
Lepidus answered 2/3, 2011 at 0:7 Comment(0)
H
3

This is the stack trace of mentioned exception

        at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6149)
        at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:843)
        at android.view.View.requestLayout(View.java:16474)
        at android.view.View.requestLayout(View.java:16474)
        at android.view.View.requestLayout(View.java:16474)
        at android.view.View.requestLayout(View.java:16474)
        at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:352)
        at android.view.View.requestLayout(View.java:16474)
        at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:352)
        at android.view.View.setFlags(View.java:8938)
        at android.view.View.setVisibility(View.java:6066)

So if you go and dig then you come to know

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

Where mThread is initialize in constructor like below

mThread = Thread.currentThread();

All I mean to say that when we created particular view we created it on UI Thread and later try to modifying in a Worker Thread.

We can verify it via below code snippet

Thread.currentThread().getName()

when we inflate layout and later where you are getting exception.

Hindmost answered 19/1, 2015 at 9:6 Comment(0)
A
3

If you do not want to use runOnUiThread API, you can in fact implement AsynTask for the operations that takes some seconds to complete. But in that case, also after processing your work in doinBackground(), you need to return the finished view in onPostExecute(). The Android implementation allows only main UI thread to interact with views.

Acquiescent answered 29/3, 2015 at 22:46 Comment(0)
A
2

If you simply want to invalidate (call repaint/redraw function) from your non UI Thread, use postInvalidate()

myView.postInvalidate();

This will post an invalidate request on the UI-thread.

For more information : what-does-postinvalidate-do

Aftmost answered 1/2, 2019 at 18:11 Comment(0)
R
2

Well, You can do it like this.

https://developer.android.com/reference/android/view/View#post(java.lang.Runnable)

A simple approach

currentTime.post(new Runnable(){
            @Override
            public void run() {
                 currentTime.setText(time);     
            }
        }

it also provides delay

https://developer.android.com/reference/android/view/View#postDelayed(java.lang.Runnable,%20long)

Riocard answered 28/12, 2020 at 16:26 Comment(1)
Glad to see you posting answers! Do keep in mind that you are expected to add some details about what you fixed or why it is right. It helps users understand what is going on, rather than just being served the answer. Consider it a rule for all your answers here. I hope you have a good time.Anachronous
Z
1

For me the issue was that I was calling onProgressUpdate() explicitly from my code. This shouldn't be done. I called publishProgress() instead and that resolved the error.

Zamboanga answered 31/1, 2014 at 0:16 Comment(0)
R
1

In my case, I have EditText in Adaptor, and it's already in the UI thread. However, when this Activity loads, it's crashes with this error.

My solution is I need to remove <requestFocus /> out from EditText in XML.

Respectful answered 25/6, 2016 at 8:24 Comment(0)
G
1

For the people struggling in Kotlin, it works like this:

lateinit var runnable: Runnable //global variable

 runOnUiThread { //Lambda
            runnable = Runnable {

                //do something here

                runDelayedHandler(5000)
            }
        }

        runnable.run()

 //you need to keep the handler outside the runnable body to work in kotlin
 fun runDelayedHandler(timeToWait: Long) {

        //Keep it running
        val handler = Handler()
        handler.postDelayed(runnable, timeToWait)
    }
Gilleod answered 2/5, 2019 at 8:5 Comment(0)
G
1

If you couldn't find a UIThread you can use this way .

yourcurrentcontext mean, you need to parse Current Context

 new Thread(new Runnable() {
        public void run() {
            while (true) {
                (Activity) yourcurrentcontext).runOnUiThread(new Runnable() {
                    public void run() { 
                        Log.d("Thread Log","I am from UI Thread");
                    }
                });
                try {
                    Thread.sleep(1000);
                } catch (Exception ex) {

                }
            }
        }
    }).start();
Glossary answered 2/12, 2019 at 5:41 Comment(0)
T
1

In Kotlin simply put your code in runOnUiThread activity method

runOnUiThread{
    // write your code here, for example
    val task = Runnable {
            Handler().postDelayed({
                var smzHtcList = mDb?.smzHtcReferralDao()?.getAll()
                tv_showSmzHtcList.text = smzHtcList.toString()
            }, 10)

        }
    mDbWorkerThread.postTask(task)
}
Tupiguarani answered 4/5, 2020 at 19:16 Comment(0)
V
1

If you are within a fragment, then you also need to get the activity object as runOnUIThread is a method on the activity.

An example in Kotlin with some surrounding context to make it clearer - this example is navigating from a camera fragment to a gallery fragment:

// Setup image capture listener which is triggered after photo has been taken
imageCapture.takePicture(
       outputOptions, cameraExecutor, object : ImageCapture.OnImageSavedCallback {

           override fun onError(exc: ImageCaptureException) {
           Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
        }

        override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                        val savedUri = output.savedUri ?: Uri.fromFile(photoFile)
                        Log.d(TAG, "Photo capture succeeded: $savedUri")
               
             //Do whatever work you do when image is saved         
             
             //Now ask navigator to move to new tab - as this
             //updates UI do on the UI thread           
             activity?.runOnUiThread( {
                 Navigation.findNavController(
                        requireActivity(), R.id.fragment_container
                 ).navigate(CameraFragmentDirections
                        .actionCameraToGallery(outputDirectory.absolutePath))
              })
Verdugo answered 22/10, 2020 at 20:12 Comment(0)
M
0

In my case, the caller calls too many times in short time will get this error, I simply put elapsed time checking to do nothing if too short, e.g. ignore if function get called less than 0.5 second:

    private long mLastClickTime = 0;

    public boolean foo() {
        if ( (SystemClock.elapsedRealtime() - mLastClickTime) < 500) {
            return false;
        }
        mLastClickTime = SystemClock.elapsedRealtime();

        //... do ui update
    }
Metallophone answered 28/5, 2018 at 11:56 Comment(2)
Better solution would be to disable the button on click and enable it again when the action completes.Pyelonephritis
@Pyelonephritis In my case is not that simple because the caller is 3rd party library internal and out of my control.Cedar
B
0

Solved : Just put this method in doInBackround Class... and pass the message

public void setProgressText(final String progressText){
        Handler handler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message msg) {
                // Any UI task, example
                progressDialog.setMessage(progressText);
            }
        };
        handler.sendEmptyMessage(1);

    }
Borek answered 28/9, 2018 at 8:6 Comment(0)
E
0

RunOnUIThread didn't seem to work for me but the following ended up solving my issues.

            _ = MainThread.InvokeOnMainThreadAsync(async () =>
           {
               this.LoadApplication(Startup.Init(this.ConfigureServices));

               var authenticationService = App.ServiceProvider.GetService<AuthenticationService>();
               if (authenticationService.AuthenticationResult == null)
               {
                   await authenticationService.AuthenticateAsync(AuthenticationUserFlow.SignUpSignIn, CrossCurrentActivity.Current.Activity).ConfigureAwait(false);
               }
           });

Within the Startup.Init method there is ReactiveUI routing and this needs to be invoked on the main thread. This Invoke method also accepts async/await better than RunOnUIThread.

So anywhere I need to invoke methods on the mainthread I use this.

Please comment on this if anyone knows something I don't and can help me improve my application.

Ettaettari answered 23/12, 2020 at 19:49 Comment(0)
A
0

'Esse é meu codigo'

Timer timer = new Timer();
    timer.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    KeyValuePair<String, String> keyValuePair = getCalculateDifferenceBetweenTwoTimes();

                    CharSequence charSequence = getPresenterUtil().contact(
                            getPresenterUtil().messageStyle("Check-in", Color.GRAY, Typeface.NORMAL, 0.9f),
                            UtilPresenter.LINE,
                            getPresenterUtil().messageStyle(keyValuePair.getKey(), Color.BLACK, Typeface.NORMAL, 1.3f),
                            UtilPresenter.LINE,
                            UtilPresenter.LINE,
                            getPresenterUtil().messageStyle("Tempo de execução", Color.GRAY, Typeface.NORMAL, 0.9f),
                            UtilPresenter.LINE,
                            getPresenterUtil().messageStyle(keyValuePair.getValue(), Color.BLACK, Typeface.NORMAL, 1.3f)
                    );

                    if (materialDialog.getContentView() != null) {
                        materialDialog.getContentView().setText(charSequence);
                    }
                }
            });
        }
    }, 0, 1000);
Antananarivo answered 12/7, 2022 at 16:56 Comment(0)
V
0

if your are using the coroutines for and doing in the IO thread and then where ever are post the UI then use

Dispatcher.Main to update the thread.

withContext(Dispatcher.Main){

//update the UI

}
Visit answered 4/3 at 10:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.