Android:"类加载器可能会因托管多个应用程序的进程而失败"

caw*_*caw 21 multithreading android classloader

Eclipse的logcat for Android中的这条消息是什么意思?

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());
Run Code Online (Sandbox Code Playgroud)

不幸的是,没有关于此警告的上下文,所以我不知道是什么导致了这个问题以及我如何解决它.

Mar*_*lts 35

背景资料

该消息意味着,Android有设置一个虚拟ClassLoaderThread.currentThread().setContextClassLoader(),以及一些尝试使用虚拟的类加载器.该东西可以是很多东西,很难从所给的信息正是告诉.你可以尝试一下,见下文.无论如何,当存在进程可能包含来自多个APK的代码的风险时,Android会设置虚拟类加载器.更具体地说,如果您使用过,Android会在您的清单中查找android:sharedUserId:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    android:sharedUserId="triggers.dummy.loader" >
Run Code Online (Sandbox Code Playgroud)

或者如果你以非标准运行 android:process

    <application android:process="triggers.dummy.loader">
Run Code Online (Sandbox Code Playgroud)

如何摆脱警告

你可以做两件事来摆脱警告:

  1. 不要使用android:sharedUserIdandroid:process
  2. ClassLoader在运行任何其他代码之前,明确设置要使用的APK

要使用解决方案2,您需要一些关键的见解.首先,对于AnyClassAPK中的任何类,AnyClass.class.getClassLoader()将返回相同的ClassLoader.第二,

AnyClass obj = new AnyClass();
Thread.currentThread().setContextClassLoader(obj.getClass().getClassLoader())
Run Code Online (Sandbox Code Playgroud)

是相同的

Thread.currentThread().setContextClassLoader(AnyClass.class.getClassLoader())
Run Code Online (Sandbox Code Playgroud)

第三,你需要在调用Thread.currentThread().setContextClassLoader(getClass().getClassLoader())的代码之前调用Thread.currentThread().getContextClassLoader().第四,当涉及到许多APK时,您需要在加载最后一个APK Thread.setContextClassLoader(getClass().getClassLoader()) 调用(否则加载最后一个APK将覆盖您手动设置的内容).因此,通过使用下面的调试技巧,找出谁在使用上下文类加载器是个好主意.然后,在此之前,您需要Thread.setContextClassLoader(getClass().getClassLoader())从所需的APK中调用一个类,通常是首先加载的APK(或者,在涉及仅一个APK的情况下,该APK;).第五,上下文类加载器是每个线程,如果你的应用程序是多线程的,你需要记住它.

调试技巧

如果你想找出调用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);
    }
});
Run Code Online (Sandbox Code Playgroud)

如果你做得这么早,你应该在logcat中看到一个堆栈跟踪,它可以追溯到调用getResources()虚拟类加载器的人.