MonoDroid:调用自定义视图的构造函数时出错 - TwoDScrollView [英] MonoDroid: Error when calling constructor of custom view - TwoDScrollView

查看:40
本文介绍了MonoDroid:调用自定义视图的构造函数时出错 - TwoDScrollView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个使用自定义构建的 TwoDScrollView 的 Android 应用程序:

I am building an Android application that uses the custom-built TwoDScrollView found here:

http://blog.gorges.us/2010/06/android-two-维度滚动视图/

这个类可以在其他几个网站上找到,Stack Overflow 上的其他人也提出了相关问题.我在以前使用 Java/Eclipse 构建的 Android 应用程序中使用了它,并且取得了成功.

This same class can be found referenced at several other websites, and others on Stack Overflow have asked questions with regard to it. I was using it in a previous Android application that I was building using Java/Eclipse, and I was having success.

对于我当前的应用程序,我想使用 C# 和 MonoDroid.我决定用 C# 重写整个 TwoDScrollView 类.重写后,然后在一些布局 XML 中使用它后,尝试运行我的代码时出现以下异常:

With my current application, I wanted to use C# and MonoDroid. I decided to rewrite the entire TwoDScrollView class in C#. After rewriting it, and then using it in some layout XML, I get the following exceptions when trying to run my code:

System.NotSupportedException 已被抛出.无法激活来自本机句柄 44f4d310 的 MyProject.TwoDScrollView 类型的实例.

System.NotSupportedException has been thrown. Unable to activate instance of type MyProject.TwoDScrollView from native handle 44f4d310.

System.Exception: 找不到构造函数MyProject.TwoDScrollView::.ctor(System.IntPtr,Android.Runtime.JniHandleOwnership) ......带有更多文字如下....

System.Exception: No constructor found for MyProject.TwoDScrollView::.ctor(System.IntPtr, Android.Runtime.JniHandleOwnership) ......with more text that follows....

我的布局 XML 如下:

My layout XML is as follows:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >

<myproject.TwoDScrollView
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

</myproject.TwoDScrollView>

</RelativeLayout>

根据以下链接中有关在 MonoDroid 中使用布局 XML 中的自定义视图的说明:http://docs.xamarin.com/android/advanced_topics/using_custom_views_in_a_layout

Per the instructions at the following link on using custom views in layout XML in MonoDroid: http://docs.xamarin.com/android/advanced_topics/using_custom_views_in_a_layout

TwoDScrollView 类的构造函数如下所示:

The constructors to the TwoDScrollView class look as follows:

public TwoDScrollView(Context context) 
    : base(context)
{
    initTwoDScrollView();
}

public TwoDScrollView(Context context, IAttributeSet attrs) 
    : base(context, attrs)
{
    initTwoDScrollView();
}

public TwoDScrollView(Context context, IAttributeSet attrs, int defStyle) 
    : base(context, attrs, defStyle)
{
    initTwoDScrollView();
}

C# 版本中存在与 Java 版本中相同的构造函数(您可以在上面的链接中找到).关于可能出什么问题的任何想法?如果有人想看,我可以发布我的 TwoDScrollView 的完整 C# 代码.除了用 C# 重写外,它本质上与 Java 代码一样.

The same constructors exist in the C# version as in the Java version (which you can find at the above link). Any idea on what could be going wrong? I can post the full C# code of my TwoDScrollView if anyone would like to see it. It's essentially the same as the Java code bit for bit - except rewritten in C#.

感谢您的帮助!

推荐答案

恭喜!你遇到了一个有漏洞的抽象.:-/

Congratulations! You've hit a leaky abstraction. :-/

问题是这样的:无论好坏,来自构造函数的虚方法调用都会调用派生程度最高的方法实现.C#在这方面与Java相同;考虑以下程序:

The problem is this: for better or worse, virtual method calls from constructors invoke the most derived method implementation. C# is the same as Java in this respect; consider the following program:

using System;

class Base {
    public Base ()
    {
        Console.WriteLine ("Base..ctor");
        M ();
    }

    public virtual void M ()
    {
        Console.WriteLine ("Base.M");
    }
}

class Derived : Base {

    public Derived ()
    {
        Console.WriteLine ("Derived..ctor");
    }

    public override void M ()
    {
        Console.WriteLine ("Derived.M");
    }
}

static class Demo {
    public static void Main ()
    {
        new Derived ();
    }
}

运行时,输出为:

Base..ctor
Derived.M
Derived..ctor

也就是说,在 Derived 构造函数执行之前调用 Derived.M() 方法.

That is, the Derived.M() method is invoked before the Derived constructor has executed.

在适用于 Android 的 Mono 中,事情变得更加……复杂.Android Callable Wrapper (ACW) 的构造函数由 Java 调用,负责创建 对等 C# 实例并将 Java 实例映射到 C# 实例.但是,如果从 Java 构造函数调用虚拟方法,则该方法将在 有 C# 实例调用该方法之前被分派!

In Mono for Android, things get more...complicated. The Android Callable Wrapper (ACW)'s constructor is invoked by Java and is responsible for creating the peer C# instance and mapping the Java instance to the C# instance. However, if a virtual method is invoked from the Java constructor, then the method will be dispatched before there is a C# instance to invoke the method upon!

让它沉入一点.

我不知道哪种方法正在为您的特定代码触发场景(您提供的代码片段工作正常),但我们确实有一个示例可以满足此场景:LogTextBox 覆盖 TextView.DefaultMovementMethod 属性,以及 TextView 构造函数调用 getDefaultMovementMethod() 方法.结果是 Android 尝试在 LogTextBox 实例存在之前调用 LogTextBox.DefaultMovementMethod.

I don't know which method is triggering the scenario for your specific code (the code fragment you provided works fine), but we do have a sample which hits this scenario: LogTextBox overrides the TextView.DefaultMovementMethod property, and the TextView constructor invokes the getDefaultMovementMethod() method. The result is that Android tries to invoke LogTextBox.DefaultMovementMethod before a LogTextBox instance even exists.

那么 Mono for Android 有什么作用呢?Mono for Android 创建了 ACW,因此知道应该将 getDefaultMovementMethod() 方法委托给哪个 C# type.它没有实例,因为还没有创建实例.所以 Mono for Android 创建了一个适当类型的实例......通过 (IntPtr, JniHandleOwnership) 构造函数,如果找不到这个构造函数,就会产生一个错误.

So what does Mono for Android do? Mono for Android created the ACW, and thus knows which C# type the getDefaultMovementMethod() method should be delegated to. What it doesn't have is an instance, because one hasn't been created. So Mono for Android creates an instance of the appropriate type...via the (IntPtr, JniHandleOwnership) constructor, and generates an error if this constructor cannot be found.

一旦(在这种情况下)TextView 构造函数完成执行,LogTextBox 的 ACW 构造函数将执行,此时 Mono for Android 将啊哈!我们已经为这个 Java 实例创建了一个 C# 实例",并且将然后在已经创建的实例上调用适当的构造函数.这意味着对于单个实例,将执行两个构造函数:(IntPtr, JniHandleOwnership) 构造函数,以及(稍后)(Context, IAttributeSet, int) 构造函数.

Once the (in this case) TextView constructor finishes executing, the LogTextBox's ACW constructor will execute, at which point Mono for Android will go "aha! we've already created a C# instance for this Java instance", and will then invoke the appropriate constructor on the already created instance. Meaning that for a single instance, two constructors will be executed: the (IntPtr, JniHandleOwnership) constructor, and (later) the (Context, IAttributeSet, int) constructor.

这篇关于MonoDroid:调用自定义视图的构造函数时出错 - TwoDScrollView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆