I have distributed the application on the Android Marketplace. I get error reports from a small part of users (maybe 2%), where they get NullPointerExceptions, where this makes no logical sense.
I could never reproduce it myself. The code is relatively simple and is a common code path that every user must follow. I actually took every single line of code that could create an NPE and wrap it in a try-catch block and throw a custom runtime exception, but I still get NullPointerException errors that were not detected.
At this moment, the only thing I can imagine is something related to my involvement with Proguard. I saw how some other articles talked about taking out the -overloadaggressively option if you noticed strange behavior, but as far as I can tell, I don't use this option.
Has anyone else experienced the mysterious NPEs using android and proguard. Are there other settings that people can recommend for a set of optimizations that can cause this problem?
Any other ideas?
For reference, here is an unobservable function that gets NPE:
public MainMenuScreen(final HauntedCarnival game) { super(game); game.startMusic("data/music/intro.mp3"); stage = new Stage(Screen.SCREEN_WIDTH, Screen.SCREEN_HEIGHT,true); stage.addActor(new Image("background", Assets.mainMenuBackground)); Image title = new Image("title", Assets.mainMenuTitle); title.x = 0; title.y = 340; resetEyeBlink(); stage.addActor(title); dispatcher.registerInputProcessor(stage); settings = game.getSettings(); eyeBlinkImage = new Image("eyeBlink", Assets.eyeBlink); if (settings.getPlayers().isEmpty()) { settings.addPlayer("Player One"); settings.save(game); } setupContinue(); }
So the only features that I see are the game, the dispatcher, and the settings.
the game is installed through this code in another class. the game is the final variable in this other class:
game.setScreen(new MainMenuScreen(game));
the dispatcher gets installed inside when calling super above.
getSettings () returns the settings object, which is installed at the very beginning of the application, is closed and never canceled. It has also been used several times before this method.
There are no primitives for automatic boxing.
here is the proguard configuration:
-optimizationpasses 5 -dontusemixedcaseclassnames -dontskipnonpubliclibraryclasses -dontpreverify -verbose -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* -keepattributes Signature -keep public class com.alkilabs.hauntedcarnival.settings.Settings -keep public class com.alkilabs.hauntedcarnival.settings.Settings { *; } -keep public class com.alkilabs.hauntedcarnival.settings.Player -keep public class com.alkilabs.hauntedcarnival.settings.Player { *; } -keepnames public class com.alkilabs.hauntedcarnival.world.World -keepnames public class * extends com.alkilabs.hauntedcarnival.world.upgrades.Upgrade -keepnames public class * extends com.alkilabs.hauntedcarnival.world.achievments.Achievement -keepnames public class com.alkilabs.hauntedcarnival.world.monsters.MonsterType -keepclassmembers class * extends com.alkilabs.hauntedcarnival.world.monsters.Monster { public <init>(com.alkilabs.hauntedcarnival.world.monsters.MonsterType, java.lang.Integer, com.alkilabs.hauntedcarnival.world.World); } -keepnames public class com.alkilabs.hauntedcarnival.world.items.ItemType -keepclassmembers class * extends com.alkilabs.hauntedcarnival.world.items.Item { public <init>(com.alkilabs.hauntedcarnival.world.World, java.lang.Integer, java.lang.Integer); } -keep public class * extends android.app.Activity -keep public class * extends android.app.Application -keep public class * extends android.app.Service -keep public class * extends android.content.BroadcastReceiver -keep public class * extends android.content.ContentProvider -keep public class * extends android.app.backup.BackupAgentHelper -keep public class * extends android.preference.Preference -dontwarn com.badlogic.gdx.scenes.scene2d.ui.utils.DesktopClipboard -dontwarn com.badlogic.gdx.utils.JsonWriter -dontwarn com.badlogic.gdx.utils.XmlWriter -keepclasseswithmembernames class * { native <methods>; } -keepclasseswithmembers class * { public <init>(android.content.Context, android.util.AttributeSet); } -keepclasseswithmembers class * { public <init>(android.content.Context, android.util.AttributeSet, int); } -keepclassmembers class * extends android.app.Activity { public void *(android.view.View); } -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); } -keep class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator *; }