web-dev-qa-db-ja.com

Android:「複数のアプリケーションをホストするプロセスでクラスローダーが失敗する可能性があります」

AndroidのEclipseのlogcatにあるこのメッセージはどういう意味ですか?

W/ActivityThread: ClassLoader.getResources: The class loader returned by Thread.getContextClassLoader() may fail for processes that Host multiple applications. You should explicitly specify a context class loader. For example: Thread.setContextClassLoader(getClass().getClassLoader());

残念ながら、この警告に関するコンテキストが与えられていないため、この問題の原因と解決方法がわかりません。

21
caw

背景情報

このメッセージは、AndroidがThread.currentThread().setContextClassLoader()を使用してダミーのClassLoaderをセットアップし、何かがそのダミーのクラスローダーを使用しようとしていることを意味します。何か多くのことがあり、与えられた情報から正確に何を判断するのは難しいです。しかし、試すことができるトリックがあります。以下を参照してください。とにかく、Androidはダミークラスローダーを設定しますプロセスに複数のAPKからのコードが含まれる可能性がある場合。具体的には、_Android:sharedUserId_を使用した場合、Androidはマニフェストを検索します:

_<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
    ...
    Android:sharedUserId="triggers.dummy.loader" >
_

または、非標準の_Android:process_で実行している場合

_    <application Android:process="triggers.dummy.loader">
_

警告を取り除く方法

警告を取り除くためにできることは2つあります。

  1. _Android:sharedUserId_または_Android:process_は使用しないでください
  2. 他のコードを実行する前に、使用するAPK ClassLoaderを明示的に設定します

ソリューション2を使用するには、いくつかの重要な洞察が必要です。まず、APKのクラスAnyClassの場合、AnyClass.class.getClassLoader()は同じClassLoaderを返します。第二に、

_AnyClass obj = new AnyClass();
Thread.currentThread().setContextClassLoader(obj.getClass().getClassLoader())
_

と同じです

_Thread.currentThread().setContextClassLoader(AnyClass.class.getClassLoader())
_

第三に、Thread.currentThread().setContextClassLoader(getClass().getClassLoader())を呼び出すコードの前にThread.currentThread().getContextClassLoader()を呼び出す必要があります。第4に、多くのAPKが関係している場合は、Thread.setContextClassLoader(getClass().getClassLoader())afterを呼び出す必要があります(そうでない場合、最後のAPKをロードすると、手動で設定したものが上書きされます)。そのため、以下のデバッグトリックを使用して、この場合にコンテキストクラスローダーを使用しているユーザーを見つけることをお勧めします。次に、その直前に、目的のAPK、通常は最初に読み込まれるAPK(または、APKが1つしかない場合は、そのAPK;)のクラスに対してThread.setContextClassLoader(getClass().getClassLoader())を呼び出します。第5に、コンテキストクラスローダーはスレッドごとです。これは、アプリケーションがマルチスレッドの場合に注意する必要があります。

デバッグトリック

ClassLoader.getResources()を呼び出すコードを知りたい場合は、次のように機能するはずです。

_Thread.currentThread().setContextClassLoader(new ClassLoader() {
    @Override
    public Enumeration<URL> getResources(String resName) throws IOException {
        Log.i("Debug", "Stack trace of who uses " +
                "Thread.currentThread().getContextClassLoader()." +
                "getResources(String resName):", new Exception());
        return super.getResources(resName);
    }
});
_

これを十分に早く行うと、ダミークラスローダーでgetResources()を呼び出した人に戻るスタックトレースがlogcatに表示されます。

35

マニフェストにAndroid:sharedUserIdまたはAndroid:processのいずれも含まれていないこの警告を受け取りました...

エミュレーターでのみ表示されることがわかりました...

デバイスは警告メッセージを表示しませんでした。 Smartphone KitKat 4.4 API19およびTablet5.0.1 API21でテスト済み。

0
WM1