带有mvxlistview和mvx适配器的java.lang.IllegalStateException

时间:2014-07-11 11:35:49

标签: android xamarin xamarin.android mvvmcross

我们正在使用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);
        }
    }
}

1 个答案:

答案 0 :(得分:0)

我的解决方案是在创建MvxListView时设置自定义适配器。这可以通过继承MvxListView,然后覆盖ctor,并在那里设置自定义适配器来完成。