我们正在使用mvvmcross 3.1.1。但是在android版本中每隔一段时间就会出现一个问题。抛出以下异常但是我们无法每次都重现。我还添加了自定义适配器和列表视图。如果您发现任何可能导致异常的事情,请告诉:) 数据通过xml绑定。
java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(16908298, class cirrious.mvvmcross.binding.droid.views.MvxListView) with Adapter(class cirrious.mvvmcross.binding.droid.views.MvxAdapter)]
at android.widget.ListView.layoutChildren(ListView.java:1656)
at android.widget.AbsListView.onTouchUp(AbsListView.java:3904)
at android.widget.AbsListView.onTouchEvent(AbsListView.java:3715)
at android.widget.ListView.onTouchEvent(ListView.java:4123)
at android.view.View.dispatchTouchEvent(View.java:7811)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2210)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1945)
at android.widget.AbsListView.dispatchTouchEvent(AbsListView.java:7569)
at android.widget.ListView.dispatchTouchEvent(ListView.java:4494)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2169)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1613)
at android.app.Activity.dispatchTouchEvent(Activity.java:2539)
at cirrious.crosscore.droid.views.MvxEventSourceActivity.dispatchTouchEvent(MvxEventSourceActivity.java)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2117)
at android.view.View.dispatchPointerEvent(View.java:8005)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4274)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4153)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3688)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3738)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3707)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3818)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3715)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3875)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3688)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3738)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3707)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3715)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3688)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5947)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5920)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5883)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6031)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:214)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:138)
at android.os.Looper.loop(Looper.java:134)
at android.app.ActivityThread.main(ActivityThread.java:5872)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:674)
at dalvik.system.NativeStart.main(Native Method)
自定义适配器
namespace MissionsApp.App.Droid.Controls
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using Android.Content;
using Android.Views;
using Cirrious.MvvmCross.Binding.Droid.Views;
using Cirrious.MvvmCross.ViewModels;
using MissionsApp.App.Model;
using MissionsApp.Core.ViewModels.Items;
public class MvxSectionAdapter : MvxAdapter
{
private int _itemTemplateHeaderId;
private int _itemTemplateFooterId;
public MvxSectionAdapter(Context context)
: base(context)
{
}
public int ItemTemplateHeaderId
{
get { return this._itemTemplateHeaderId; }
set
{
if (this._itemTemplateHeaderId == value)
return;
this._itemTemplateHeaderId = value;
// since the template has changed then let's force the list to redisplay by firing NotifyDataSetChanged()
if (this.ItemsSource != null)
this.NotifyDataSetChanged();
}
}
public int ItemTemplateFooterId
{
get { return this._itemTemplateFooterId; }
set
{
if (this._itemTemplateFooterId == value)
return;
this._itemTemplateFooterId = value;
// since the template has changed then let's force the list to redisplay by firing NotifyDataSetChanged()
if (this.ItemsSource != null)
this.NotifyDataSetChanged();
}
}
public bool UseLastItemAsFooter { get; set; }
public MvxSectionListView ListView { get; set; }
public override void NotifyDataSetChanged()
{
this.NotifyDataSetChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public override void NotifyDataSetChanged(NotifyCollectionChangedEventArgs e)
{
base.NotifyDataSetChanged(e);
var handler = this.DataSetChanged;
if (handler != null)
handler(this, e);
}
protected override void SetItemsSource(IEnumerable value)
{
if (value != null)
{
var list = new List<object>();
foreach (ISectionViewModel section in value)
{
list.Add(new MvxHeaderSectionListItem(section as MvxViewModel));
for (int i = 0; i < section.Count; i++)
{
MvxViewModel viewModel = (MvxViewModel) section.Get(i);
var islast = i == section.Count - 1;
list.Add(islast && this.UseLastItemAsFooter
? (object) new MvxFooterSectionListItem(viewModel)
: viewModel);
}
if (!this.UseLastItemAsFooter && this.ItemTemplateFooterId > 0)
{
list.Add(new MvxFooterSectionListItem(section as MvxViewModel));
}
}
base.SetItemsSource(list);
}
}
protected override View GetBindableView(View convertView, object dataContext, int templateId)
{
var header = dataContext as MvxHeaderSectionListItem;
if (this.ItemTemplateHeaderId > 0 && header != null)
{
return base.GetBindableView(convertView, header.ViewModel, this.ItemTemplateHeaderId);
}
var footer = dataContext as MvxFooterSectionListItem;
if (this.ItemTemplateFooterId > 0 && footer != null)
{
return base.GetBindableView(convertView, footer.ViewModel, this.ItemTemplateFooterId);
}
if (this.ListView != null)
{
if (convertView != null)
{
convertView.Click -= this.ViewOnClick;
}
var view = base.GetBindableView(convertView, dataContext, templateId);
view.Click += this.ViewOnClick;
var vm = dataContext as MissionListItemViewModel;
var invite = vm.Item as MissionInviteStatus;
if (invite != null && invite.GetType() == typeof(MissionInviteStatus)&&invite.UserAccepted)
{
var headerView = view.FindViewById<TextViewWithFont>(Resource.Id.button1);
headerView.SetBackgroundResource(Resource.Drawable.button_red);
}
else
{
var headerView = view.FindViewById<TextViewWithFont>(Resource.Id.button1);
headerView.SetBackgroundResource(Resource.Drawable.button_grey);
}
return view;
}
return base.GetBindableView(convertView, dataContext, templateId);
}
private void ViewOnClick(object sender, EventArgs eventArgs)
{
var viewItem = sender as MvxBaseListItemView;
if (this.ListView.ItemClick == null)
return;
var item = viewItem.DataContext;
if (item == null)
return;
if (!this.ListView.ItemClick.CanExecute(item))
return;
this.ListView.ItemClick.Execute(item);
}
public event EventHandler<NotifyCollectionChangedEventArgs> DataSetChanged;
}
public class MvxHeaderSectionListItem
{
public MvxHeaderSectionListItem(MvxViewModel section)
{
this.ViewModel = section;
}
public MvxViewModel ViewModel { get; set; }
}
public class MvxFooterSectionListItem
{
public MvxFooterSectionListItem(MvxViewModel section)
{
this.ViewModel = section;
}
public MvxViewModel ViewModel { get; set; }
}
}
自定义列表视图
namespace Cirrious.MvvmCross.Binding.Droid.Views
{
using Android.Content;
using Android.Util;
using Android.Views;
using Cirrious.MvvmCross.Binding.Droid.ResourceHelpers;
using Cirrious.MvvmCross.Binding.Droid.Views;
using MissionsApp.App.Droid;
using MissionsApp.App.Droid.Controls;
public class MvxSectionListView : MvxListView
{
public MvxSectionListView(Context context, IAttributeSet attrs)
: this(context, attrs, new MvxSectionAdapter(context))
{
}
public MvxSectionListView(Context context, IAttributeSet attrs, MvxSectionAdapter adapter)
: base(context, attrs,adapter)
{
// adapter.ItemTemplateId = MvxAttributeHelpers.ReadListItemTemplateId(context, attrs);
adapter.ItemTemplateHeaderId = MvxAttributeHelpers.ReadAttributeValue(context, attrs, MvxAndroidBindingResource.Instance.ListViewStylableGroupId, Resource.Styleable.MvxListView_MvxItemHeaderTemplate);
adapter.ItemTemplateFooterId = MvxAttributeHelpers.ReadAttributeValue(context, attrs, MvxAndroidBindingResource.Instance.ListViewStylableGroupId, Resource.Styleable.MvxListView_MvxItemFooterTemplate);
adapter.ListView = this;
//Adapter = adapter;
}
public override bool PerformItemClick(View view, int position, long id)
{
return true;
//return base.PerformItemClick(view, position, id);
}
}
}
答案 0 :(得分:0)
我的解决方案是在创建MvxListView时设置自定义适配器。这可以通过继承MvxListView,然后覆盖ctor,并在那里设置自定义适配器来完成。