[mono-android] FindViewById returning a ViewGroupInvoker
Jonathan Pryor
jonp at xamarin.com
Thu Feb 23 02:28:48 UTC 2012
On Feb 22, 2012, at 10:50 AM, Chris Tacke wrote:
> Later on in my app, I'd like to get hold of this MapView so I can zoom in on it, but I'm having difficulty.
>
> My first attempt returned null:
>
> var m = m_layout.FindViewById<MapView>(Resource.Id.DriverMap);
...
> So I tried this:
> var m = m_layout.FindViewById(Resource.Id.DriverMap);
This doesn't make sense to me. :-/
View.FindViewById<T>(int) is (incorrectly!) this:
public T FindViewById<T> (int id)
{
object view = this.FindViewById (id);
return (T)view;
}
I have no idea why View.FindViewById<T>(int) would return null while View.FindViewById(int) returns a non-null instance. I'd expect an InvalidCastException, since FindViewById<T>(int) is calling FindViewById(int)...
As I said, that implementation is incorrect. (Thanks for finding the bug! I fixed Activity but forgot about View...) It will be fixed in the 4.2 series so that FindViewById<MapView>() will work as expected. In the mean time...
> I run this:
>
> var mt = m.GetType().Name;
>
> And I get back "ViewGroupInvoker"
The problem here is a leaky abstraction: at present, our Java instance wrapper logic only knows about types from android.jar/Mono.Android.dll, and MapView isn't in android.jar, so it's not known. So we check the base type of MapView, find ViewGroup, which we _do_ know about, but it's abstract. "Fortunately" our plumbing generates "Invoker" types for abstract types and interfaces, so we construct a ViewGroupInvoker to hold thew MapView, as a MapView IS-A ViewGroup, and we return the invoker.
This still isn't entirely useful to you. The missing part you want/need is the Extensions.JavaCast<T>() extension method:
http://androidapi.xamarin.com/?link=M:Android.Runtime.Extensions.JavaCast{TResult}
Extensions.JavaCast<T>() is used to traverse (and type-check) the Java type system when the Mono for Android type system is dealing with incomplete information. You could thus do:
MapView m = m_layout.FindViewById(Resource.Id.DriverMap).JavaCast<MapView>();
This would return a (far more useful) MapView instance instead of a ViewGroupInvoker instance.
Thanks,
- Jon
More information about the Monodroid
mailing list