MonoDroid:调用自定义视图的构造函数时出错 - TwoDScrollView

Dav*_*vid 45 android scrollview android-custom-view android-layout xamarin.android

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

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>
Run Code Online (Sandbox Code Playgroud)

根据以下链接中有关在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();
}
Run Code Online (Sandbox Code Playgroud)

C#版本中存在与Java版本相同的构造函数(可以在上面的链接中找到).什么可能出错?如果有人想看,我可以发布我的TwoDScrollView的完整C#代码.除了用C#重写之外,它基本上与位的Java代码位相同.

谢谢你的帮助!

jon*_*onp 89

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

问题是:无论好坏,来自构造函数的虚方法调用会调用派生最多的方法实现.在这方面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 ();
    }
}
Run Code Online (Sandbox Code Playgroud)

运行时,输出为:

Base..ctor
Derived.M
Derived..ctor
Run Code Online (Sandbox Code Playgroud)

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

在Mono for Android中,事情变得更加复杂.所述的Android调用包装(ACW)的构造是由Java的调用和负责创建的对等体C#实例和映射的Java实例的C#实例.但是,如果从Java构造函数调用虚方法,则会在有一个C#实例调用该方法之前调度该方法!

让它沉入一点.

我不知道哪种方法触发场景为您的特定代码(代码片段您提供优良工程),但我们确实有它打这种情况的例子:LogTextBox 覆盖TextView.DefaultMovementMethod属性和TextView构造函数调用的getDefaultMovementMethod()方法.结果是Android尝试LogTextBox.DefaultMovementMethodLogTextBox实例存在之前调用.

那么Mono for Android会做什么?单声道的Android创建的ACW,并且因此知道哪个C#类型getDefaultMovementMethod()方法应被授予.它没有的是一个实例,因为还没有创建实例.因此,Mono for Android通过(IntPtr, JniHandleOwnership)构造函数创建了相应类型的实例,如果找不到此构造函数则会生成错误.

一旦(在这种情况下)TextView构造函数完成执行后,LogTextBox的ACW构造函数会执行,在这一点单为Android会去'啊哈!我们已经创建了这个Java实例的C#实例’,并将然后调用相应的已创建的实例上的构造函数.这意味着对于单个实例,将执行两个构造函数:(IntPtr, JniHandleOwnership)构造函数和(稍后)(Context, IAttributeSet, int)构造函数.

  • 不,我们不应该默认添加该构造函数,因为它将*隐藏错误*.如果你得到一个'No constructor found ...`消息,这意味着映射的实例被*过早收集*,这意味着要么有一个不应该存在的`Dispose()`调用,或者有一个GC错误,或其他非常重要且不应该被隐藏的东西.您需要了解*为什么*例外情况正在发生,以免货物崇拜"解决问题". (5认同)
  • @jonp为了防止我之前提到的那些例外,我能做些什么吗?在这一点上,我感到无能为力.:| 对于其他人提到的视图渲染器,似乎很容易提供额外的构造函数,但我不知道`Java.Lang.Thread + RunnableImplementor`和`Xamarin.Forms.Platform.Android.Platform + DefaultRenderer`是什么. (4认同)
  • @jonp默认情况下,Xamarin不应该将此构造函数添加到所有类中吗?程序员可以在他们自己的代码中提供这个,但是Mono和Forms也有问题.我一直得到`没有找到Java.Lang.Thread + RunnableImplementor`的构造函数和`Xamarin.Forms.Platform.Android.Platform + DefaultRenderer` (2认同)
  • 有没有人知道如何找到被调查的视图在哪里被调用? (2认同)

jpo*_*bst 27

错误消息说:

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

尝试添加像它说的构造函数,看看是否有帮助:

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

  • @David:为什么首先要搜索`(IntPtr,JniHandleOwnership)`构造函数?漏洞抽象.请参阅我的回答:http://stackoverflow.com/a/10603714/83444 (5认同)
  • 你的意思是我应该尝试合乎逻辑的答案?;-)所以,是的,你的建议确实解决了我原来的问题所描述的问题(如:它摆脱了错误信息,但是应用程序的行为仍然不正确 - 视图没有显示),但是它并没有真正解决问题的核心问题:为什么它甚至首先搜索那个构造函数?它调用的构造函数不是Android自定义视图类的标准构造函数之一.应该创建的标准构造函数是我在上面列出的构造函数. (2认同)

小智 11

我对自定义imageview有同样的问题,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)
        {
        }
Run Code Online (Sandbox Code Playgroud)