问题
This is sort of an update to an older question I asked, I made it into a new question since I have a lot of new information and I never got any useful answers. I have sort of fixed the issue but I want to understand why.
The old questions:
java.util.MissingResourceException: Can't find bundle for base name javax.servlet.LocalStrings
Basically, a tiny percentage of my users will experience this crash.
Fatal Exception: java.lang.ExceptionInInitializerError
at MyApp$2.run(MyApp.java:364)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'void java.util.jar.JarVerifier.removeMetaEntries()' on a null object reference
at java.util.jar.JarFile.getInputStream(JarFile.java:381)
at libcore.net.url.JarURLConnectionImpl.getInputStream(JarURLConnectionImpl.java:222)
at java.net.URL.openStream(URL.java:470)
at java.lang.ClassLoader.getResourceAsStream(ClassLoader.java:444)
at java.util.ResourceBundle.handleGetBundle(ResourceBundle.java:516)
at java.util.ResourceBundle.handleGetBundle(ResourceBundle.java:542)
at java.util.ResourceBundle.handleGetBundle(ResourceBundle.java:542)
at java.util.ResourceBundle.getBundle(ResourceBundle.java:228)
at java.util.ResourceBundle.getBundle(ResourceBundle.java:139)
at javax.servlet.GenericServlet.(GenericServlet.java)
at MyApp$2.run(MyApp.java:364)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
This is happening when my app is trying to instantiate a Servlet
. Basically GenericServlet
is trying to load a resource, these are the lines it seems to be crashing on:
private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
private static ResourceBundle lStrings =
ResourceBundle.getBundle(LSTRING_FILE);
My app creates that Servlet
as soon as it starts, basically on the onCreate
of the Application
class. So the fix for the crash I found, is ugly but it works. If I create the Servlet
instance inside a thread launched from onCreate
then it will crash for some users. If I instead create the Servlet
on onCreate
without delaying it, then it won't crash.
Basically this won't crash:
public void onCreate() {
.....
new MyServlet();
.....
But this will:
public void onCreate() {
.....
new Thread(){..... new Servlet();}
.....
So my guess is that multidex is making sure to keep the javax
classes and resources on the main dex file when it sees the Servlet
creation on onCreate
. But as I mentioned on that previous question, I'm attempting to use multiDexKeepFile
and more recently I've tried multiDexKeepProguard
. So why aren't they working?
My latest attempt with multiDexKeepProguard
in desperation was:
-keep class javax.servlet.http.HttpServlet
-keep class javax.servlet.GenericServlet
-keep class javax.servlet.*
-keep class javax.servlet.LocalStrings
-keepclassmembers class javax.servlet.LocalStrings
But it didn't help. The only thing that has helped is moving the first Servlet
instantiation outside of the Thread
and into onCreate
. All subsequent Servlet
creations and the start of the server happen on a Thread
without issue.
So what am I doing wrong?
Thanks.
来源:https://stackoverflow.com/questions/47930299/multidex-app-cant-find-jar-resource-but-only-on-some-phones