We're getting an IllegalStageException when trying to initialize our shared preferences singleton class but I don't know what's causing it.
Can anyone here advise me as to what may be causing this?
NOTE: This is ONLY happening on Pie
Here's the report from the Google Play Console (crash is not showing in Crashlytics):
java.lang.RuntimeException:
at android.app.ActivityThread.handleBindApplication (ActivityThread.java:5876)
at android.app.ActivityThread.access$1100 (ActivityThread.java:199)
at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1650)
at android.os.Handler.dispatchMessage (Handler.java:106)
at android.os.Looper.loop (Looper.java:193)
at android.app.ActivityThread.main (ActivityThread.java:6669)
at java.lang.reflect.Method.invoke (Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:858)
Caused by: java.lang.IllegalStateException:
at android.app.ContextImpl.getSharedPreferences (ContextImpl.java:419)
at android.app.ContextImpl.getSharedPreferences (ContextImpl.java:404)
at android.content.ContextWrapper.getSharedPreferences (ContextWrapper.java:174)
at com.nbc.news.utils.SharedPreferences.<init> (SharedPreferences.java:27)
at com.nbc.news.utils.SharedPreferences.init (SharedPreferences.java:44)
at com.nbc.news.NbcNews.onCreate (NbcNews.java:122)
at android.app.Instrumentation.callApplicationOnCreate (Instrumentation.java:1154)
at android.app.ActivityThread.handleBindApplication (ActivityThread.java:5871)
Here's the init code:
private android.content.SharedPreferences sharedPreferences;
private static SharedPreferences instance;
private SharedPreferences(Context context) {
Context appContext = context.getApplicationContext();
sharedPreferences = appContext.getSharedPreferences(context.getString(R.string.database_name), Context.MODE_PRIVATE); // <- this is line #27
}
public android.content.SharedPreferences getPreference(){
return sharedPreferences;
}
public static SharedPreferences getInstance() {
if (instance == null) {
throw new RuntimeException("SharedPreferences must be initialized with context prior to use");
}
return instance;
}
public static void init(Context context) {
if (instance == null) {
instance = new SharedPreferences(context); // <- this is line #44
}
}
I only found one or two puzzle pieces which may be helpful: the source code of ContextImpl has two IllegalStateException
s, one of them from a method getSharedPreferences()
in line 426-454.
"SharedPreferences in credential encrypted storage are not available until after user is unlocked"
This IllegalStateException
is thrown from an if
block which is executed only if the target SDK version is Oreo or higher
if (getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.O) {
if (isCredentialProtectedStorage()
&&
!getSystemService(UserManager.class).isUserUnlockingOrUnlocked(UserHandle.myUserId())) {
throw new IllegalStateException("SharedPreferences in credential encrypted "
+ "storage are not available until after user is unlocked");
}
}
Searching the web for isCredentialProtectedStorage()
led me to FileBasedEncryption.
Since I don't know the details of your app's workflow I can only suggest to make sure that the app does not try to access a secured file while the device is locked.
You must be trying to access SharedPreferences
after LOCKED_BOOT_COMPLETED
and before BOOT_COMPLETED
which isn't allowed since Nougat / API 24 unless you migrate your preferences to the Device Protected Storage.
2 options here:
LOCKED_BOOT_COMPLETED
action and the android:directBootAware
flag from your Broadcast Receiver. This way your app will wait till BOOT_COMPLETED
(when the user unlocks the device) before trying to access SharedPreferences
.SharedPreferences
after LOCKED_BOOT_COMPLETED
and before BOOT_COMPLETED
, make sure your migrate your preferences to the Device Protected Storage and use Device Protected Storage Context when calling getSharedPreferences()
.More details on the second option in the official docs: Support Direct Boot mode
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With