因此,为了继续我第一次涉足Xamarin,我正在尝试开发一个可拍照的内容页面,然后将照片保存在设备库中供查看。我正在使用Prism和Autofac,我跟随wiki documentation on DependencyService以及GitHub上提供的示例,但程序崩溃而没有解释原因。
我讨厌那个!
所以,这是我的界面:
public interface ISavePicture
{
void SavePictureToGallery(string path);
}
视图模型:
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);
}
}
}
请注意, I DO 具有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>
答案 0 :(得分:1)
我在这里提出答案,以防其他人遇到与我未来相同的问题。此外,由于那里的文档很少,我不得不拼凑出Chinese website(所有地方!)的替代解决方案,并与Slate Prism-Forms频道上的一些人讨论,我认为它最好把它放在替代解决方案上,所以至少你得到一个关于解决DependencyService问题的基本想法,以及使用Autofac DI的解决方法。
我想要注意的是,Prism GitHub正在讨论Prism的DependencyService实现应该被折旧,并且我将在本文中对此进行描述。所以希望开发团队中的一个人能够记录它并提供更好的代码示例来说明我在这里展示的内容。
那说,随着节目......
好的,所以我找到了问题的答案。长话短说,问题是Autofac容器。
现在是漫长的版本。
从我收集的Dan Siegel,Prism可以为IoC / DI容器实现的所有容器中,我不得不选择一个与其他人不能合作的容器!
为什么,我说它不能发挥出色?根据Autofac文档,the container is Immutable表示一旦构建它就无法修改。所以我的假设是,当Prism通过项目并尝试添加DependencyService的注册类型时,Autofac会因为容器已经构建而无法进行,因此“未处理的异常”#34;被扔了。
这解释了问题,但不是解决方案。
解决方案是什么?好吧,事实证明Brian(Lagunas)和Brian(Noyes)实现了一个名为IPlatformInitializer的新接口,因此我别无选择,只能使用ContainerBuilder.Update(容器)添加新的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构建getting rid of their implementation of DependencyService的想法,并沿着这条路向我解释。
值得注意的是,在Autofac 4的下一个版本上,Autofac上的人也是discussing on getting rid of the ContainerBuilder.Update()。
只是一些公平的警告,因为我在这里放的东西可能会在未来出现。
我希望它可以帮助别人!
答案 1 :(得分:1)
Prism社区的各个成员致力于为Xamarin.Forms(Prism.Autofac.Forms)制作Prof的Autofac实现优秀;所以使用这个IoC容器选项并不是一个糟糕的选择。问题是Autofac实现的第一个版本(对于Prism.Forms)是在不知道ContainerBuilder.Update()方法被弃用的情况下编写的;并且Autofac容器应该是不可变的(即构建一次而不是更新)。
此外,如果无法从Autofac IoC容器中解析,则Autofac实现没有通过Xamarin.Forms DependencyService解析依赖关系的内置功能。这是一个已知的问题,并且不太可能被修复,因为 - 正如史蒂夫指出的那样 - 正在重新考虑Prism for Xamarin.Forms和DependencyService之间的集成(并且可能已经弃用)。
因此,使用Autofac,您只需要执行Xamarin.Forms依赖项的二次注册。你可以像史蒂夫所展示的那样 - 在RegisterTypes()
实现的IPlatformInitializer
方法中注册特定于平台的实现; 或您可以使用Xamarin.Forms DependencyService在App.RegisterTypes()
方法(在 App.xaml.cs 文件中)的共享(PCL)项目中注册它)。
使用Xamarin.Forms DependencyService在共享项目中注册它看起来像这样(在类中继承自PrismApplication,通常是 App.xaml.cs 文件):< / p>
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>();
}