Xamarin - 在主线程以外的线程上加载数据
Posted
技术标签:
【中文标题】Xamarin - 在主线程以外的线程上加载数据【英文标题】:Xamarin - load data on thread other than main 【发布时间】:2021-12-11 06:32:50 【问题描述】:加载页面时,我会运行一些从 SQLite DB 加载项目的代码。因此(我相信如此)页面加载动画并不流畅。所以我决定提前在App.OnStart
加载数据。
Task.Run(itemsStore.LoadItemsAsync);
那么问题是它总是在主线程中运行。我尝试在LoadItemsAsync
内部做一个这样的把戏:
while (MainThread.IsMainThread)
Debug.WriteLine($"ItemsStore.DoLoadItemsAsync: (2) Is main thread: MainThread.IsMainThread");
await Task.Delay(100);
但随后应用程序挂起。
所以我的问题是:如何真正在后台加载数据以及为什么上面的技巧不起作用?我也尝试使用Task.Yield
。
更新
我已将应用程序的 OnStart
方法更改为:
protected override void OnStart()
var itemStore = DependencyService.Get<IItemStore>();
itemsStore.Init(); // !!! HERE THE CHANGE !!!
Task.Run(itemsStore.LoadItemsAsync);
到
protected override void OnStart()
var itemStore = DependencyService.Get<IItemStore>();
Task.Run(() => itemsStore.Init()); // !!! HERE THE CHANGE !!!
Task.Run(itemsStore.LoadItemsAsync);
现在它不仅仅在主线程上运行。谁能给我解释一下?
【问题讨论】:
您需要向您的问题添加更多代码,特别是 LoadItemsAsync 正文。一种可能的方法可能是调用itemsStore.LoadItemsAsync()
而不在其前面添加 await
1) 无论您在Task.Run
中放入什么,都可以在后台线程上运行。除非你“.Wait”什么的。所以问题一定是 LoadItemsAsync 中的其他问题。或者在Task.Run
行之前或之后没有显示的内容。显示更多有问题的代码。 2)这个技巧没有任何用处。代码永远不会自动从 MainThread 更改为不同的线程。
关于如何正确执行此操作,我展示了两个示例 here 和 here。在第一个示例中,我在Run
中使用Task.Delay
,以确保XForms 加载空页面不会延迟。 (我暂停了一会儿后台工作。))
@ToolmakerSteve 感谢 cmets。我一定会延迟尝试这个技巧。但与此同时,我已经更新了我的问题。您正确地认为“问题必须是其他问题”。也许你可以回答我的最后一个问题?
在我的第一个链接中查看我的代码。了解“BackgroundWork”如何完成需要在后台运行的一切。然后当它完成时,它会调用Device.BeginInvokeOnMainThread
。在其中,您将需要放在主线程上的代码。您发布的OnStart
代码存在缺陷。 Task.Run
的全部意义在于启动在后台运行的东西。这意味着第一个Task.Run
行在第二个Task.Run 行开始时可能还没有完成运行。可能没问题,但也可能不行。相反,制作 one Task.Run,并将所有内容放入其中。如我的代码所示。
【参考方案1】:
我写了一个小例子供大家参考。
这里是 xaml 代码:
<StackLayout>
<CollectionView x:Name="mytest">
<CollectionView.ItemTemplate>
<DataTemplate>
<Label Text="Binding ."></Label>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
这是cs代码:
public partial class MainPage : ContentPage
ObservableCollection<string> ts = new ObservableCollection<string>();
public MainPage()
InitializeComponent();
mytest.ItemsSource = ts;
protected override void OnAppearing()
base.OnAppearing();
var result = Task.Run(() => myTest());
private void myTest()
Thread.Sleep(10000);//Time spent in simulated query
ts.Add("aaa");
ts.Add("bbb");
ts.Add("ccc");
但是根据您的说法,我不确定您的数据库有多少数据,用于快速查询。在数据库中使用index是提高查询效率的最佳方式。
【讨论】:
以上是关于Xamarin - 在主线程以外的线程上加载数据的主要内容,如果未能解决你的问题,请参考以下文章
-[GCKCastDeviceProvider stopDiscovery] 必须在主线程上调用
tableView.reloadData() 不起作用,可能没有在主线程上调用