[英]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:
最后一件事:您可以转储[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.