我有一个基于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”如下所示: 使用系统; 使用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对象已经完成,我的绑定试图调用它?
答案 0 :(得分:2)
跟随提供的代码片段有点困难,但我猜你所看到的问题是由于你正在回收cell
并且每次回收它时你都是:< / p>
解决此问题的一种方法可能是使用WithClearBindingKey
流畅方法来清除这些绑定。
例如,如果绑定创建为:
var set = this.CreateBindingSet<Cell, CellViewModel>();
set.Bind(text).To(vm => vm.TextValue).WithClearBindingKey("MyDynamicBindings");
set.Apply();
然后只需使用以下命令清除使用此标记创建的绑定:
this.ClearBindings("MyDynamicBindings");
答案 1 :(得分:2)
感谢stuart,但是我只是粘贴了一些我写的代码,因为我的listadapter已经变得非常复杂了。所以实际上我已经在回收我在代码中创建的控件了。 然而,我似乎找到了解决方案。 我看到我的应用程序最近崩溃,它们似乎都是因为某些绑定调用了android小部件(EditText,Spinner,Checkbox等)的setter导致了本机错误。 所以我将跟踪消息放入&#34; Dispose&#34;和#34; JavaFinalize&#34;方法,事实证明,错误总是发生在一些&#34; JavaFinalize&#34;调用。 所以我所做的是将以下代码添加到所有控件中,我将其作为&#34; Bindable&#34;实现。 (如上面代码段中的BindableEditText)
protected override void JavaFinalize()
{
if (this.BindingContext != null)
this.BindingContext.ClearAllBindings();
base.JavaFinalize();
}
这样就完成了工作!
警告:我还必须将此添加到&#34; MvxListItemView&#34;。那么也许它应该被添加到mvvmcross源中呢?