前人未踏の領域へ Androidアプリ開発編

Androidアプリ開発に関する調査メモ置き場。古い記事にはアプリ以外も含まれます。

WorkManager.getInstanceでIllegalStateException

課題

一部の端末(例えば Zenfone 3など) でアプリが起動しないという事象が発生している。スタックトレースを見るとWokrManagerのgetInstanceするところでクラッシュしていた。

Caused by: java.lang.IllegalStateException: 
  at androidx.work.impl.WorkManagerImpl.getInstance (WorkManagerImpl.java:140)
  at androidx.work.WorkManager.getInstance (WorkManager.java:180)

どうすればよいか。

原因

WorkManagerImpl.javaのgetInstanceメソッドを参照すると以下のような感じになっている。 https://android.googlesource.com/platform/frameworks/support/+/androidx-master-dev/work/workmanager/src/main/java/androidx/work/impl/WorkManagerImpl.java

    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static @NonNull WorkManagerImpl getInstance(@NonNull Context context) {
        synchronized (sLock) {
            WorkManagerImpl instance = getInstance();
            if (instance == null) {
                Context appContext = context.getApplicationContext();
                if (appContext instanceof Configuration.Provider) {
                    initialize(
                            appContext,
                            ((Configuration.Provider) appContext).getWorkManagerConfiguration());
                    instance = getInstance(appContext);
                } else {
                    throw new IllegalStateException("WorkManager is not initialized properly.  You "
                            + "have explicitly disabled WorkManagerInitializer in your manifest, "
                            + "have not manually called WorkManager#initialize at this point, and "
                            + "your Application does not implement Configuration.Provider.");
                }
            }

            return instance;
        }
    }

if (appContext instanceof Configuration.Provider) { がポイントで、ApplicationクラスではConfiguration.Providerを実装していないので通常 false で例外をくらうことになると思うが、 本来はライブラリの方でアプリの起動時にカスタムContentProviderを使用して自身を初期化してくれているため、特に何もしなくても他の端末だとエラーにはならない。

対応1

追記 SonyXperia Z5 Premium(SO-03H)にて同一箇所でクラッシュ発生 。 なぜ駄目なのかが判然としないが、対応1では解決しないらしい。

ApplicationContextでConfiguration.Providerを実装しといてあげればとりあえずクラッシュは避けられそう。 ということでMyApplicationでConfiguration.Provider をimplementすることに。 getWorkManagerConfiguration の実装が必要になるが、WorkManagerInitializer.java 内のデフォルト実装にそろえておけばよいだろう。

class MyApplication : MultiDexApplication(), Configuration.Provider {

    override fun getWorkManagerConfiguration(): Configuration {
        return Configuration.Builder().build()
    }
}

対応2

自前で初期化する方法もある。この場合はProvider側でのデフォルト初期化を無効化しておく必要がある(忘れるとクラッシュ)。

<provider
    android:name="androidx.work.impl.WorkManagerInitializer"
    android:authorities="${applicationId}.workmanager-init"
    tools:node="remove" />
class MyApplication : MultiDexApplication(), Configuration.Provider {
    override fun onCreate() {
        WorkManager.initialize(this, Configuration.Builder().build())
    }
}

参考

developer.android.com