2013-10-29 81 views
1

我有一個基於Xamarin和MvvmCross的Android應用程序。 在那個應用程序中有一個我自己創建的ExpandableListView視圖。 現在這個列表顯示了幾個項目,它們使用MvvmCross綁定到它們的DataContext。 但是,由於各個ListItemViews的視圖差別很大,因此這些ListItemViews的一部分以編程方式在ExpandedListViewAdapter中生成。 這就像這樣:MVVMCross綁定崩潰Android應用程序

 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」 看上去像下面這樣: 使用系統;使用Android.Content的 ;使用Android.Runtime的 ;使用Android.Views的 ;使用Android.Widget的 ;使用Android.Util的 ; using Cirrious.MvvmCross.Binding.Droid.BindingContext; using 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對象已經敲定,和我的綁定嘗試打電話了嗎?

回答

2

感謝司徒,但onestly我只粘貼一些我編寫的代碼我的listadapter變得相當複雜了。所以實際上我已經在回收我在代碼中創建的控件了。 但是,似乎我找到了解決方案。 我最近看到我的應用程序崩潰,它們都似乎是因爲某些綁定調用了導致本機錯誤的android小部件(EditText,Spinner,Checkbox等)的setter。 因此,我將跟蹤消息放入了「Dispose」和「JavaFinalize」方法,事實證明,錯誤總是發生在一些「JavaFinalize」調用之後。 所以我所做的就是將以下代碼添加到所有控件中,我將其實現爲「Bindable」。(如上面代碼段中的BindableEditText)

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

這樣完全可以完成這項工作!

警告:我還必須將此添加到「MvxListItemView」。所以也許它應該被添加到mvvmcross來源呢?

2

這是一個有點難以遵循代碼片段提供的,但我猜想,你所看到的問題是由於這樣的事實,你是回收cell,並且每次回收它的時候你是:

  • 創建一個新的細胞子視圖,
  • 創建一個新的綁定,
  • 清除舊的子視圖
  • 刪除舊的綁定。

解決此問題的一種方法可能是使用流利方法WithClearBindingKey來清除這些綁定。

例如,如果作爲創建綁定:

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

然後就用這個標籤創建的綁定可以使用被清除:

this.ClearBindings("MyDynamicBindings");