50

ここにあるカスタムビルドのTwoDScrollViewを使用するAndroidアプリケーションを構築しています:

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

この同じクラスは、他のいくつかのWebサイトで参照されており、StackOverflowの他のWebサイトから質問があります。Java / Eclipseを使用して構築していた以前のAndroidアプリケーションで使用していましたが、成功していました。

現在のアプリケーションでは、C#とMonoDroidを使用したいと思いました。TwoDScrollViewクラス全体をC#で書き直すことにしました。それを書き直し、レイアウト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#コードを投稿できます。これは、C#で書き直されていることを除いて、ビットのJavaコードビットと本質的に同じです。

助けてくれてありがとう!

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プロパティをオーバーライドし、コンストラクターがメソッドを呼び出します。。その結果、Androidはインスタンスが存在する前に呼び出しを試みます。TextViewgetDefaultMovementMethod()LogTextBox.DefaultMovementMethodLogTextBox

では、Mono for Androidは何をするのでしょうか?Mono for AndroidはACWを作成したため、メソッドを委任する必要があるC#タイプを認識しています。getDefaultMovementMethod()インスタンスが作成されていないため、インスタンスがありません。そのため、Mono for Androidは、(IntPtr, JniHandleOwnership)コンストラクターを介して適切なタイプのインスタンスを作成し、このコンストラクターが見つからない場合はエラーを生成します。

(この場合)TextViewコンストラクターの実行が完了すると、LogTextBox's ACWコンストラクターが実行されます。その時点で、Mono for Androidは「ああ!このJavaインスタンスのC#インスタンスを既に作成しました」になり、適切なもの呼び出します。作成済みのインスタンスのコンストラクタ。つまり、単一のインスタンスの場合、2つのコンストラクターが実行されます。(IntPtr, JniHandleOwnership)コンストラクターと(後で)(Context, IAttributeSet, int)コンストラクターです。

于 2012-05-15T15:11:29.997 に答える
28

エラーメッセージは次のとおりです。

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

それが言うようにコンストラクターを追加してみて、それが役立つかどうかを確認してください:

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

于 2012-05-15T02:26:04.313 に答える
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)
        {
        }
于 2015-03-11T03:10:27.183 に答える
1

カスタムリストビューレンダラーを使用していましたが、どの回避策も機能しませんでした。しかし、メソッドを遅らせることbase.Disposeでクラッシュを修正できました。おそらくこれにより、モノAndroidにプロキシインスタンスを初期化する機会が与えられます。

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

今はクラッシュは見られません!

于 2018-01-18T19:00:17.367 に答える