Multithreading Device.BeginInvokeMainThread用于什么?
我想有人向我解释什么是Device.beginInvokeMainThread,它是用来做什么的Multithreading Device.BeginInvokeMainThread用于什么?,multithreading,xamarin,xamarin.forms,Multithreading,Xamarin,Xamarin.forms,我想有人向我解释什么是Device.beginInvokeMainThread,它是用来做什么的 还有一些使用它的示例。您只能从主UI线程更新UI。如果您正在后台线程上运行代码,并且需要更新UI,BeginInvokeOnMainThread()允许您强制代码在主线程上运行,以便您可以更新UI。仅添加一个示例 假设您有一个异步方法DoAnyWorkAsync,如果您这样调用它(作为示例): DoAnyWorkAsync().ContinueWith ((arg) => {
还有一些使用它的示例。您只能从主UI线程更新UI。如果您正在后台线程上运行代码,并且需要更新UI,
BeginInvokeOnMainThread()
允许您强制代码在主线程上运行,以便您可以更新UI。仅添加一个示例
假设您有一个异步方法DoAnyWorkAsync
,如果您这样调用它(作为示例):
DoAnyWorkAsync().ContinueWith ((arg) => {
StatusLabel.Text = "Async operation completed...";
});
StatusLabel
是XAML中的标签
异步操作完成后,上面的代码将不会在标签中显示消息,因为回调位于与UI线程不同的另一个线程中,因此它无法修改UI
如果您更新了同一代码,只需将StatusLabel
文本更新包含在Device.beginInvokeMainThread
中,如下所示:
DoAnyWorkAsync().ContinueWith ((arg) => {
Device.BeginInvokeOnMainThread (() => {
StatusLabel.Text = "Async operation completed...";
});
});
不会有任何问题
你自己试试看,用
Task.Delay(2000)
替换DoAnyWorkAsync()
。简单的答案是:后台线程无法修改UI元素,因为iOS和Android中的大多数UI操作都不是线程安全的;因此,您需要调用UI线程来执行修改UI的代码,例如MyLabel.Text=“New Text”
详细答案可在Xamarin文档中找到:
对于iOS:
IOSPlatformServices.BeginInvokeMainThread()方法只调用nsrunlop.Main.BeginInvokeMainThread
public void BeginInvokeOnMainThread(Action action)
{
NSRunLoop.Main.BeginInvokeOnMainThread(action.Invoke);
}
从线程使用此方法调用指定对象中的代码,该对象在UI线程中使用指定选择器公开这是影响UIKit或AppKit的大多数操作所必需的,因为这些API都不是线程安全的。
当主线程返回其主循环处理事件时,将执行该代码
对于Android:
许多人认为Xamarin.Android BeginInvokeOnMainThread()方法使用Activity.runOnUiThread(),但事实并非如此,使用runOnUiThread()和Handler.Post()之间存在差异:
如您所见,Handler.Post(action)不会立即执行操作代码。它被添加到循环器的消息队列中,并在UI线程计划处理其消息时进行处理 如上所述,任何UI更新都必须在主线程中进行,否则将发生导出
虽然Xamarin.Forms有一个特点,但只要用户界面的这一部分与当前显示的用户界面元素分离,就可以在主线程下操纵用户界面元素(例如创建
标签s并将其添加到堆栈布局的子类集合),而不会出现任何故障。这种方法可以通过创建Xamarin.Forms控件并在单独的线程中设置它们在内存中/屏幕外的子/子关系来提高性能,但要将它们附加到显示的容器(例如,分配ContentPage
的内容属性)您必须在设备中执行此操作。BeginInvokeOnMainThread()
非常感谢您。我们想在发布后指出android实现的新位置,并在github repo下搜索IPlatformServices
,查找其他平台实现
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.
}
}
public void BeginInvokeOnMainThread(Action action)
{
if (s_handler == null || s_handler.Looper != Looper.MainLooper)
{
s_handler = new Handler(Looper.MainLooper);
}
s_handler.Post(action);
}