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 - 在主线程以外的线程上加载数据的主要内容,如果未能解决你的问题,请参考以下文章

如何在 iOS 7 中使用加载器

-[GCKCastDeviceProvider stopDiscovery] 必须在主线程上调用

tableView.reloadData() 不起作用,可能没有在主线程上调用

核心数据:获取背景并在主线程上使用 objectWithID,性能优势?

在主线程上启动对话框等待工作线程的结果

GCD主队列是不是必须在主线程上执行?