使用SQLite-Net-Extensions时Xamarin Forms Media Plugin在iPhone崩溃求助
从你的描述来看,问题出在调用相机获取图片后,执行SQLiteNetExtensions.Extensions.ReadOperations.GetAllWithChildren<MyObject>(database, recursive: true);时程序崩溃,而不调用相机时一切正常,异常指向Photos.PHImageManager.RequestImage时asset参数为null。下面是针对这个问题的分析和解决方案:
问题场景回顾
- 触发条件:使用Xamarin Forms Media Plugin调用相机拍照后,执行SQLite-Net-Extensions的递归加载操作
- 异常信息:
2018-03-26 16:21:37.303 (ProjectName).iOS[364:41332] Unable to get metadata: System.ArgumentNullException: Value cannot be null. Parameter name: asset at Photos.PHImageManager.RequestIma...
- 正常情况:不调用相机时,
GetAllWithChildren可以正常运行
可能的原因
- 相机操作后,Media Plugin未正确释放Photos框架的
asset资源,导致后续SQLite操作触发了对null asset的访问 - 拍照后你可能将未正确初始化的图片相关数据存入了
MyObject,在SQLite-Net-Extensions递归加载子对象时,触发了空引用异常 - 相机操作在UI线程执行,而SQLite操作也在同一线程,导致资源锁定或上下文冲突,间接引发了asset相关的异常
解决方案
1. 确保相机获取的图片资源被正确处理和释放
拍照后一定要先判断返回的MediaFile是否为null,并且使用using语句自动释放资源,避免持有无效的Photos asset对象:
using (var mediaFile = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions())) { if (mediaFile != null) { // 仅当图片有效时,才更新MyObject的相关字段 myObject.ImagePath = mediaFile.Path; // 保存到数据库 await database.UpdateAsync(myObject); } else { // 用户取消拍照,直接返回,不更新数据库 return; } }
2. 切换到后台线程执行SQLite操作
相机操作是在UI线程进行的,SQLite操作如果也在UI线程,容易引发资源冲突。把GetAllWithChildren的调用放到后台线程执行:
var myObjects = await Task.Run(() => SQLiteNetExtensions.Extensions.ReadOperations.GetAllWithChildren<MyObject>(database, recursive: true) );
3. 检查MyObject的关联配置和数据有效性
检查MyObject类中与图片相关的关联属性(比如[ForeignKey]、[OneToOne]等)是否正确配置,确保不会因为图片字段为null而触发递归加载时的异常。另外,在保存到数据库前,确认所有关联的子对象都已正确初始化,避免存入null值导致后续加载出错。
4. 捕获异常并定位具体问题
在调用GetAllWithChildren的地方添加异常捕获,打印详细的堆栈信息,帮助你精准定位是哪个环节出现了null asset:
try { var myObjects = SQLiteNetExtensions.Extensions.ReadOperations.GetAllWithChildren<MyObject>(database, recursive: true); } catch (ArgumentNullException ex) { Console.WriteLine($"异常详情:{ex.Message}\n堆栈跟踪:{ex.StackTrace}"); // 这里可以根据实际情况做错误提示或恢复操作 }
内容的提问来源于stack exchange,提问作者Daron Rice

