On Feb 16, 2012, at 12:01 AM, chris@Terrago wrote:
> I occasionally get external calls to my class' constructor with the following
> prototype:
> AsyncTask(IntPtr, Android.Runtime.JniHandleOwnership).
The (IntPtr, JniHandleOwnership) constructor is needed whenever a Java object
will be exposed to managed code and a wrapper needs to be created. For example,
if some Java code creates a java.lang.String instance and that String is
exposed to managed code (via method invocation), then the
Java.Lang.String(IntPtr, JniHandleOwnership) constructor will be called to wrap
the java.lang.String instance.
Once a wrapper has been created, an internal mapping is kept between the Java
object and the managed wrapper. This mapping is maintained until both the Java
and managed objects are collected by both the Dalvik and Mono GCs, OR until
Java.Lang.Object.Dispose() is invoked. Calling Dispose() will break the
mapping, allowing both objects to be collected earlier than they otherwise
would be.
Here's the problem: if you have an AsyncTask subclass that you create, the
creation will implicitly create a corresponding Java object and the mapping
between the Java instance and your C# instance. If there is a request for an
AsyncTask(IntPtr, JniHandleOwnership) constructor, that means that the mapping
was somehow broken, and the Java instance is being re-exposed to managed code.
The problem here is that the execution of a constructor implies the creation of
a new instance, meaning the "loss" of any instance state (because you now have
a new object with `null`ed out instance data). This is very likely Badâ„¢, as it
will likely result in very subtle bugs ("why is this variable null?!"). :-)
I would check your code to ensure that you're not calling Dispose() on your
AsyncTask instance, or if you are calling Dispose() that you're not calling it
prematurely. You should only call Dispose() when you KNOW that either:
1. the instance is "just" a wrapper, e.g. Java.Lang.String instances are "just"
wrappers over Java instances. For such wrappers, it doesn't matter if the Java
object re-enters managed code and a new wrapper is created.
2. the corresponding Java instance will NEVER be exposed to managed code again,
and thus a wrapper will not need to be created for it.
> If I include a constructor of this form in my class as a pass through,
> everything appears fine
...
> I have noticed that this call immediately precedes the throwing of an
> exception in code called by my AsyncTask
Is that exception a NullReferenceException? :-)
- Jon
_______________________________________________
Monodroid mailing list
[email protected]
UNSUBSCRIBE INFORMATION:
http://lists.ximian.com/mailman/listinfo/monodroid