50

我正在构建一个使用此处找到的定制 TwoDScrollView 的 Android 应用程序:

http://blog.gorges.us/2010/06/android-two-dimensional-scrollview/

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

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

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

System.Exception:未找到 MyProject.TwoDScrollView::.ctor(System.IntPtr, Android.Runtime.JniHandleOwnership) 的构造函数......后面还有更多文本......

我的布局 XML 如下:

<?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

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

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# 代码。它本质上与 Java 代码逐位相同——除了用 C# 重写。

谢谢你的帮助!

4

4 回答 4

99

恭喜!你遇到了一个泄漏的抽象。:-/

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

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.M()方法在Derived构造函数执行之前被调用。

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

让它沉下去一点。

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

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

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

于 2012-05-15T15:11:29.997 回答
28

The error message says:

System.Exception: No constructor found for MyProject.TwoDScrollView::.ctor(System.IntPtr, Android.Runtime.JniHandleOwnership)

Try adding a constructor like it says and see if that helps:

public TwoDScrollView (IntPtr a, JniHandleOwnership b) : base (a, b) { }

于 2012-05-15T02:26:04.313 回答
11

我对自定义图像视图有同样的问题,jpobst 的答案肯定完全解决了这个问题:

public CircularImageView(Context context)
            :base(context) 
        {

            init (context, null, 0);
        }

        public CircularImageView(Context context, IAttributeSet attrs)
            : base(context, attrs)
        {
            init (context, attrs, Resource.Attribute.circularImageViewStyle);
        }

        public CircularImageView(Context context, IAttributeSet attrs, int defStyle)
            :base(context, attrs, defStyle)
        {

            init(context, attrs, defStyle);
        }
        public CircularImageView (IntPtr a, JniHandleOwnership b) : base (a, b)
        {
        }
于 2015-03-11T03:10:27.183 回答
1

我正在使用自定义列表视图渲染器,但没有一个解决方法对我有用。但是延迟base.Dispose方法帮助我修复了崩溃,可能这给了 mono android 初始化代理实例的机会。

Xamarin.Forms.Device.BeginInvokeOnMainThread(base.Dispose);

我现在没有看到任何崩溃!

于 2018-01-18T19:00:17.367 回答