Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Protect Android Bindings #1446

Merged
merged 8 commits into from Oct 19, 2016
Merged

Conversation

kjeremy
Copy link
Contributor

@kjeremy kjeremy commented Oct 3, 2016

Occasionally we can get in a state where an object has been garbage collected by the Android GC but not Mono. This is most common with MvxRecyclerView where we can't deterministically destroy the bindings.

To protect against this we need to detect invalid Java Handles and skip setting binding values. Part of this change introduces a weak event subscription model that also takes this into account. We now weak subscribe to Android Views/Widgets in an attempt to reduce the refcount on the Mono side. The latter change is more of a precautionary measure but is part of the reason we're seeing: #1405

Fixes: #1402

This is the first part of a two part fix for:
#1405
#1444

kjeremy added a commit to kjeremy/MvvmCross-AndroidSupport that referenced this pull request Oct 3, 2016
Fixes memory issues with the Android Support Library
Removes hack that tracked ViewHolders.
@Cheesebaron
Copy link
Member

I just looked through this. It seems to achieve the same thing I did in one of my PR's but ran into the issue that EventHandler cannot be cast to EventHandler, which lead to some issues with detecting whether the Event was present on the View, through reflection.

This seems like a nice way of tackling this and makes Android bindings weak, yay!

I'll give this a spin soon 👍

@kjeremy
Copy link
Contributor Author

kjeremy commented Oct 3, 2016

I spent a LOT of time trying to figure out why C# can't tell the difference between Func(TSource source, EventHandler handler) and Func(TSource source, EventHandler<TEventArgs> handler) at the caller site.

I'm not sure if the other platforms should also weak subscribe to their event handlers as well (separate change). What makes Android special is that you can get into this weird undead (but not zombie) object state.

@Cheesebaron
Copy link
Member

Cheesebaron commented Oct 16, 2016

Something is up with SelectedItem binding for MvxRadioGroup.

It doesn't work until I change the FillTargetFactories registration from MvxRadioGroup to RadioGroup. After that change it triggers. However, a new problem appears:

10-16 22:38:23.755 I/MonoDroid( 3106): UNHANDLED EXCEPTION:
10-16 22:38:23.755 I/MonoDroid( 3106): System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidCastException: Specified cast is not valid.
10-16 22:38:23.755 I/MonoDroid( 3106):   at MvvmCross.Binding.Droid.Target.MvxRadioGroupSelectedItemBinding.RadioGroupCheckedChanged (System.Object sender, Android.Widget.RadioGroup+CheckedChangeEventArgs args) [0x00001] in D:\git\MvvmCross-kj\MvvmCross\Binding\Droid\Target\MvxRadioGroupSelectedItemBinding.cs:45 
10-16 22:38:23.755 I/MonoDroid( 3106):   at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
10-16 22:38:23.755 I/MonoDroid( 3106):   at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00038] in /Users/builder/data/lanes/3819/96c7ba6c/source/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:305 
10-16 22:38:23.755 I/MonoDroid( 3106):    --- End of inner exception stack trace ---
10-16 22:38:23.755 I/MonoDroid( 3106):   at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00050] in /Users/builder/data/lanes/3819/96c7ba6c/source/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:313 
10-16 22:38:23.755 I/MonoDroid( 3106):   at System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) [0x00000] in /Users/builder/data/lanes/3819/96c7ba6c/source/mono/mcs/class/referencesource/mscorlib/system/reflection/methodbase.cs:229 
10-16 22:38:23.755 I/MonoDroid( 3106):   at MvvmCross.Platform.WeakSubscription.MvxWeakEventSubscription`2[TSource,TEventArgs].OnSourceEvent (System.Object sender, TEventArgs e) [0x00011] in D:\git\MvvmCross-kj\MvvmCross\Platform\Platform\WeakSubscription\MvxWeakEventSubscription.cs:77 
10-16 22:38:23.755 I/MonoDroid( 3106):   at Android.Widget.RadioGroup+IOnCheckedChangeListenerImplementor.OnCheckedChanged (Android.Widget.RadioGroup group, System.Int32 checkedId) [0x0000d] in /Users/builder/data/lanes/3819/96c7ba6c/source/monodroid/src/Mono.Android/platforms/android-24/src/generated/Android.Widget.RadioGroup.cs:266 
10-16 22:38:23.755 I/MonoDroid( 3106):   at Android.Widget.RadioGroup+IOnCheckedChangeListenerInvoker.n_OnCheckedChanged_Landroid_widget_RadioGroup_I (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_group, System.Int32 checkedId) [0x00011] in /Users/builder/data/lanes/3819/96c7ba6c/source/monodroid/src/Mono.Android/platforms/android-24/src/generated/Android.Widget.RadioGroup.cs:217 
10-16 22:38:23.755 I/MonoDroid( 3106):   at (wrapper dynamic-method) System.Object:051aaf09-1fcb-4a93-83b0-f6b728639adb (intptr,intptr,intptr,int)

EDIT:

Just changed the casts to RadioGroup in the MvxRadioGroupSelectedItemBinding and it magically works again? What the heck is going on? I am using MvxRadioGroup in my axml file... Why does the cast not work?

EDIT EDIT:

Apart from this strangeness with MvxRadioGroup, I think this is good to go when merge conflict has been resolved. I've tested with the APIExample where I added explicit GC on all property changed, which does not seem to break bindings.

@kjeremy
Copy link
Contributor Author

kjeremy commented Oct 16, 2016

I bet you that MvxRadioGroup was swapped with MvxAppCompatRadioGroup

@Cheesebaron
Copy link
Member

Aw crap! You might be right! I guess it is good then. These changes to use WeakSubscribe instead should ofc also be present in AndroidSupport.

@kjeremy
Copy link
Contributor Author

kjeremy commented Oct 16, 2016

There is a PR open for that (MvvmCross/MvvmCross-AndroidSupport#300). Also: I'm surprised that binding worked for RadioGroup. I thought it would need something specific that MvxRadioGroup provides.

@Cheesebaron
Copy link
Member

SelectedItem binding will only work on MvxRadioGroup because of the way MvxAdapter wraps stuff in MvxListItemView. However, for the binding target, I don't see a reason why we couldn't just apply it on RadioGroup since it doesn't depend on anything in MvxRadioGroup directly.

@kjeremy
Copy link
Contributor Author

kjeremy commented Oct 16, 2016

Cool. Let's take the binding discussion over to #1466. This probably isn't the only widget where we hit that problem.

@kjeremy
Copy link
Contributor Author

kjeremy commented Oct 19, 2016

@Cheesebaron hey is this good? Did you look at the support lib version?

@Cheesebaron
Copy link
Member

I think this is good. Only thing was the MvxRadioGroup. I guess well take that in the issue you linked. So fix the merge conflict and we'll merge this.

kjeremy and others added 8 commits October 19, 2016 13:45
This weak event subscription handles the case where an object may be alive
according to Xamarin but is dead according to the Java GC.

Weak subscribe to Android View/Widget event sources
This is more of a precaution than anything else.
@kjeremy
Copy link
Contributor Author

kjeremy commented Oct 19, 2016

Rebased onto develop.

@Cheesebaron Cheesebaron merged commit e84e3ec into MvvmCross:develop Oct 19, 2016
@kjeremy
Copy link
Contributor Author

kjeremy commented Dec 5, 2016 via email

@martijn00 martijn00 added this to the 4.4.0 milestone Apr 25, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

WeakSubcribe an EventHandler without EventArgs?
3 participants