Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<h2>Background information</h2> <p>The message means that Android has setup a dummy <code>ClassLoader</code> with <code>Thread.currentThread().setContextClassLoader()</code>, and something tries to use that dummy class loader. The <em>something</em> can be a lot of things, it's hard to tell exactly what from the information given. There is a trick you can try though, see below. Anyway, Android sets up the dummy class loader when there is a risk that the process might contain code from more than one APK. More specifically, Android looks in your manifest if you have used <code>android:sharedUserId</code>:</p> <pre><code>&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android" ... android:sharedUserId="triggers.dummy.loader" &gt; </code></pre> <p>or if you run in a non-standard <code>android:process</code></p> <pre><code> &lt;application android:process="triggers.dummy.loader"&gt; </code></pre> <h2>How to get rid of the warning</h2> <p>There are two things you can do to get rid of the warning:</p> <ol> <li>Don't use <code>android:sharedUserId</code> or <code>android:process</code></li> <li>Explicitly set what APK <code>ClassLoader</code> to use before running any other code</li> </ol> <p>To go with solution 2, there are some key insights you need. First, for any class <code>AnyClass</code> in an APK, <code>AnyClass.class.getClassLoader()</code> will return the same <code>ClassLoader</code>. Second,</p> <pre><code>AnyClass obj = new AnyClass(); Thread.currentThread().setContextClassLoader(obj.getClass().getClassLoader()) </code></pre> <p>is the same as</p> <pre><code>Thread.currentThread().setContextClassLoader(AnyClass.class.getClassLoader()) </code></pre> <p>Third, you need to call <code>Thread.currentThread().setContextClassLoader(getClass().getClassLoader())</code> before the code that calls <code>Thread.currentThread().getContextClassLoader()</code>. Fourth, When many APKs are involved, you need to call <code>Thread.setContextClassLoader(getClass().getClassLoader())</code> <em>after</em> the last APK has been loaded (otherwise loading the last APK will overwrite what you have set manually). Because of that, it would be a good idea to find out who is using the context class loader in you case by using the below debug trick. Then, right before that, you call <code>Thread.setContextClassLoader(getClass().getClassLoader())</code> for a class from the desired APK, typically the APK that is loaded first (or, in the case when only one APK is involved, that APK ;). Fifth, the context class loader is <em>per thread</em>, which you need to keep in mind if your application is multi-threaded.</p> <h2>Debug trick</h2> <p>If you want to find out what code that calls ClassLoader.getResources(), this should work:</p> <pre><code>Thread.currentThread().setContextClassLoader(new ClassLoader() { @Override public Enumeration&lt;URL&gt; 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); } }); </code></pre> <p>if you do this early enough, you should see in the logcat a stack trace that goes back to whoever calls <code>getResources()</code> on the dummy class loader.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload