'Jobject' no debe ser IntPtr.Zero al ajustar el texto textview en MonoDroid
Estoy usando MvvmCross con MonoDroid.
En un temporizador en el viewmodel, cada minuto que llamo RaisePropertyChanged("MinutesRemaining")
– MinutesRemaining
es un entero que especifica la duración en minutos hasta que termine la entrada actual (y sí, esto se llama en el subproceso de interfaz de usuario).
- ¿Cómo popule ListView con elementos de la base de datos en Xamarin?
- GetAllNetworkInterfaces () lanza la excepción
- Simulaciones de desarrollo de Android de MonoDroid
- Interfaz de JavaScript de Monodroid
- Android - ListView onItemClick () no disparando en 4.1 jellybean
MinutesRemaining
está enlazado a un TextView
utilizando MvvmCross.
Hasta la actualización 4.10.1
de Xamarin, la aplicación se bloquearía completamente sin mensaje de error impreso en la traza. Ahora se está rompiendo correctamente al depurar y dar el siguiente error al invocar el evento PropertyChanged
:
MvxBind:Error:281.24 Problem seen during binding execution for binding Text for MinutesRemaining - problem ArgumentException: 'jobject' must not be IntPtr.Zero. Parameter name: jobject at Android.Runtime.JNIEnv.CallVoidMethod (IntPtr jobject, IntPtr jmethod, Android.Runtime.JValue[] parms) [0x00010] in /Users/builder/data/lanes/monodroid-mlion-monodroid-4.10.1-branch/9d03ce3e/source/monodroid/src/Mono.Android/src/Runtime/JNIEnv.g.cs:499 at Android.Widget.TextView.set_TextFormatted (ICharSequence value) [0x00034] in /Users/builder/data/lanes/monodroid-mlion-monodroid-4.10.1-branch/9d03ce3e/source/monodroid/src/Mono.Android/platforms/android-14/src/generated/Android.Widget.TextView.cs:1814 at Android.Widget.TextView.set_Text (System.String value) [0x00013] in /Users/builder/data/lanes/monodroid-mlion-monodroid-4.10.1-branch/9d03ce3e/source/monodroid/src/Mono.Android/platforms/android-14/src/generated/Android.Widget.TextView.cs:1823 at Cirrious.MvvmCross.Binding.Droid.Target.MvxTextViewTextTargetBinding.SetValueImpl (System.Object target, System.Object toSet) [0x00000] in <filename unknown>:0 at Cirrious.MvvmCross.Binding.Bindings.Target.MvxConvertingTargetBinding.SetValue (System.Object value) [0x00000] in <filename unknown>:0 at Cirrious.MvvmCross.Binding.Bindings.MvxFullBinding.UpdateTargetFromSource (System.Object value) [0x00000] in <filename unknown>:0
Se enlaza correctamente la primera vez – es sólo en las RaisePropertyChanged
llamadas RaisePropertyChanged
que esto ocurre. El mismo código también funciona en Windows 8 y Windows Phone.
Actualizar
El uso de JavaFinalise en el adaptador utilizado para el escenario anterior solucionó el problema (encontrado aquí: MVVMCross Binding Crashes Android Application ). El problema que tengo ahora es el mismo resultado, pero donde la primera vista de un adaptador está enlazada a una propiedad en el modelo de vista principal (no el elemento).
El código utilizado para enlazar es el siguiente:
public class SubjectFilterAdapter : MvxAdapter { private EntityListFragment<TEntity, TViewModel> _owner; public SubjectFilterAdapter(Context context, EntityListFragment<TEntity, TViewModel> owner) : base(context, (IMvxAndroidBindingContext)owner.BindingContext) { _owner = owner; } protected override View GetBindableView(View convertView, object dataContext, int templateId) { var view = base.GetBindableView(convertView, dataContext, templateId); if (templateId == ItemTemplateId && GetPosition(dataContext) == 0) { var set = _owner.CreateBindingSet<EntityListFragment<TEntity, TViewModel>, TViewModel>(); set.Bind(view.FindViewById<TextView>(Resource.Id.SelectedScheduleText)) .To(x => x.SelectedScheduleText).WithClearBindingKey("SelectedScheduleTextFilterBinding"); set.Apply(); } return view; } protected override void JavaFinalize() { if (this.BindingContext != null) this.BindingContext.ClearAllBindings(); base.JavaFinalize(); } }
Funciona correctamente para empezar (para el primer par de cambios), pero después de que la excepción anterior se lanza. Utilizando MvvmCross 3.0.14-beta3
.
¡Gracias!
- Necesita un ejemplo de tomar una imagen con MonoDroid y MVVMCross
- Error al navegar lejos de una página con un mapa en Android, mientras que el teclado en pantalla es visible
- Xamarin C # - Android - Impedir que un AlertDialog cierre en PositiveButton haga clic
- OnConfigurationChanged no se llama en mono android
- Android TextView defStyle parámetro ignorado?
- Cambiar el color de ActionBar - Xamarin
- ¿MonoDroid vale la pena el esfuerzo?
- Cómo manejar las excepciones MonoDroid sin capturar globalmente y evitar que la aplicación se bloquee
Al mezclar los contextos de vinculación de listitem / célula con el contexto padre, estás entrando en un área bastante avanzada.
Para ayudar a intentar explicar / depurar lo que está pasando, es necesario comprender un poco acerca de todo el ciclo de vida de los padres, el ciclo de vida de listitem / célula y los ciclos de vida de los contextos de enlace MvvmCross correspondientes.
En el nivel de ciclo de vida de los padres, generalmente se trata de una Activity
o Fragment
Android. Para simplificar, utilizaré Activity
para el resto de esta respuesta.
Esta Activity
tiene un par de eventos clave del ciclo de vida
-
OnCreate
se llama una sola vez cuando se lanza laActivity
-
OnDestroy
se llama una sola vez cuando laActivity
no se mostrará de nuevo.
MvvmCross intercepta estos eventos y:
- Dentro de
OnCreate
, establece unViewModel
comoViewModel
laActivity
. Código de usuario – normalmente código Xml inflado dentro deSetContentView
– a continuación, crea enlaces. Estos enlaces se almacenan dentro delBindingContext
de laActivity
- Dentro de
OnDestroy
, MvvmCross destruye todos los enlaces dentro deBindingContext
En la interfaz de usuario que nos interesa aquí, la Activity
posee un ListView
, y que ListView
tiene un Adapter
configurado para él. Dentro de este escenario, el DataContext
para el ListView
y su Adapter
es el mismo como su padre.
Dentro de la vida útil de ListView
la lista puede necesitar mostrar un montón de elementos. Los elementos que se muestran en cualquier momento pueden cambiar, tanto por las acciones táctiles del usuario como por los cambios del modelo de vista. Para mostrar estos elementos, el ListView
le pregunta al Adapter
para View
. Para cada elemento se muestra que el Adapter
suministra una View
, y estas View
pueden ser reutilizadas (utilizando el parámetro convertView
). Sin embargo, a veces, estas View
también no se reutilizan; en esta situación, a veces es posible que el objeto Ver permanezca en C # incluso después de que se haya quitado Java / Dalvik View
se haya finalizado Java.
MvvmCross intercepta las llamadas GetView
dentro de su MvxAdapter
. Para cada llamada no devuelve sólo una View
pero además y MvxListItemView
. Esta es una View
con un BindingContext
añadido – y esto permite a los usuarios de MvvmCross vincular cada MvxListItemView
a su elemento de lista DataContext
.
Cuando se MvxListItemView
utilizar un MvxListItemView
, es sencillo para MvvmCross cambiar simplemente su DataContext
.
Cuando un MvxListItemView
no se reutiliza – cuando se quita de la interfaz de usuario y, a continuación, JavaFinalize
d – MvvmCross intercepta el evento OnDetachedFromWindow
y utiliza esto para cambiar el DataContext
a null
. Esto se hace en OnDetachedFromWindow
lugar de JavaFinalize
como la llamada a la ventana se garantiza que se haga en el hilo de interfaz de usuario y como se siente (a mí) como un lugar más limpio para hacer esto.
Tenga en cuenta que parte de este comportamiento ha cambiado sutilmente en versiones recientes, pero esta descripción anterior es correcta para v3.0.14
Con ese fondo en su lugar, lo que parece que está intentando hacer es crear un enlace para el contenido de un ListItemView
dentro del BindingContext
de la Activity
.
Esto significa que el enlace no tiene realmente una buena comprensión del ciclo de vida de ListItemView
– por lo que el enlace puede decir vivo incluso después de que el ListItemView
ha sido eliminado de la pantalla y (tal vez) finalizado.
Para resolver este problema …
- Creo que la ruta más simple es cambiar el DataContext para su listitem. Si su enlace ListItemView es un simple enlace normal – si contiene la propiedad MinutesRemaining – entonces no debe golpear estos errores del ciclo de vida.
- Usted puede intentar el enlace avanzado encontrado en la respuesta de @ Jamie ( https://stackoverflow.com/a/20031690/373321 ) – sin embargo, creo que esta respuesta todavía no lo entiendo bien – como creo:
- No maneja correctamente el caso donde el listitemview se quita / finalizó – si el primer artículo de la lista se desplaza fuera de pantalla bajo el código actual entonces creo que todavía puede ver problemas. Para utilizar el adaptador de código basado, entonces creo que el adaptador necesita de alguna manera obtener una devolución de llamada desde el listitemview en el caso de que la vista se elimina de la interfaz de usuario o finalizado.
- El
JavaFinalize
en esa respuesta es "un poco travieso" en que borra laActivity
principal BindingContext durante laFinalize
delAdapter
. Esto es probablemente OK para hacer pero no debería ser realmente necesario –OnDestroy
debe manejar eso.
Se corrigió actualizando el código del adaptador anterior a:
public class SubjectFilterAdapter : MvxAdapter { private EntityListFragment<TEntity, TViewModel> _owner; private MvxFluentBindingDescriptionSet<EntityListFragment<TEntity, TViewModel>, TViewModel> _scheduleBindingSet; public SubjectFilterAdapter(Context context, EntityListFragment<TEntity, TViewModel> owner) : base(context, (IMvxAndroidBindingContext)owner.BindingContext) { _owner = owner; } protected override View GetBindableView(View convertView, object dataContext, int templateId) { var view = base.GetBindableView(convertView, dataContext, templateId); if (templateId == ItemTemplateId && GetPosition(dataContext) == 0) { if (_scheduleBindingSet != null) { _owner.BindingContext.ClearBindings("SelectedScheduleTextFilterBinding"); _scheduleBindingSet = null; } _scheduleBindingSet = _owner.CreateBindingSet<EntityListFragment<TEntity, TViewModel>, TViewModel>(); _scheduleBindingSet.Bind(view.FindViewById<TextView>(Resource.Id.SelectedScheduleText)) .To(x => x.SelectedScheduleText).WithClearBindingKey("SelectedScheduleTextFilterBinding"); _scheduleBindingSet.Apply(); } return view; } protected override void JavaFinalize() { if (this.BindingContext != null) this.BindingContext.ClearAllBindings(); base.JavaFinalize(); } }