What is Device.BeginInvokeOnMainThread for?

前端 未结 3 1471
無奈伤痛
無奈伤痛 2021-02-01 16:26

I would like someone to explain to me what is Device.BeginInvokeOnMainThread and what is it for?

And also some examples of cases where it\'s used.

相关标签:
3条回答
  • 2021-02-01 16:33

    Just to add an example.

    Imagine you have an async method DoAnyWorkAsync if you call it (just as an example) this way:

     DoAnyWorkAsync().ContinueWith ((arg) => {
                    StatusLabel.Text = "Async operation completed...";
                });
    

    StatusLabel is a label you have in the XAML.

    The code above will not show the message in the label once the async operation had finished, because the callback is in another thread different than the UI thread and because of that it cannot modify the UI.

    If the same code you update it a bit, just enclosing the StatusLabel text update within Device.BeginInvokeOnMainThread like this:

     DoAnyWorkAsync().ContinueWith ((arg) => {
         Device.BeginInvokeOnMainThread (() => {
                    StatusLabel.Text = "Async operation completed...";
               });
         });
    

    there will not be any problem.

    Try it yourself, replacing DoAnyWorkAsync() with Task.Delay(2000).

    0 讨论(0)
  • 2021-02-01 16:41

    You can only update the UI from the main UI thread. If you are running code on a background thread and need to update the UI, BeginInvokeOnMainThread() allows you to force your code to run on the main thread, so you can update the UI.

    0 讨论(0)
  • 2021-02-01 16:44

    The simple answer is: Background thread cannot modify UI elements because most UI operations in iOS and Android are not thread-safe; therefore, you need to invoke UI thread to execute the code that modifies UI such MyLabel.Text="New Text".

    The detailed answer can be found in Xamarin document:

    For iOS:

    IOSPlatformServices.BeginInvokeOnMainThread() Method simply calls NSRunLoop.Main.BeginInvokeOnMainThread

    public void BeginInvokeOnMainThread(Action action)
    {
        NSRunLoop.Main.BeginInvokeOnMainThread(action.Invoke);
    }
    

    https://developer.xamarin.com/api/member/Foundation.NSObject.BeginInvokeOnMainThread/p/ObjCRuntime.Selector/Foundation.NSObject/

    You use this method from a thread to invoke the code in the specified object that is exposed with the specified selector in the UI thread. This is required for most operations that affect UIKit or AppKit as neither one of those APIs is thread safe.

    The code is executed when the main thread goes back to its main loop for processing events.

    For Android:

    Many People think on Xamarin.Android BeginInvokeOnMainThread() method use Activity.runOnUiThread(), BUT this is NOT the case, and there is a difference between using runOnUiThread() and Handler.Post():

    public final void runOnUiThread(Runnable action) {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);//<-- post message delays action until UI thread is scheduled to handle messages
        } else {
            action.run();//<--action is executed immediately if current running thread is UI thread. 
        }
    }
    

    The actual implementation of Xamarin.Android BeginInvokeOnMainThread() method can be found in AndroidPlatformServices.cs class

    public void BeginInvokeOnMainThread(Action action)
    {
        if (s_handler == null || s_handler.Looper != Looper.MainLooper)
        {
            s_handler = new Handler(Looper.MainLooper);
        }
    
        s_handler.Post(action);
    }
    

    https://developer.android.com/reference/android/os/Handler.html#post(java.lang.Runnable) As you can see, you action code is not executed immediately by Handler.Post(action). It is added to the Looper's message queue, and is handled when the UI thread's scheduled to handle its message.

    0 讨论(0)
提交回复
热议问题