365連休

にわかのandroidとかの開発メモ。

Android Studio 3.5 ApplicationクラスのライフサイクルとHandler#postの挙動

f:id:neet_rookie:20200203135329p:plain

Applicationクラスのライフサイクルめも

経緯

new Handler().postってアプリを離れても動いてる!!!!???? 

 

 

Applicationクラスのライフサイクルメソッド

  • public void onCreate() アプリケーション起動時
  • public void onTerminate() エミュレート環境でのみコール
  • public void onConfigurationChanged(@NonNull Configuration newConfig) 画面回転など
  • public void onLowMemory() Androidシステムのメモリが足りなくなった時(バックグラウンドプロセスを全て殺す時)
  • public void onTrimMemory(int level) メモリをトリムするのにいいと判断された時

 

 

Handler#postはいつ実行されなくなるのか

× Activityを離れた時

× アプリケーションを離れたとき

〇 アプリを離れ、かつ、起動中のアプリ一覧から削除された時(プロセスが死んだとき)

 

 

検証コード

Applicationクラスで繰り返しpost処理を行い、無限にStringBuffer#appendを行った結果、OutOfMemoryで死亡するアプリ。

マニフェストのApplicationタグのandroid:nameにGodクラスを指定すること。

public class God extends Application {
    private static final @NonNull String LOGTAG = "God";
    private int counter = 0;
    private StringBuffer buf = new StringBuffer();
    public God() {
        super();
final @NonNull Handler handler = new Handler(); final @NonNull Runnable loopRun = new Runnable(){ @Override public void run() { Log.d(LOGTAG, "looperテスト "+(++counter)+" 回目 buf.length()/1000="+(buf.length()/1000)); try { for(int i=0; i<1000*100; i++){ buf.append(this.getClass().toString()); //いずれOutOfMemoryで死亡する。 } Thread.sleep(1000); //1秒 } catch (InterruptedException e) { e.printStackTrace(); } handler.post(this); } }; handler.post(loopRun);
} /** アプリケーションの起動時に一度だけ実行される。<br/> * 一度アプリを離れてから戻った時はコールされない。 */ @Override public void onCreate() { Log.d(LOGTAG, "onCreate"); super.onCreate(); } /** エミュレートされた環境でのみコールされる。実機ではコールされない。 */ @Override public void onTerminate() { Log.d(LOGTAG, "onTerminate"); super.onTerminate(); } /** アプリを開いていなくても画面回転があればコールされる */ @Override public void onConfigurationChanged(@NonNull Configuration newConfig) { Log.d(LOGTAG, "onConfigurationChanged"); super.onConfigurationChanged(newConfig); } /** メモリが足りなくてバックグラウンドプロセスが全て殺される時にコールされる。 */ @Override public void onLowMemory() { Log.d(LOGTAG, "onLowMemory"); super.onLowMemory(); } /** メモリをトリムするのにいいと判断された時にコールされる(?) */ @Override public void onTrimMemory(int level) { Log.d(LOGTAG, "onTrimMemory(level="+level+")"); super.onTrimMemory(level); } }

 

実行ログ

Android 5.0 エミュレータ 途中でアプリを離れた

02-03 04:18:51.583 23796-23796/jp.********** D/God: onCreate
02-03 04:18:51.584 23796-23796/jp.********** D/God: onTrimMemory(level=5)
02-03 04:18:51.953 23796-23796/jp.********** D/God: looperテスト 1 回目 buf.length()/1000=0
02-03 04:18:53.216 23796-23796/jp.********** D/God: looperテスト 2 回目 buf.length()/1000=4200
02-03 04:18:54.843 23796-23796/jp.********** D/God: looperテスト 3 回目 buf.length()/1000=8400
02-03 04:18:55.984 23796-23796/jp.********** D/God: looperテスト 4 回目 buf.length()/1000=12600
02-03 04:18:57.109 23796-23796/jp.********** D/God: looperテスト 5 回目 buf.length()/1000=16800
02-03 04:18:58.275 23796-23796/jp.********** D/God: looperテスト 6 回目 buf.length()/1000=21000
02-03 04:18:59.394 23796-23796/jp.********** D/God: onTrimMemory(level=80)
//ホームボタンによりアプリを離れた。 02-03 04:18:59.399 23796-23796/jp.********** D/God: looperテスト 7 回目 buf.length()/1000=25200 02-03 04:19:00.613 23796-23796/jp.********** D/God: looperテスト 8 回目 buf.length()/1000=29400 02-03 04:19:01.742 23796-23796/jp.********** D/God: looperテスト 9 回目 buf.length()/1000=33600 02-03 04:19:02.860 23796-23796/jp.********** D/God: looperテスト 10 回目 buf.length()/1000=37800 02-03 04:19:03.022 23796-23796/jp.********** E/AndroidRuntime: FATAL EXCEPTION: main Process: jp.*********, PID: 23796 java.lang.OutOfMemoryError: Failed to allocate a 113607328 byte allocation with 2097152 free bytes and 51MB until OOM at java.lang.AbstractStringBuilder.enlargeBuffer(AbstractStringBuilder.java:95) at java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java:146) at java.lang.StringBuffer.append(StringBuffer.java:219) at jp.**********.God$1.run(God.java:23) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5254) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

 

Android 5.0 エミュレータ 途中でアプリ一覧から削除した

02-03 05:03:42.396 24695-24695/jp.********** D/God: onCreate
02-03 05:03:42.701 24695-24695/jp.********** D/God: looperテスト 1 回目 buf.length()/1000=0
02-03 05:03:43.991 24695-24695/jp.********** D/God: looperテスト 2 回目 buf.length()/1000=4200
02-03 05:03:45.614 24695-24695/jp.********** D/God: looperテスト 3 回目 buf.length()/1000=8400
02-03 05:03:46.789 24695-24695/jp.********** D/God: looperテスト 4 回目 buf.length()/1000=12600
02-03 05:03:47.915 24695-24695/jp.********** D/God: looperテスト 5 回目 buf.length()/1000=16800
02-03 05:03:49.069 24695-24695/jp.********** D/God: looperテスト 6 回目 buf.length()/1000=21000
02-03 05:03:50.231 24695-24695/jp.********** D/God: looperテスト 7 回目 buf.length()/1000=25200
02-03 05:03:51.427 24695-24695/jp.********** D/God: onTrimMemory(level=20)
02-03 05:03:51.436 24695-24695/jp.********** D/God: looperテスト 8 回目 buf.length()/1000=29400
//アプリ一覧から削除

 

Android 7.1.1 実機 途中でアプリを離れた

2020-02-03 13:20:53.831 22108-22108/jp.********** D/God: onCreate
2020-02-03 13:20:54.062 22108-22108/jp.********** D/God: looperテスト 1 回目 buf.length()/1000=0
2020-02-03 13:20:55.389 22108-22108/jp.********** D/God: looperテスト 2 回目 buf.length()/1000=4200
2020-02-03 13:20:57.901 22108-22108/jp.********** D/God: looperテスト 3 回目 buf.length()/1000=8400
2020-02-03 13:20:59.237 22108-22108/jp.********** D/God: looperテスト 4 回目 buf.length()/1000=12600
2020-02-03 13:21:00.617 22108-22108/jp.********** D/God: looperテスト 5 回目 buf.length()/1000=16800
2020-02-03 13:21:01.941 22108-22108/jp.********** D/God: looperテスト 6 回目 buf.length()/1000=21000
2020-02-03 13:21:03.351 22108-22108/jp.********** D/God: onTrimMemory(level=20)
//ホームボタンによりアプリを離れた。 2020-02-03 13:21:03.355 22108-22108/jp.********** D/God: looperテスト 7 回目 buf.length()/1000=25200 2020-02-03 13:21:04.695 22108-22108/jp.********** D/God: looperテスト 8 回目 buf.length()/1000=29400 2020-02-03 13:21:06.025 22108-22108/jp.********** D/God: looperテスト 9 回目 buf.length()/1000=33600 2020-02-03 13:21:07.290 22108-22108/jp.********** D/God: looperテスト 10 回目 buf.length()/1000=37800 2020-02-03 13:21:08.564 22108-22108/jp.********** D/God: looperテスト 11 回目 buf.length()/1000=42000 2020-02-03 13:21:09.139 22108-22108/jp.********** E/AndroidRuntime: FATAL EXCEPTION: main Process: jp.**********, PID: 22108 java.lang.OutOfMemoryError: Failed to allocate a 184549384 byte allocation with 8388608 free bytes and 98MB until OOM at java.util.Arrays.copyOf(Arrays.java:3352) at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:130) at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:114) at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:417) at java.lang.StringBuffer.append(StringBuffer.java:237) at jp.**********.God$1.run(God.java:23) at android.os.Handler.handleCallback(Handler.java:751) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:159) at android.app.ActivityThread.main(ActivityThread.java:6139) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

 

Android 7.1.1 実機 途中でアプリ一覧から削除した

2020-02-03 14:06:37.793 25133-25133/jp.********** D/God: onCreate
2020-02-03 14:06:37.976 25133-25133/jp.********** D/God: looperテスト 1 回目 buf.length()/1000=0
2020-02-03 14:06:39.257 25133-25133/jp.********** D/God: looperテスト 2 回目 buf.length()/1000=4200
2020-02-03 14:06:41.545 25133-25133/jp.********** D/God: looperテスト 3 回目 buf.length()/1000=8400
2020-02-03 14:06:42.909 25133-25133/jp.********** D/God: looperテスト 4 回目 buf.length()/1000=12600
2020-02-03 14:06:44.418 25133-25133/jp.********** D/God: onTrimMemory(level=20)
2020-02-03 14:06:44.418 25133-25133/jp.********** D/God: looperテスト 5 回目 buf.length()/1000=16800
2020-02-03 14:06:45.682 25133-25133/jp.********** D/God: looperテスト 6 回目 buf.length()/1000=21000
//アプリ一覧から削除