Android MonoDroid:调用自定义视图的构造函数时出错 - TwoDScrollView
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10593022/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
MonoDroid: Error when calling constructor of custom view - TwoDScrollView
提问by David
I am building an Android application that uses the custom-built TwoDScrollView found here:
我正在构建一个 Android 应用程序,该应用程序使用此处找到的自定义 TwoDScrollView:
http://blog.gorges.us/2010/06/android-two-dimensional-scrollview/
http://blog.gorges.us/2010/06/android-two-Dimension-scrollview/
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.
可以在其他几个网站上找到相同的类,Stack Overflow 上的其他人也提出了相关问题。我在以前使用 Java/Eclipse 构建的 Android 应用程序中使用它,并且取得了成功。
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:
对于我当前的应用程序,我想使用 C# 和 MonoDroid。我决定用 C# 重写整个 TwoDScrollView 类。重写后,然后在某些布局 XML 中使用它后,尝试运行我的代码时出现以下异常:
System.NotSupportedException has been thrown. Unable to activate instance of type MyProject.TwoDScrollView from native handle 44f4d310.
System.Exception: No constructor found for MyProject.TwoDScrollView::.ctor(System.IntPtr, Android.Runtime.JniHandleOwnership) ......with more text that follows....
已抛出 System.NotSupportedException。无法从本机句柄 44f4d310 激活 MyProject.TwoDScrollView 类型的实例。
System.Exception: 未找到 MyProject.TwoDScrollView::.ctor(System.IntPtr, Android.Runtime.JniHandleOwnership) 的构造函数......后面还有更多文本......
My layout XML is as follows:
我的布局 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>
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
根据以下链接中有关在 MonoDroid 中使用布局 XML 中的自定义视图的说明:http://docs.xamarin.com/android/advanced_topics/using_custom_views_in_a_layout
The constructors to the TwoDScrollView class look as follows:
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();
}
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#.
C# 版本中存在与 Java 版本中相同的构造函数(您可以在上面的链接中找到)。关于可能出什么问题的任何想法?如果有人想看的话,我可以发布我的 TwoDScrollView 的完整 C# 代码。除了用 C# 重写外,它本质上与 Java 代码一样。
Thanks for any help!
谢谢你的帮助!
回答by jonp
Congratulations! You've hit a leaky abstraction. :-/
恭喜!你遇到了一个有漏洞的抽象。:-/
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:
问题是这样的:无论好坏,来自构造函数的虚方法调用都会调用派生最多的方法实现。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 ();
}
}
When run, the output is:
运行时,输出为:
Base..ctor
Derived.M
Derived..ctor
That is, the Derived.M()
method is invoked before the Derived
constructor has executed.
也就是说,该Derived.M()
方法在Derived
构造函数执行之前被调用。
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!
在 Mono for Android 中,事情变得更加……复杂。所述的Android调用包装(ACW)的构造是由Java的调用和负责创建的对等体C#实例和映射的Java实例的C#实例。但是,如果从 Java 构造函数调用虚拟方法,则将在有 C# 实例调用该方法之前调度该方法!
Let that sink in a bit.
让它沉入一点。
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: LogTextBoxoverridesthe TextView.DefaultMovementMethodproperty, and the TextView
constructor invokes the getDefaultMovementMethod()
method. The result is that Android tries to invoke LogTextBox.DefaultMovementMethod
before a LogTextBox
instance even exists.
我不知道哪种方法触发场景为您的特定代码(代码片段您提供优良工程),但我们确实有它打这种情况的例子:LogTextBox覆盖的TextView.DefaultMovementMethod属性和TextView
构造函数调用的getDefaultMovementMethod()
方法. 结果是 Android 尝试LogTextBox.DefaultMovementMethod
在LogTextBox
实例甚至存在之前调用。
So what does Mono for Android do? Mono for Android created the ACW, and thus knows which C# typethe 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.
那么 Mono for Android 有什么作用呢?单声道的Android创建的ACW,并且因此知道哪个C#键入的getDefaultMovementMethod()
方法应该授予。它没有实例,因为还没有创建实例。所以 Mono for Android 创建了一个适当类型的实例......通过(IntPtr, JniHandleOwnership)
构造函数,如果找不到这个构造函数,就会产生一个错误。
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 theninvoke 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.
一旦(在这种情况下)TextView
构造函数完成执行后,LogTextBox
的ACW构造函数会执行,此时单为Android会去‘啊哈!我们已经创建了一个C#实例,该Java实例’,并将然后调用相应的已经创建的实例上的构造函数。这意味着对于单个实例,将执行两个构造函数:(IntPtr, JniHandleOwnership)
构造函数和(稍后)(Context, IAttributeSet, int)
构造函数。
回答by jpobst
The error message says:
错误消息说:
System.Exception: No constructor found for MyProject.TwoDScrollView::.ctor(System.IntPtr, Android.Runtime.JniHandleOwnership)
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)
{
}
public TwoDScrollView (IntPtr a, JniHandleOwnership b) : base (a, b)
{
}
回答by Amir Kotb
I had the same problem with a custom imageview and the answer for jpobst certainly fixed the problem completely :
我在自定义 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)
{
}
回答by zafar
I was using custom list view renderer, but none of the work arounds worked for me. But delaying the base.Dispose
method helped me fix the crash, probably this gives the mono android, the chance to initialize the proxy instance.
我正在使用自定义列表视图渲染器,但没有一种解决方法对我有用。但是延迟该base.Dispose
方法帮助我修复了崩溃,可能这给了单声道 android 初始化代理实例的机会。
Xamarin.Forms.Device.BeginInvokeOnMainThread(base.Dispose);
I don't see any crashes now!
我现在没有看到任何崩溃!