Xamarin.forms: [Bug] TypedBinding`2 [TSource,TProperty]中的InvalidOperationException。应用

创建于 2019-06-28  ·  58评论  ·  资料来源: xamarin/Xamarin.Forms

描述

在我的应用中看到这些未处理的异常。 我相信它们是在绑定到ObservableCollections的ObservableCollection的分组ListView中添加和删除叶项时发生的。

我正在使用编译的绑定,以防万一。

System.InvalidOperationException: Operation is not valid due to the current state of the object.

这是我在AppCenter中看到的堆栈跟踪:

TypedBinding`2[TSource,TProperty].Apply (System.Boolean fromTarget)
TypedBinding`2+PropertyChangedProxy[TSource,TProperty].<OnPropertyChanged>b__16_0 ()
Thread+RunnableImplementor.Run ()
IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this)
(wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.39(intptr,intptr)

重现步骤

抱歉,我还没有可靠的代表。

预期行为

实际行为

基本信息

  • 发行版本:3.6最新
  • 上次已知的良好版本:未知
  • IDE:VS 2019
  • 平台目标框架:

    • Android:9.0

  • Android支持库版本:最新
  • Nuget软件包:
  • 受影响的设备:

屏幕截图

复制链接

listview 7 high in-progress Android iOS 🍎 bug

最有用的评论

@StephaneDelcroix @ kingces95 @wachs
你们似乎落后于TypedBinding实现。

正如你可以在这个线程看到,很多开发者那里(包括我),然后现在有自己的应用程序崩溃,因为的InvalidOperationException被抛出TypedBinding
@samhouts在她的假设中似乎是正确的,在GC启动并删除了targetTypedBinding (很可能在我们的应用程序中,我们有一个很大的ListView和许多复杂的DataTemplates ),则TypedBinding抛出一个InvalidOperationException ,它永远不会被捕获,并导致Android(以及其他任何平台)上的应用程序崩溃??) 像这样:

TypedBinding 2[TSource,TProperty].Apply (System.Boolean fromTarget) System.InvalidOperationException: Operation is not valid due to the current state of the object. Stack traces TypedBinding 2 [TSource,TProperty] .Apply(System.Boolean fromTarget)
TypedBinding`2 + PropertyChangedProxy [TSource,TProperty]。b__16_0()
线程+ RunnableImplementor.Run()
IRunnableInvoker.n_Run(System.IntPtr jnienv,System.IntPtr本机__this)
(包装动态方法)Android.Runtime.DynamicMethodNameCounter.43(intptr,intptr)

现在, @ mfeingol会合理地询问为什么会有InvalidOperationException导致此崩溃。 我的意思是,从概念上讲,不允许目标被垃圾回收,为什么要使用弱引用?

我本人是.NET 3.0以来的WPF开发人员,并且知道绑定异常从来不会导致崩溃,而只是被记录下来。

所以我的问题是:
TypedBinding引发异常并且不仅仅忽略目标(如果已收集),是否有充分的理由?

还是绑定系统本身应该捕获所有绑定异常,并允许我们的开发人员吞并它们或做出适当反应?

对于我们的生产应用程序,这确实是一个重要的错误,如果需要,我将为我们创建一个中间的Xamarin.Forms版本来解决此问题。 但是为此,我想知道这可能产生哪些不良影响!

@bruzkovsky-您也可能对此感兴趣

所有58条评论

@mfeingol如果可以缩小这个范围,可以请附加一个演示此问题的小项目吗? 谢谢!

我将在本周末尝试这样做,但是这种需求很难重现。 根据您对代码的理解,您是否有任何线索?

看起来这与使用DataType的XAML绑定有关。

我现在正在旅行,但是暂时我的临时解决方法是禁用编译的绑定。

@mfeingol好的,听起来

我在iOS和Android上都看到了同样的问题。 我没有使用编译的绑定。

AppCenter问题:

TypedBinding 2[TSource,TProperty].Apply (System.Boolean fromTarget) TypedBinding 2 + PropertyChangedProxy [TSource,TProperty]。b__16_0()
线程+ RunnableImplementor.Run()
IRunnableInvoker.n_Run(System.IntPtr jnienv,System.IntPtr本机__this)
(包装动态方法)System.Object.26(intptr,intptr)

Xamarin表单项目,带有ViewModel的Xaml页面-包含ScrollView的网格-ScrollView包含标签。 很简单

@samhouts :我已经尽力了,但是无法在示例应用程序中重现该问题。 但是,我的生产应用程序确实具有100%的再现性。

我可以授予您团队中的某人对我的Azure DevOps项目的权限,以便他们可以重现该问题吗?

微软公司的shneuvil

您在: https :

复制步骤:

  1. git checkout 6698-repro并构建。 您可能需要将“外部”目录添加到您的NuGet目录列表中,以选择软件包。
  2. 运行该应用程序,然后从“行程”页面创建一个新行程。 将行程命名为“测试”,并保留所有默认值,但指定出发和到达的地点以及机场(例如SEA和LAS)。
  3. 点击行程以将其选中。
  4. 从汉堡菜单中,转到天气页面,确认正在显示有关位置的天气报告。
  5. 转到设置,将天气提供者从NWS更改为HERE。
  6. 返回天气页面。 您应该很快就会看到崩溃。 重新启动该应用程序应在天气页面中重新打开,刷新天气,并产生另一个崩溃。

如果由于某种原因您不能通过这种简单的行程进行复制,那么我将在更多的位置为您导出更复杂的选项。

@PureWeen :让我知道这是否对您不起作用。

@mtirona :对不起,我错过了您的评论。 奇怪的是,您没有使用已编译的绑定就看到了这一点。 我不认为您有一个简单的repro项目会按需触发崩溃?

@mfeingol此问题在我们的应用程序中随机出现。 我没有一个简单的按需重新创建-我在AppCenter中确实有数百起崩溃记录了该问题。 对于如何防止该问题的任何指示,我将不胜感激。

@mtirona :您是否100%确定您不在XAML中的任何地方使用x:DataType?

@mfeingol父页面上有x:DataType,所以我已经遍历整个应用程序并创建了一个分支,在其中删除了x:DataType。 我正在让我们的质量检查人员测试此分支是否崩溃,以查看是否可以解决问题。

我十分确定这与XamlC有关,除非您在自己的代码中创建TypedBindings(这些是Xaml编译器创建的_only_)

旁注:我使用过Xamarin Forms 3.6,并且我刚刚更新到了最新的4.1。 在我的应用程序首次运行时,我立即看到此崩溃,同时迅速将项目添加到分组的listview页面中。 因此,该问题在4.1.0.618606中仍然存在。

@PureWeen :我已经更新了上面的

@mfeingol你能帮我吗?

如果由于某种原因您不能通过这种简单的行程进行复制,那么我将在更多的位置为您导出更复杂的选项。

我尝试了您的脚步,但没有发生任何事故

好吧,所以@mfeingol我不确定您的数据如何或为什么排队导致此问题,但这是到目前为止我所知道的

TypedBindings使用对BindableObject的WeakReference,因此,如果它是唯一引用BindableObject的东西,则它将丢失该引用。

这是崩溃的代码
C#
如果(!_weakTarget.TryGetTarget(out target))
抛出新的InvalidOperationException();


If you look at the output of the application while it's running the exception always happens after a GC which makes sense why you are only seeing this after loading a larger data set.

As a test with the TypeBindings I created a nuget where it stores the source and target to a local variable just to see what would happen 

```C#
            _weakSource.SetTarget(source);
            _weakTarget.SetTarget(bindObj);
            _bindObj = bindObj;
            _source = source;
            ApplyCore(source, bindObj, targetProperty);
        }

        BindableObject _bindObj;
        object _source;

如果我这样做,崩溃就不会发生。

我的想法是,您的数据以某种方式到达某个地方,唯一引用绑定到ViewCell的LocationDayWeatherViewModel实例的就是TypeBinding就是这样。 如果这在某种程度上是我们这边还是您这边的例外,我还没有完全找到答案。 您能确定要维护对绑定到ListView的所有已创建LocationLocationWeatherViewModel的引用吗?

感谢您查看这个! 这个问题很难在完整的应用程序外部重现,因此有意义的是涉及弱引用。 我想知道是否将内存压力添加到一个简单的repro中是否会导致相同的问题。

无论如何,viewmodel唯一无法引用LocationDayWeatherViewModel实例的情况是在天气刷新期间,其中代码在插入新鲜项目之前清除了绑定的项目ObservableCollection。 如果要设置bps,这种情况会在ExpandableGroupCollectionViewModel.Refresh深处发生。

但是,我认为清除绑定的ObservableCollection应该是安全的操作,而且对于我来说,为什么XF绑定将使用弱引用并不明显。 听起来这完全是一场比赛。

另外:在清除Refresh之前,我尝试将this的项目复制到临时列表中,但是令人惊讶的是,这似乎无法解决该问题。 我确实在方法末尾引用了该列表,以确保GC也不会对其进行核对。 我想如果XF尝试使用过时的绑定“稍后”,这将是有道理的,并且这表明应用程序没有稳定绑定引用的好方法。 但是我可能会误会事情。

(是的,天气/扩展器代码有些失控。我希望XF具有本机的Expander控件...)

我认为增加内存压力或仅调用GC.Collect可能会在较小的项目中重现该问题。 这也可能是因为TypedBinding上的OnPropertyChanged被封送至UI线程

https://github.com/xamarin/Xamarin.Forms/blob/7cc9a282bdeb76405c793574ebe0d096072f4228/Xamarin.Forms.Core/TypedBinding.cs#L275

因此,我想清楚了会发生什么

UI线程上的PropertyChanged队列
明确
GC
WeakReference失去参考
PropertyChanged现在可以解决并引发异常

也许与这个问题有关?
https://github.com/xamarin/xamarin-android/issues/2049

@StephaneDelcroix此时可能会有一些其他见解:-)

昨晚我有一点空闲时间,我尝试在简化后的副本中将GC.Collect()调用后添加到Clear() 。 不幸的是,我无法以这种方式重现该问题。

真是个好电话。 但可悲的是,即使在那之后, Clear()也不会触发再现。

所以退后一步...这应该如何工作? 如果绑定持有弱引用,则根据定义可以对该对象进行GC处理。 因此,这是有可能发生的,并且XF不应抛出不可捕获的异常。 相反,它可能应该只是忽略PropertyChanged通知,并信任应用程序知道它在做什么。 我的意思是,它还能做什么?

您可以附上您要尝试重新创建的repro吗?

今晚我将附加代码。 它基本上是您已经看到的应用程序内复制,并提取到独立的应用程序中。 但是我还没有看到问题的根源。

@PureWeen :我还能做些什么来帮助诊断吗?

@mfeingol目前不可用,除非您对如何使用独立应用程序进行复制有任何想法。 将其缩小到较大的区域中有点棘手,因此解决该问题时我们会稍微慢一点。

正如我在https://github.com/xamarin/Xamarin.Forms/issues/6698#issuecomment -519359760中提到的那样,我们是否有可能在概念上进行思考? 还是在实际上造成问题的原因上仍然缺少片段?

我遇到了同样的问题,也无法轻松地重现)-:

@ysmoradi :我不认为您能够上传一个简单的副本?

即使在我的生产应用中也很难复制!

我在生产中也有复制品,但是根据@PureWeen ,如果没有简单的复制品,他们很难理解问题。 我尝试过但未能产生。 :-(

我认为在异常消息中包含属性名称+视图类型名称+绑定上下文的类型名称是一个好主意,这样我们就可以获得更好的见解。

我使用xamarin形式4.2.0.709249遇到了完全相同的问题,iOS和Android。
我有一个使用DataTemplate的ListView来可视化在我的xaml中定义的对象。
我在xaml页面上设置了DataType,然后在listview数据模板上设置了另一个。

我不必在要绑定的列表上调用clear或replace或anyting,调用GC.Collect似乎已经足够,并且等待另一个方法来给我上面的错误。 (如果我没有GC.Collect调用,它很少会失败,但是偶尔会执行一次,并且调用成功加载,但是刷新失败。)

但是,如果删除了viewModel.IsBusy和listview.IsRefreshing之间的绑定,我确实发现了一些有趣的东西(但刷新指示器在拉动后仍然保持运行,当然刷新了)。

另外,如果删除内容页面上的数据类型,而仅在数据模板上进行设置,则错误也消失了,可以在列表视图IsRefresing上使用绑定。

总结一下我需要在生产应用程序中进行复制的内容:

  1. 在ContentPage上设置DataType
  2. 在ListView中的IsRefreshing上设置绑定
  3. 进行GC.Collect调用,然后等待Task.Delay(250); 在绑定到listview RefreshCommand的方法中

@shoyheim :您可以在此处发布一个简单的

@shoyheim :您可以在此处发布一个简单的

@mfeingol对不起,我一直在测试/调试生产代码。 我会看看我是否可以抽出一些时间来重现错误...

@shoyheim :你有运气吗?

@mfeingol
抱歉,我尝试过,但是每当进行简单的复制时,都无法使其崩溃,但生产应用程序却不断崩溃。
现在,我删除了所有已编译的绑定,只在xaml文件中使用了运行时绑定,崩溃消失了。
我花了很多时间试图找出问题所在,而我唯一能确定的是,使用ListView和“ isRefreshing”上的绑定来显示刷新列表与使用之间存在联系编译的绑定...崩溃似乎也发生在垃圾回收的时间。

1-绑定上下文(视图模型)的属性被更改。
2-我们弹出视图,使其被破坏。
3- GC被调用。

  1. Binding.Apply被调用,并尝试获取已丢失的访问所需对象,因此抛出InvalidOperationException。
    您可能会问为什么这么晚才执行步骤4? 因为它是在Device.BeginInvokeOnMainThread中调用的,所以这样的操作将被添加到主线程的操作队列列表的末尾。
    我能够通过向xf提供自定义PlatformServices来处理该异常,并且不再崩溃,但是它抛出800多次异常! 对于几乎所有类型的已绑定页面的绑定

@ysmoradi :我花了一些时间尝试重现您的步骤,但无法触发任何崩溃。 我不认为您有一个示例项目。

我之前说过,我没有任何简单的回购协议,它正在我的生产应用程序中发生,并且它也是随机发生的。
第一次开始创建存储库时,我并不了解很多事情,但是明天我将尝试使用新的假设来创建另一个。
另一个可能有用的技巧:根据我的假设,启用并发GC会增加重现崩溃的机会。 因为它可以在单独的线程上收集对象。 我们还需要在单独的线程/任务上更改视图模型的属性,因为Device.BeginInvokeOnMainThread仅在非主线程上调用该操作时,才将操作传递到主线程队列的末尾。
请再试一次,如果您发现了任何问题,请告诉我,我明天再试。

我启用了并发GC。 根据您的建议,我正在使用的代码段是这样做的:

            Page1 page = new Page1();
            await this.Navigation.PushModalAsync(page);
            await Task.Run(() => { page.TXT = "Foo"; });
            await this.Navigation.PopModalAsync();

            GC.Collect();
            GC.WaitForPendingFinalizers();

            GC.Collect();
            GC.WaitForPendingFinalizers();

TXT是Page1上的一个属性,使用BindableProperty实现。 Page1正在使用编译的绑定。

仍然没有运气。

在我的生产应用中,这里也随机遇到相同的问题。 在经历了性能指南中建议的在各处设置x:Datatype的繁琐过程之后,不能说我很高兴由于这个问题而不得不将它们全部删除。

如果可以成功运行,我将使用repro应用程序对此进行更新。

注意:我怀疑这是相关的,但似乎我只是在开始使用压缩布局后才开始看到该问题。 可能是巧合,因为问题是非常随机的,但谁知道。

刚刚使用编译的绑定将我的应用程序更新为MVVM,现在得到了相同的错误。
运行最新的Xamarin.Forms:4.2.0.848062

使用以下配置:
image

也没有重复步骤(此版本的应用处于测试版状态,而且我已经通过AppCenter获得了两个报告)。
可以共享应用程序存储库,但是如果没有复制步骤,我想这不会有太大帮助。

我可能不了解整个情况,但这不是简单的解决方案,就是简单地取消应用并在目标被GC时返回,就像在TypedBinding.cs中没有DO_NOT_CHECK_FOR_BINDING_REUSE定义的情况下那样吗? 我不认为在这里投掷是个好主意。

@fmanseau :我有相同的看法。 @PureWeen?

同样,如果有帮助,Prism回购中与此相关的问题似乎具有复制步骤(它需要Prism应用程序,但很容易遵循类似的模式而没有)。

https://github.com/PrismLibrary/Prism/issues/1688

@StephaneDelcroix @ kingces95 @wachs
你们似乎落后于TypedBinding实现。

正如你可以在这个线程看到,很多开发者那里(包括我),然后现在有自己的应用程序崩溃,因为的InvalidOperationException被抛出TypedBinding
@samhouts在她的假设中似乎是正确的,在GC启动并删除了targetTypedBinding (很可能在我们的应用程序中,我们有一个很大的ListView和许多复杂的DataTemplates ),则TypedBinding抛出一个InvalidOperationException ,它永远不会被捕获,并导致Android(以及其他任何平台)上的应用程序崩溃??) 像这样:

TypedBinding 2[TSource,TProperty].Apply (System.Boolean fromTarget) System.InvalidOperationException: Operation is not valid due to the current state of the object. Stack traces TypedBinding 2 [TSource,TProperty] .Apply(System.Boolean fromTarget)
TypedBinding`2 + PropertyChangedProxy [TSource,TProperty]。b__16_0()
线程+ RunnableImplementor.Run()
IRunnableInvoker.n_Run(System.IntPtr jnienv,System.IntPtr本机__this)
(包装动态方法)Android.Runtime.DynamicMethodNameCounter.43(intptr,intptr)

现在, @ mfeingol会合理地询问为什么会有InvalidOperationException导致此崩溃。 我的意思是,从概念上讲,不允许目标被垃圾回收,为什么要使用弱引用?

我本人是.NET 3.0以来的WPF开发人员,并且知道绑定异常从来不会导致崩溃,而只是被记录下来。

所以我的问题是:
TypedBinding引发异常并且不仅仅忽略目标(如果已收集),是否有充分的理由?

还是绑定系统本身应该捕获所有绑定异常,并允许我们的开发人员吞并它们或做出适当反应?

对于我们的生产应用程序,这确实是一个重要的错误,如果需要,我将为我们创建一个中间的Xamarin.Forms版本来解决此问题。 但是为此,我想知道这可能产生哪些不良影响!

@bruzkovsky-您也可能对此感兴趣

此外, @ StephaneDelcroix @ kingces95 @wachs ,我可以看到一个标志
DO_NOT_CHECK_FOR_BINDING_REUSE
到底是为了什么?

我非常想用DO_NOT_CHECK_FOR_BINDING_REUSE设置为true来编译Xamarin.Forms来摆脱这个错误。
但是其背后的思考过程是什么? 必须有充分的理由将此标志存在,对吗?

这只是在带有ListView和DataTemplateSelector的简单ContentPage中发生的。
关于此问题是否有任何更新?
如果此问题尚未解决,建议当前为什么使用编译的绑定?
https://docs.microsoft.com/es-es/xamarin/xamarin-forms/app-fundamentals/data-binding/compiled-bindings

@mrjavicho :您是否有可能发布一个简单的项目来始终如一地重现问题?

我能够使用此示例经常重现该问题。
https://github.com/usausa/TypedBindingIssue

运行该应用程序,然后单击“测试”按钮。
此外,如果您删除MainPage.Cleanup()中的注释,则不会发生此问题。

这是我使用@usausa的代码看到的堆栈跟踪。 无法确定是否与上述问题相同,但这绝对是一个问题:

    0x16 in Xamarin.Forms.Internals.TypedBinding<TypedBindingIssueApp.View1ViewModel,string>.Apply at D:\a\1\s\Xamarin.Forms.Core\TypedBinding.cs:99,5  C#  Annotated Frame
    0x7 in Xamarin.Forms.Internals.TypedBinding<TypedBindingIssueApp.View1ViewModel,string>.PropertyChangedProxy.<OnPropertyChanged>b__16_0 at D:\a\1\s\Xamarin.Forms.Core\TypedBinding.cs:277,31   C#  Annotated Frame
    0x29 in Xamarin.Forms.DispatcherExtensions.Dispatch at D:\a\1\s\Xamarin.Forms.Core\DispatcherExtensions.cs:53,6 C#  Annotated Frame
    0x3F in Xamarin.Forms.Internals.TypedBinding<TypedBindingIssueApp.View1ViewModel,string>.PropertyChangedProxy.OnPropertyChanged at D:\a\1\s\Xamarin.Forms.Core\TypedBinding.cs:277,5    C#  Annotated Frame
    0x15 in Xamarin.Forms.BindingExpression.WeakPropertyChangedProxy.OnPropertyChanged at D:\a\1\s\Xamarin.Forms.Core\BindingExpression.cs:645,6    C#  Annotated Frame
>   0x14 in TypedBindingIssueApp.NotificationObject.RaisePropertyChanged at C:\Operations\Build\External\TypedBindingIssue\TypedBindingIssueApp\TypedBindingIssueApp\NotificationObject.cs:13,13    C#  Symbols loaded.
    0x5D in TypedBindingIssueApp.LongLifecycleModel.Next at C:\Operations\Build\External\TypedBindingIssue\TypedBindingIssueApp\TypedBindingIssueApp\LongLifecycleModel.cs:19,13    C#  Symbols loaded.
    0x2A in TypedBindingIssueApp.MainPage.Button_OnClicked at C:\Operations\Build\External\TypedBindingIssue\TypedBindingIssueApp\TypedBindingIssueApp\MainPage.xaml.cs:29,17   C#  Symbols loaded.
    0x6 in System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext at /Users/builder/jenkins/workspace/archive-mono/2019-08/android/release/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1092,17   C#  Annotated Frame
    0x73 in System.Threading.ExecutionContext.RunInternal at /Users/builder/jenkins/workspace/archive-mono/2019-08/android/release/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:968,17   C#  Annotated Frame
    0x4 in System.Threading.ExecutionContext.Run at /Users/builder/jenkins/workspace/archive-mono/2019-08/android/release/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:910,13    C#  Annotated Frame
    0x32 in System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run at /Users/builder/jenkins/workspace/archive-mono/2019-08/android/release/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1073,25 C#  Annotated Frame
    0x6 in System.Threading.Tasks.SynchronizationContextAwaitTaskContinuation.<>c.<.cctor>b__7_0 at /Users/builder/jenkins/workspace/archive-mono/2019-08/android/release/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/TaskContinuation.cs:379,78  C#  Annotated Frame
    0xC in Android.App.SyncContext. C#  Annotated Frame

再现现场! 我注意到的第一件事是崩溃是在完全随机的时间发生的,有时会多次按下按钮并等待,所以我对其进行了一些微调以使其更快崩溃(在29个实体之后一致):
typedbindingrepro

只需将PC事件引发80次,如下所示:
c# for (var i = 0; i < 80; i++) RaisePropertyChanged(nameof(Entity));

这会将更多事件安排给调度程序,从而增加故障率。

View1View2类禁用XAML编译时,在BindingExpression.cs中会抛出NullReferenceException

image

仍在寻找简单的解决方法...

此页面是否有帮助?
0 / 5 - 0 等级