Xamarin.Essentials FilePicker 导致应用重启

Xamarin.Essentials FilePicker causes restart of app

我们有一个具有选项卡视图的 Xamarin Forms 应用程序。从其中一个选项卡,我们打开一个新的内容页面,它需要有一个选项 select 文件并上传附件。 使用 Xamarin.Essentials FilePicker,我们可以选择文件并读取文件内容,但在读取文件后,应用程序会自动导航到主屏幕 - 与应用程序重启相同。

我们观察到,当打开文件选择器时,会调用 App.xaml.cs 中的 OnSleep,当读取文件并关闭选择器时,会调用 App.xaml.cs 中的 onresume。这似乎会导致 XForms 应用程序完全重新启动。

所有权限都已到位 - 我们的目标是 Android 9.0,使用 XForms 4.8 版,X.Essentials v1.6。

你能帮忙吗?

相关代码:

            try
            {
                var file = await FilePicker.PickAsync();
                if (file != null)
                {
                    var stream = await file.OpenReadAsync();
                    byte[] FileData = new byte[stream.Length];
                    await stream.ReadAsync(FileData, 0, (int)(stream.Length - 1));
                    fileData = Convert.ToBase64String(FileData);
                    fileStream = new MemoryStream(FileData);
                    FileNameVisibility = true;
                    FileName = file.FileName;
                }
            }
            catch (Exception ex)
            {
                Crashes.TrackError(ex);
            }

已测试 code snippet in doc

这段代码对我有用:

FilePickerPage.xaml:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XFSOAnswers.FilePickerPage">
    <ContentPage.Content>
        <StackLayout>
            <Button Text="Pick File" Clicked="PickFileButton_Clicked" />
            <Label x:Name="FileName" />
            <Image x:Name="FileImage" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

FilePickerPage.xaml.cs:

using System;
using System.Threading.Tasks;
using Xamarin.Essentials;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace XFSOAnswers
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class FilePickerPage : ContentPage
    {
        public FilePickerPage()
        {
            InitializeComponent();
        }

        private void PickFileButton_Clicked(object sender, EventArgs e)
        {
            Device.BeginInvokeOnMainThread(async () =>
            {
                await PickAndShow(PickOptions.Images);
            });
        }

        async Task<FileResult> PickAndShow(PickOptions options)
        {
            try
            {
                var result = await FilePicker.PickAsync(options);
                if (result != null)
                {
                    FileName.Text = $"File Name: {result.FileName}";
                    if (result.FileName.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) ||
                        result.FileName.EndsWith("png", StringComparison.OrdinalIgnoreCase))
                    {
                        var stream = await result.OpenReadAsync();
                        FileImage.Source = ImageSource.FromStream(() => stream);
                    }
                }

                return result;
            }
            catch (Exception ex)
            {
                // The user canceled or something went wrong
                _ = ex;
            }

            return null;
        }
    }
}

App.xaml.cs:

...
MainPage = new StartPage();

起始页:

... had a button to go to FilePickerPage.

因此 StartPage 在堆栈上,然后是 FilePickerPage。
完成 FilePicker 后,FilePickerPage 仍在显示 - 文件名和图像:

MainActivity.cs:

protected override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);

    Xamarin.Essentials.Platform.Init(this, savedInstanceState);
    ...
}


public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
    Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);

    base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}

注意:上面的 MainActivity 代码应该自动出现在任何新的 Xamarin Forms 项目中;只有在项目模板自动添加 Essentials 之前,如果这是一个旧项目,它才会丢失。


那么,如何调试您的代码。

  1. 先把里面的代码全部注释掉
    if (file != null) { ... }

注释掉时,崩溃与否?


  1. 包装您显示的整个代码片段:
    Device.BeginInvokeOnMainThread( async () => {
        ... YOUR CODE ...
    });

  1. 是的,确实会调用 OnSleep / OnResume。不,这不一定是“重新启动应用程序”。

也许您的导航堆栈是空的?当 FilePicker 关闭时,可能无处可回。