Ответ 1
Фоновая информация
Сообщение означает, что Android установил манекен ClassLoader
с помощью Thread.currentThread().setContextClassLoader()
, и что-то пытается использовать этот загрузочный загрузчик. Что-то может быть много, трудно точно сказать, что из приведенной информации. Есть трюк, который вы можете попробовать, см. Ниже. В любом случае, Android устанавливает загрузчик фиктивного класса, если существует риск того, что процесс может содержать код из нескольких APK. Более конкретно, Android выглядит в вашем манифесте, если вы использовали android:sharedUserId
:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
...
android:sharedUserId="triggers.dummy.loader" >
или если вы запускаете нестандартный android:process
<application android:process="triggers.dummy.loader">
Как избавиться от предупреждения
Есть две вещи, которые вы можете сделать, чтобы избавиться от предупреждения:
- Не используйте
android:sharedUserId
илиandroid:process
- Явным образом задайте APK
ClassLoader
для использования перед запуском любого другого кода.
Чтобы пойти с решением 2, вам нужны некоторые ключевые идеи. Во-первых, для любого класса AnyClass
в APK, 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()
.
В-четвертых, когда задействовано много APK, вам нужно позвонить Thread.setContextClassLoader(getClass().getClassLoader())
после того, как был загружен последний APK (в противном случае загрузка последнего 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);
}
});
если вы сделаете это достаточно рано, вы должны увидеть в logcat трассировку стека, которая возвращается к тому, кто называет getResources()
в загрузчике фиктивного класса.