为什么在Xamarin应用程序中使用Device.BeginInvokeOnMainThread()?

时间:2017-07-20 06:31:36

标签: xamarin xamarin.forms

我的代码如下所示:

    public void Init() {
        if (AS.pti == PTI.UserInput)
        {
            AS.runCardTimer = false;
        }
        else
        {
            AS.runCardTimer = true;
            Device.BeginInvokeOnMainThread(() => showCards().ContinueWith((arg) => { }));
        }
    }

从构造函数调用Init方法。有人可以向我解释为什么开发人员可能添加了Device.BeginInvokeOnMainThread()而不是只调用showCards方法吗?

还有什么是ContinueWith((arg))做什么以及为什么要包含它?

3 个答案:

答案 0 :(得分:3)

可以在后台线程上创建此Init()方法的类。我假设showCards()正在更新某种UI。 UI只能在UI /主线程上更新。 Device.BeginInvokeOnMainThread()确保lambda中的代码在主线程上执行。

ContinueWith()是一种可以在Task上找到的方法。如果showCards()返回任务,ContinueWith()会确保在退出lambda之前完成任务。

答案 1 :(得分:2)

必须在UI线程上执行UI操作(主线程的名称不同)。如果您尝试从非主线程执行UI更改,您的应用程序将崩溃。我认为开发人员希望确保它能按预期工作。

答案 2 :(得分:0)

简单的答案是:后台线程无法修改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);
}

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. 
    }
}

可以在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);
}

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