4

component-scan開発中の Android フレームワークに、Spring の に似たパッケージ スキャン機能を実装しようとしています。基本的に、基本パッケージを指定して、特定の注釈を持つcom.foo.barすべてのインスタンスを取得できるようにしたいと考えています。Classすべてのコンポーネントをフレームワークに登録する必要はありません。自動スキャンの目的が損なわれるからです。

私の調査によると、Java では、リフレクションを使用してパッケージ名を指定してリソースを取得することはできないようです。ただし、簡単にReflections フレームワークを調べたところ、Android 互換の同等のものがあるかどうか疑問に思っています。そうでない場合は、私がやりたいことを達成するための少し分かりにくい方法があるかもしれません。

Spring のソースを少し調べて、彼らがこれをどのように達成したかを確認しましたが、彼らがしていることは Dalvik ランタイム内で機能するとは思いません。

アップデート

現在、以下のコードは、特定の注釈を含むすべてのクラスを取得するために私ができる最善の方法ですが、率直に言って、それはかなり貧弱な解決策です。ClassLoaderさらに、すべてのアプリケーション クラスをスキャン (およびロード) することについて、非常に危険な仮定を立てています。

public Set<Class<?>> getClassesWithAnnotation(Class<? extends Annotation> annotation) {
    Set<Class<?>> classes = new HashSet<Class<?>>();
    Field dexField = PathClassLoader.class.getDeclaredField("mDexs");
    dexField.setAccessible(true);
    PathClassLoader classLoader = (PathClassLoader) Thread.currentThread().getContextClassLoader();
    DexFile[] dexs = (DexFile[]) dexField.get(classLoader);
    for (DexFile dex : dexs) {
        Enumeration<String> entries = dex.entries();
        while (entries.hasMoreElements()) {
            String entry = entries.nextElement();
            Class<?> entryClass = dex.loadClass(entry, classLoader);
            if (entryClass != null && entryClass.isAnnotationPresent(annotation)) {
                classes.add(entryClass);
            }
        }
    }
    return classes;
}
4

5 に答える 5

4

実行時にすべてのサブクラスを見つけたかったのです。だから私はアンドロイドクラスのスキャンを探していました。これは、Web で収集したものからの最終的なコードです。あなたはアイデアを得るでしょう。

public static void findSubClasses(Context context, Class parent) {
    ApplicationInfo ai = context.getApplicationInfo();
    String classPath = ai.sourceDir;
    DexFile dex = null;
    try {
        dex = new DexFile(classPath);
        Enumeration<String> apkClassNames = dex.entries();
        while (apkClassNames.hasMoreElements()) {
            String className = apkClassNames.nextElement();
            try {
                Class c = context.getClassLoader().loadClass(className);
                if (parent.isAssignableFrom(c)) {
                    android.util.Log.i("nora", className);
                }
            } catch (ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            //              android.util.Log.i("nora", className);
        }
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } finally {
        try {
            dex.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
于 2012-11-01T10:17:57.380 に答える
3

私は Joop Eggen の意見を共有し、彼のアプローチは良いものだと思います。Android では、アプリケーションの起動に時間がかかる通常の Web アプリ機能を回避しようとしています。リフレクションやパッケージ スキャンは使用しません。

しかし、あなたがしたいのであれば....私がそれを正しく理解していれば、クラスの注釈が必要です。注釈を使用する代わりに、マーカー インターフェイスを使用することもできます (可能性を広げるため)。

1) 見て

2) Android アノテーション

私はAndroidAnnotationsが機能する方法を好みます(AndroidAnnotations への統合が望ましい方法かもしれません)。標準の Java Annotation Processing Tool を使用して、ソース コードを生成する追加のコンパイル ステップが自動的に追加されます。したがって、ランタイム スキャンの代わりに、コンパイル時に生成された注釈に基づいてコードを実行します。

Bean/EBean アノテーションが機能すると思います (単一クラスのみ): https://github.com/excilys/androidannotations/wiki/Enhance%20custom%20classes

スキャン機能は利用できません。このスレッドを参照してください

3) 独自の注釈プロセッサを作成する

于 2012-07-13T06:42:13.190 に答える
0

Vogar の ClassPathScanner を見てください。これを使用して、クラス パスでテスト ケースを検索します。

于 2012-07-11T12:10:56.300 に答える
0

編集:

この問題は、Android イシュー トラッカーで見つけました。がClassLoader.getResource(String)返されるという点で、「期待どおりに機能している」ようnullです。これは、DalvikVM がコンパイル後にリソースを保持しないためです。問題にリストされている回避策がありますが、必要なクラスにアクセスする別の方法があるかもしれません。

PackageManagerのインスタンスを取得するには、 を使用しますApplicationInfo。 には、そのアプリケーションのソース ディレクトリの場所へのフル パス (a) であるApplicationInfoというパブリック フィールドがあります。この から を作成すると、ソース ディレクトリ内のパッケージに移動できるはずです。そこに着いたら、元の回答のメソッドを使用して、探しているクラスを見つけることができます。sourceDirStringFileString

String applicationSourceDir = 
    getPackageManager().getApplicationInfo(androidPackageName, 0).sourceDir;

/編集

ClassLoader.getResource(String)を使用して、特定のパッケージを取得できるはずですURL(渡されたStringは、関心のあるパッケージ名であり、ピリオドではなくパス区切り文字で区切られています)。これURLを使用して を呼び出すことができgetFile()、そこから JavaFileをパッケージ フォルダーに作成できます。そこから呼び出すpackageFile.listFiles()と、クラス/サブパッケージがあります。

サブパッケージでは再帰的になり、クラスでClassは静的Class.forName(String)メソッドを使用してオブジェクトを見つけます。

于 2012-07-10T20:18:14.193 に答える