更新UI不立即反映的BeginInvokeOnMainThread

时间:2016-05-19 07:28:36

标签: xamarin.forms ui-thread

我在点击登录按钮后显示活动指示器,直到将用户重定向到另一个页面,让他们了解正在进行的一些进展。但点击登录按钮后,活动指示器不会立即显示,几秒钟后会显示,

为什么会这样?为了减少这种延迟,我只是把活动指标......

我的代码:

async void loginButtonGesture_Tapped(object sender, EventArgs e)
{
     Device.BeginInvokeOnMainThread(() =>
                    {
                        loadingPanel.IsRunning = true;
                        loadingPanel.IsVisible = true;
                    }); 
}

2 个答案:

答案 0 :(得分:0)

该方法是否必须是异步无效的?似乎主线程上的这个特定调度不应该是异步的。试试看它是否会改变任何东西。您还可以尝试在Device.BeginInvokeOnMainThread行上设置断点,并尝试在loadingPanel.IsRunning ...行中查看延迟发生的位置。

答案 1 :(得分:0)

首先,loginButtonGesture_Tapped()事件处理程序由UI线程触发,因此您不需要使用Device.BeginInvokeOnMainThread(),它已经在UI线程中。但是因为你在这里使用了Device.BeginInvokeOnMainThread(),所以延迟的原因是因为在Android上,你的BeginInvokeOnMainThread()内的代码被添加到MainLooper的消息队列中,(你的代码没有立即执行)并被执行当UI线程被安排处理其消息时。

详细解答可以在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线程被安排处理其消息时被处理。