繁体   English   中英

Xamarin使用Prism导致Autofac崩溃而形成DependencyService-未处理的异常

[英]Xamarin Forms DependencyService with Prism with Autofac crash - Unhandled Exception

因此,为了继续我的Xamarin尝试,我正在尝试开发一个将拍摄照片的“内容”页面,然后将照片保存在设备库中以供查看。 我正在将Prism与Autofac一起使用,并且正在遵循DependencyService上Wiki文档以及GitHub上提供的示例,但是该程序崩溃了而未说明原因。

我讨厌那个!

所以,这是我的界面:

   public interface ISavePicture
{
    void SavePictureToGallery(string path);
}

ViewModel:

public class PluginPageViewModel : BindableBase
{
    private ISavePicture _savePicture;

    public PluginPageViewModel(ISavePicture savePicture)
    {
        try
        {
            TakePicCommand = new DelegateCommand(TakePicture);
            _savePicture = savePicture;
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex);    
        }

    }

    public  ICommand TakePicCommand { get; private set; }

    private async void TakePicture()
    {
        try
            // Code here for getting the camera to take a picture ...

            _savePicture.SavePictureToGallery(filePath);
        }

        catch (Exception e)
        {
            Debug.WriteLine(e);
            throw;
        }

    }

  }
}

和Android代码:

using Android.App;
using Android.Content;
using Java.IO;
using RolodexDEMO_XF.Droid.Service;
using RolodexDEMO_XF.Services;
using Xamarin.Forms;
using Uri = Android.Net.Uri;

[assembly: Dependency(typeof(SavePicture_Android))]
namespace RolodexDEMO_XF.Droid.Service
{
    public class SavePicture_Android : Activity, ISavePicture
    {
        public void SavePictureToGallery(string path)
        {
            Intent mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);
            var file = new File(path);
            Uri contentUri = Uri.FromFile(file);
            mediaScanIntent.SetData(contentUri);
            SendBroadcast(mediaScanIntent);
        }
    }
}

请注意, 确实具有DependencyService的Assembly属性。 我还想指出,我没有使用仿真器对其进行测试。 相反,我正在使用我的Galaxy Note 4,因为我正在尝试测试相机。 对于这一部分,我使用的是James Montemagno的Xamarin.Plugins,效果很好。 我只是无法保存它,或者查看图片是否确实保存到设备中。

那么,我在哪里出错呢?

更新:有人问我要在Android应用程序中添加什么权限,因此在AndroidManifest.xml中:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto" package="RolodexDEMOXF.RolodexDEMOXF">
    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <application android:theme="@style/MyTheme" android:label="Rolodex DEMO">
        <provider android:name="android.support.v4.content.FileProvider" android:authorities="RolodexDEMOXF.fileprovider" android:exported="false" android:grantUriPermissions="true">
            <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"></meta-data>
        </provider>
    </application>
</manifest>

并在file_paths.xml中(在Resources \\ xml目录中)

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images" path="Android/data/RolodexDEMOXF/files/Pictures" />
    <external-path name="my_movies" path="Android/data/RolodexDEMOXF/files/Movies" />
</paths>

我在这里输入答案,以防其他人遇到与我将来相同的问题。 另外,由于文档很少,我不得不从一个中文网站 (到处都是)拼凑这个替代解决方案,并与Slate Prism-Forms频道的一些人讨论,我认为最好把它发布出来那里有替代解决方案,因此至少您可以初步了解解决DependencyService问题以及使用Autofac DI的解决方法。

我确实要注意,在Prism GitHub上正在进行讨论,即应该弃用Prism的DependencyService的实现,并通过本文将在此介绍的替代方法进行讨论。 因此,希望开发团队中的一员能够对其进行记录,并针对我在此处显示的内容提供更好的代码示例。

也就是说,在演出中...

好的,所以我找到了问题的答案。 长话短说,问题是Autofac容器。

现在是长篇版。

从我收集的Dan Siegel的东西中,Prism可以为IoC / DI容器实现的所有容器中,我必须选择一个不能与其他容器配合的容器!

为什么,我说它播放不好? 根据Autofac文档, 容器是不可变的 ,这意味着一旦构建容器便无法对其进行修改。 因此,我的假设是,当Prism遍历该项目并尝试添加DependencyService的注册类型时,Autofac陷入困境,因为该容器已被构建,因此将引发“未处理的异常”。

这说明了问题,但没有解决方案。

解决方案是什么? 好吧,事实证明Brian(Lagunas)和Brian(Noyes)已经实现了一个名为IPlatformInitializer的新接口,因此我别无选择,只能使用ContainerBuilder.Update(container)来添加新的RegisterType,以实现其他RegisterTypes对于DependencyService,我必须像这样实现它:

public class AndroidInitializer : IPlatformInitializer
{
    public void RegisterTypes(IContainer container)
    {
        var temp = new ContainerBuilder();

        temp.RegisterType<SavePicture_Android>().As<ISavePicture>();
        temp.RegisterType<MessageService_Android>().As<IMessageService>();
        // ... add more RegisterTypes as needed ... 

        temp.Update(container);
    }
}

此类已包含在Prism模板项目中。 对于Android,它位于MainActivity.cs文件中。

万一您想知道,iOS和UWP也是一样。 因此,与其成为AndroidInitializer:

  • iOSInitializer:IPlatformInitializer(iOS)(在AppDelegate.cs内部)
  • UWPInitializer:IPlatformInitializer(UWP)(在MainPage.xaml.cs内部)

最后一件事:您可以转储[Assembly Dependency(typeof(X))]属性,因为不再需要它。 但是,您仍然需要按照其在DependencyService文档中所述的方式进行构造函数依赖项注入

正如我说的,Prism团伙正在摆脱在Prism的下一个版本上摆脱其对DependencyService的实现的想法,并按照我向您解释的方法走下去。

还值得注意的是,Autofac上的家伙还在讨论在下一版本的Autofac 4 上摆脱ContainerBuilder.Update()的问题。

只是一些合理的警告,因为我在这里放的内容可能会在将来消失。

我希望它可以帮助某人!

Prism社区的各个成员致力于使Xamarin.Forms(Prism.Autofac.Forms)的Autofac实现出色。 因此使用此IoC容器选项不是一个坏选择。 问题在于,在不了解不推荐使用ContainerBuilder.Update()方法的情况下编写了Autofac实现的第一个版本(用于Prism.Forms)。 并且Autofac容器应该是不可变的(即,一次构建且不更新)。

另外,如果无法从Autofac IoC容器解析依赖关系,则Autofac实现不具有通过Xamarin.Forms DependencyService解析依赖关系的内置功能。 这是一个已知问题,不可能解决,因为-正如Steve指出的那样-Xamarin.Forms的Prism与DependencyService之间的集成正在重新考虑(并且可能已弃用)。

因此,使用Autofac,您只需要对Xamarin.Forms依赖项执行二级注册。 您可以按照Steve的说明进行操作-在IPlatformInitializer实现的RegisterTypes()方法中RegisterTypes()特定于平台的实现; 或者您可以使用Xamarin.Forms DependencyService在注册它的共享(PCL)项目App.RegisterTypes()方法(在App.xaml.cs文件)。

使用Xamarin.Forms DependencyService在共享项目中注册它的方法如下(同样,在从PrismApplication继承的类中,该类通常是App.xaml.cs文件):

protected override void RegisterTypes()
{
   var builder = new ContainerBuilder();

   builder.Register(ctx => Xamarin.Forms.DependencyService.Get<ISavePicture>())
      .As<ISavePicture>();

   builder.Update(Container);
}

最后说明:上面提供的信息对于Prism.Autofac.Forms的6.3.0版本是正确的。 由于正在对某些东西进行重新处理(可能是针对Prism 7.x),因此在构建Autofac容器后便无法更新它们(即使其不可变); 似乎在将来的某个时候,以上代码将更改为:

protected override void RegisterTypes()
{
   Container.Register(ctx => Xamarin.Forms.DependencyService.Get<ISavePicture>())
      .As<ISavePicture>();
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM