什么是Device.BeginInvokeOnMainThread?

And*_*lar 22 xamarin xamarin.forms

我想有人向我解释什么是Device.BeginInvokeOnMainThread?它的用途是什么?使用案例的例子.

谢谢.

pin*_*dax 17

只是添加一个例子.

想象一下,DoAnyWorkAsync如果你以这种方式调用它(就像一个例子)你有一个异步方法:

 DoAnyWorkAsync().ContinueWith ((arg) => {
                StatusLabel.Text = "Async operation completed...";
            });
Run Code Online (Sandbox Code Playgroud)

StatusLabel 是XAML中的标签.

异步操作完成后,上面的代码不会在标签中显示消息,因为回调是在与UI线程不同的另一个线程中,因此它无法修改UI.

如果你更新了相同的代码,只需将StatusLabel文本更新包含在内Device.BeginInvokeOnMainThread:

 DoAnyWorkAsync().ContinueWith ((arg) => {
     Device.BeginInvokeOnMainThread (() => {
                StatusLabel.Text = "Async operation completed...";
           });
     });
Run Code Online (Sandbox Code Playgroud)

不会有任何问题.

自己尝试一下,替换DoAnyWorkAsync()Task.Delay(2000).


Jas*_*son 10

您只能从主UI线程更新UI.如果您在后台线程上运行代码并需要更新UI,则BeginInvokeOnMainThread()允许您强制代码在主线程上运行,以便您可以更新UI.


小智 10

简单的答案是:后台线程无法修改UI元素,因为iOS和Android中的大多数UI操作都不是线程安全的; 因此,您需要调用UI线程来执行修改UI的代码,例如MyLabel.Text ="New Text".

详细的答案可以在Xamarin文档中找到:

对于iOS:

IOSPlatformServices.BeginInvokeOnMainThread()方法只调用NSRunLoop.Main.BeginInvokeOnMainThread

public void BeginInvokeOnMainThread(Action action)
{
    NSRunLoop.Main.BeginInvokeOnMainThread(action.Invoke);
}
Run Code Online (Sandbox Code Playgroud)

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

您可以从线程中使用此方法来调用UI线程中使用指定选择器公开的指定对象中的代码.这对于影响UIKit或AppKit的大多数操作都是必需的,因为这些API中的任何一个都不是线程安全的.

当主线程返回其主循环以处理事件时执行代码.

对于Android:

许多人认为Xamarin.Android BeginInvokeOnMainThread()方法使用Activity.runOnUiThread(),但事实并非如此,并且使用runOnUiThread()和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. 
    }
}
Run Code Online (Sandbox Code Playgroud)

可以在AndroidPlatformServices.cs类中找到Xamarin.Android BeginInvokeOnMainThread()方法的实际实现

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

    s_handler.Post(action);
}
Run Code Online (Sandbox Code Playgroud)

https://developer.android.com/reference/android/os/Handler.html#post(java.lang.Runnable) 正如您所看到的,Handler.Post(action)不会立即执行您的操作代码.它被添加到Looper的消息队列中,并在UI线程被安排处理其消息时处理.