【Android】端末の通知設定画面から通知をオフにするとアプリケーションごと再生成されるから気をつけろという話
はじめに
わりと記事タイトルそのままなんですが、Activity どころか Application ごと再生成されるのが衝撃だったので備忘録代わりに記載しておきます。
端末の通知設定画面
アプリ側でPush通知を実装している(Manifestに <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
を宣言している )場合、端末の「設定→アプリ→通知」内に通知設定画面が表示されます。
ここのトグルをONからOFFに切り替えると、 Applicationクラスごと再生成される というのが今回のトピックです。
確認方法
通知の実装などは省略します。アプリの通知が実装されているものとして話を進めます。
通知について知りたい人は以下の公式リンクなどを参考にしてください。
Application クラスの onCreate
に以下のようなログを仕込んでおきます。
class App: Application() {
override fun onCreate() {
super.onCreate()
Log.d("Application", "Application onCreated")
}
}
アプリから通知設定画面を開く実装はこんな感じです。
val intent = Intent()
intent.action = android.provider.Settings.ACTION_APP_NOTIFICATION_SETTINGS
intent.putExtra("app_package", context.packageName)
intent.putExtra("app_uid", context.applicationInfo.uid)
intent.putExtra("android.provider.extra.APP_PACKAGE", context.packageName)
context.startActivity(intent)
上記の実装をボタンを押した時などに実行し、端末の通知設定から通知のトグルをON→OFFに切り替えます。
その後、アプリ側の画面に戻ると、Application onCreated
ログが発火しています。
何が困るか
アプリが再生成されるということは、 シングルトンのインスタンスも一度作り直される ということです。
試しに以下のようなシングルトン object を作成し、何度か add
メソッドを実行した後に前述の操作を行ったところ、変数 wordList
の中身が全て消えていました。
object SingletonObject {
private val wordList: MutableList<String> = mutableListOf()
fun add() {
wordList.add("test")
}
}
しかも厄介なことに、この時画面遷移の状態は維持されています。
例えば「アプリの設定画面から上記の通知設定画面へ遷移させ、ユーザーが設定変更後にアプリ側の設定画面に戻る」というようなユースケースは普通に考えられますが、この時シングルトンのクラスにアプリの状態などが保持されていた場合、すべての状態が初期化されてしまうということになります。
通常、シングルトンのクラスは「アプリをキルする(≒画面も初期状態に戻る)まで保持されるもの」と考えて実装する場合が多いと思いますので、「画面遷移の状態を保ったまま Application やシングルトンが再生成される場合がありうる」 という今回のケースは、かなりの盲点ではないかなと思います。
おわりに
サーバーやローカルDBを使うほどでもない、アプリが生きている間だけ保持できていればいい情報の保持にシングルトンクラスを使う、というケースはよくあると思います。
そういう時に、この記事の内容を一度思い出してもらえると予期せぬ不具合の発生を防げるかもしれません。
Discussion