2

我有一个基于 Xamarin 和 MvvmCross 的 Android 应用程序。在该应用程序中,有一个我自己创建的带有 ExpandableListView 的视图。现在这个列表显示了几个项目,它们使用 MvvmCross 绑定到它们的 DataContext。但是,由于各个 ListItemViews 的视图差异很大,这些 ListItemViews 的一部分是在 ExpandedListViewAdapter 中以编程方式生成的。这像这样工作:

        public override View GetChildView(int groupPosition, int childPosition, bool isLastChild, View convertView, ViewGroup parent)
        {
            object child = GetRawChild(groupPosition, childPosition);

            if (child == null)
            {
                MvxBindingTrace.Trace(MvxTraceLevel.Error, "GetView called for group that seems to have no itemssource: it is null");
                return null;
            }

            var view = (MvxListItemView)GetBindableView(convertView, child, ChildItemTemplateId);
            var placeholder = view.FindViewById<BindableFrameLayout>(Resource.Id.placeholder);

            var questionVm = (QuestionViewModel)child;

            if(questionVm.ViewType == "TextBox")
            {
                    placeholder.RemoveAllViews();

                    var text = new BindableEditText(context);

                    text.InputType = InputType;
                    text.SetRawInputType(InputType);
                    placeholder.RemoveAllViews();
                    placeholder.AddView(text);

                    var answer = questionVm.Children.First();
                    text.DataContext = answer;
                    var binding = text.CreateInlineBindingTarget<AnswerViewModel>();
                    text.Bind(binding, et => et.Text, vm => vm.Model.Value, (string)null, null, null,
                              MvxBindingMode.TwoWay);
            }
            else if(questionVm.ViewType == "Spinner")
            {
                    placeholder.RemoveAllViews();

                    MvxSpinner spinner = new MvxSpinner(context, null);
                    spinner.ItemsSource = questionVm.Children;
                    spinner.ItemSelected += (sender, args) =>
                    {
                        for (int i = 0; i < questionVm.Children.Count; i++)
                        {
                            var answer = (IAnswerViewModel)questionVm.Children[i];
                            if (i == spinner.SelectedItemPosition)
                                answer.IsSelected = true;
                            else
                                answer.IsSelected = false;
                        }
                    };
                    spinner.Bind(bindings, ctrl => ctrl.ItemsSource, vm => vm.Children, (string)null, null, null, MvxBindingMode.OneWay);
                    var chosenAnswer = questionVm.Children.Cast<IAnswerViewModel>().FirstOrDefault(@a => @a.IsSelected == true);
                    if (chosenAnswer != null)
                        spinner.SetSelection(questionVm.Children.Cast<IAnswerViewModel>().ToList().IndexOf(chosenAnswer));
                    placeholder.AddView(spinner);
            }

...并且“BindableEditText”如下所示: using System; 使用Android.Content;使用 Android.Runtime;使用 Android.Views;使用 Android.Widget;使用Android.Util;使用 Cirrious.MvvmCross.Binding.Droid.BindingContext;使用 Cirrious.MvvmCross.Binding.BindingContext;

        namespace iCL.Filler.Droid.Controls
        {
            public class BindableEditText : EditText, IMvxBindingContextOwner
            {
                private readonly IMvxAndroidBindingContext _bindingContext;

                public BindableEditText(Context context)
                    : base(context)
                {
                    _bindingContext = new MvxAndroidBindingContext(context, null);
                }

                public BindableEditText(Context context, IAttributeSet attributes)
                    : base(context, attributes)
                {
                    _bindingContext = new MvxAndroidBindingContext(context, null);
                }

                public BindableEditText(Context context, IAttributeSet attributes, int defStyle)
                    : base(context, attributes, defStyle)
                {
                    _bindingContext = new MvxAndroidBindingContext(context, null);
                }

                public BindableEditText(IntPtr javaReference, JniHandleOwnership transfer)
                    : base(javaReference, transfer)
                {
                }

                protected IMvxAndroidBindingContext AndroidBindingContext
                {
                    get { return _bindingContext; }
                }

                public IMvxBindingContext BindingContext
                {
                    get { return _bindingContext; }
                    set { throw new NotImplementedException("BindingContext is readonly in the radio button"); }
                }

                protected override void Dispose(bool disposing)
                {
                    if (disposing)
                    {
                        this.BindingContext.ClearAllBindings();
                    }

                    base.Dispose(disposing);
                }

                public override void SetText(Java.Lang.ICharSequence text, TextView.BufferType type)
                {
                    try
                    {
                        base.SetText(text, type);
                    }
                    catch (Exception ex)
                    {

                    }
                }

                protected View Content { get; set; }

                public object DataContext
                {
                    get { return _bindingContext.DataContext; }
                    set { _bindingContext.DataContext = value; }
                }
            }
        }

所以我的问题是,有时,当我滚动并单击列表视图时,会出现如下运行时错误,并且我的应用程序“崩溃”,这实际上意味着它导航回上一个屏幕。

10-29 14:04:37.140 D/dalvikvm( 5989): GC_EXPLICIT freed 751K, 11% free 11369K/12679K, paused 0ms+1ms
10-29 14:04:39.970 D/dalvikvm( 5989): GC_FOR_ALLOC freed 715K, 16% free 10692K/12679K, paused 5ms
10-29 14:04:41.831 E/mono-rt ( 5989): Stacktrace:
10-29 14:04:41.831 E/mono-rt ( 5989): 
10-29 14:04:41.831 E/mono-rt ( 5989):   at <unknown> <0xffffffff>
10-29 14:04:41.831 E/mono-rt ( 5989):   at (wrapper managed-to-native) object.wrapper_native_0xb71f1820 (intptr,intptr,intptr,intptr,Android.Runtime.JValue[]) <IL 0x00124, 0xffffffff>
10-29 14:04:41.831 E/mono-rt ( 5989):   at Android.Runtime.JNIEnv.CallNonvirtualVoidMethod (intptr,intptr,intptr,Android.Runtime.JValue[]) [0x00000] in /Users/builder/data/lanes/monodroid-mlion-monodroid-4.8.2-branch/a25a31d0/source/monodroid/src/Mono.Android/src/Runtime/JNIEnv.g.cs:612
10-29 14:04:41.831 E/mono-rt ( 5989):   at Android.Widget.CompoundButton.set_Checked (bool) [0x00070] in /Users/builder/data/lanes/monodroid-mlion-monodroid-4.8.2-branch/a25a31d0/source/monodroid/src/Mono.Android/platforms/android-14/src/generated/Android.Widget.CompoundButton.cs:255
10-29 14:04:41.831 E/mono-rt ( 5989):   at (wrapper runtime-invoke) <Module>.runtime_invoke_void__this___byte (object,intptr,intptr,intptr) <IL 0x00054, 0xffffffff>
10-29 14:04:41.831 E/mono-rt ( 5989):   at <unknown> <0xffffffff>
10-29 14:04:41.831 E/mono-rt ( 5989):   at (wrapper managed-to-native) System.Reflection.MonoMethod.InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&) <IL 0x00030, 0xffffffff>
10-29 14:04:41.831 E/mono-rt ( 5989):   at System.Reflection.MonoMethod.Invoke (object,System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo) <IL 0x0004a, 0x0016f>
10-29 14:04:41.831 E/mono-rt ( 5989):   at System.Reflection.MethodBase.Invoke (object,object[]) <IL 0x00006, 0x00048>
10-29 14:04:41.831 E/mono-rt ( 5989):   at Cirrious.MvvmCross.Binding.Bindings.Target.MvxPropertyInfoTargetBinding.SetValueImpl (object,object) <IL 0x0001a, 0x000a7>
10-29 14:04:41.831 E/mono-rt ( 5989):   at Cirrious.MvvmCross.Binding.Bindings.Target.MvxConvertingTargetBinding.SetValue (object) <IL 0x0008c, 0x002b1>
The program 'Mono' has exited with code 0 (0x0).

我不知道问题可能是什么....可能是某个 Java 对象已经完成,而我的绑定尝试调用它吗?

4

2 回答 2

3

遵循提供的代码片段有点困难,但我猜您看到的问题是由于您正在回收的事实,cell并且每次回收它时,您都是:

  • 创建一个新的单元格子视图,
  • 创建一个新的绑定,
  • 清除旧的子视图
  • 删除旧绑定。

解决此问题的一种方法可能是使用WithClearBindingKeyfluent 方法来允许您清除这些绑定。

例如,如果绑定创建为:

 var set = this.CreateBindingSet<Cell, CellViewModel>();
 set.Bind(text).To(vm => vm.TextValue).WithClearBindingKey("MyDynamicBindings");
 set.Apply();

然后可以使用以下方法清除使用此标记创建的绑定:

 this.ClearBindings("MyDynamicBindings");
于 2013-10-29T15:16:08.723 回答
2

谢谢斯图尔特,但我只粘贴了一些我写的代码,因为我的 listadapter 已经变得相当复杂了。所以实际上我已经在回收我在代码中创建的控件了。但是,我似乎找到了解决方案。我最近看到我的应用程序崩溃了,它们似乎都是因为某些绑定调用了 android 小部件(EditText、Spinner、Checkbox 等)的设置器,导致了本机错误。所以我将跟踪消息放入“Dispose”和“JavaFinalize”方法中,事实证明,错误总是发生在一些“JavaFinalize”调用之后。所以我所做的是将以下代码添加到所有控件中,我将其实现为“可绑定”的东西。(就像上面代码片段中的 BindableEditText 一样)

    protected override void JavaFinalize()
    {
        if (this.BindingContext != null)
            this.BindingContext.ClearAllBindings();
        base.JavaFinalize();
    }

所以这完全可以完成工作!

警告:我还必须将此添加到“MvxListItemView”。那么也许它也应该添加到 mvvmcross 源中?

于 2013-11-03T12:15:15.137 回答