ここにあるカスタムビルドのTwoDScrollViewを使用するAndroidアプリケーションを作成しています:
http://blog.gorges.us/2010/06/Android-two-dimensional-scrollview/
この同じクラスは、他のいくつかのWebサイトで参照されており、Stack Overflowの他のWebサイトからも質問が寄せられています。 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です。これは、基本的にJavaビットごとのコードビットと同じですが、C#で書き直されています。
助けてくれてありがとう!
おめでとう!漏れやすい抽象化に遭遇しました。 :-/
問題はこれです: 良くも悪くも 、コンストラクターからの仮想メソッド呼び出しは、最も派生したメソッド実装を呼び出します。この点で、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のマッピングを担当しますinstance to C#instance 。 ただし、、仮想メソッドがJavaコンストラクターから呼び出された場合、メソッドはディスパッチされますメソッドを呼び出すC#インスタンスが存在する前に!
それを少し沈めましょう。
どのメソッドが特定のコードのシナリオをトリガーしているのかわかりません(指定したコードフラグメントは正常に機能します)が、このシナリオにヒットするサンプルがあります: LogTextBoxオーバーライドTextView.DefaultMovementMethod プロパティ、および TextView
コンストラクターはgetDefaultMovementMethod()
メソッドを呼び出します 。その結果、AndroidはLogTextBox
インスタンスが存在する前に_LogTextBox.DefaultMovementMethod
_を呼び出そうとします。
では、Mono for Androidは何をしますか? AndroidのMonoはACWを作成したため、どのC#typeがgetDefaultMovementMethod()
メソッドに委任されるべきかを知っています。 。作成されていないため、インスタンスにはありません。したがって、Mono for Androidは、_(IntPtr, JniHandleOwnership)
_コンストラクターを介して適切なタイプのインスタンスを作成し、このコンストラクターが見つからない場合はエラーを生成します。
(この場合)TextView
コンストラクターの実行が完了すると、LogTextBox
のACWコンストラクターが実行され、その時点でAndroidのMonoは「あぁ!このJavaインスタンスのC#インスタンス」、およびthenは、既に作成されたインスタンスで適切なコンストラクターを呼び出します。つまり、1つのインスタンスに対して、2つのコンストラクターが実行されます: _(IntPtr, JniHandleOwnership)
_ constructor 、および(後で) _(Context, IAttributeSet, int)
_ constructor 。
エラーメッセージは言う:
System.Exception: No constructor found for MyProject.TwoDScrollView::.ctor(System.IntPtr, Android.Runtime.JniHandleOwnership)
次のようなコンストラクタを追加してみて、それが役立つかどうかを確認してください。
public TwoDScrollView (IntPtr a, JniHandleOwnership b) : base (a, b) { }
私はカスタム画像ビューでも同じ問題を抱えていましたが、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)
{
}
カスタムリストビューレンダラーを使用していましたが、回避策はありませんでした。しかし、base.Dispose
メソッドはクラッシュを修正するのに役立ちました。おそらく、これはモノのAndroidにプロキシインスタンスを初期化する機会を与えます。
Xamarin.Forms.Device.BeginInvokeOnMainThread(base.Dispose);
現在、クラッシュは見当たりません!