質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.69%

Androidで例外が発生した後のライフサイクルについて知りたい

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,627

arcanum_jp

score 76

Androidにおいて、例外が発生した場合のライフサイクルについて教えて頂きたいです。

下記のように、例えばMainActivity ⇒ SubActivityと遷移するアプリがあり、SubActivity側で例外が発生してしまった場合に、SubActivityが破棄され、表面上はMainActivityに戻ったように見えますがMainActivityで参照しているシングルトンなクラスオブジェクトが例外発生後ではインスタンスが変わってしまいます。

Logcat上では[D/AndroidRuntime: Shutting down VM ]のように出力され、例外が発生した場合は一度VMがシャットダウンされるのかなと言うのは予想がつきました。

そこで質問なのですが、例外が発生した場合のライフサイクルについて、どのようなシーケンスをたどるのか教えて頂きたいのです。Webで探したのですがなかなか見つからず、もし良いサイト等あれば教えていただきたいです。

以上、よろしくお願いします。

02-26 22:35:37.866 22074-22074/com.example.xxxxx.exceptionapp D/AndroidRuntime: Shutting down VM
02-26 22:35:37.866 22074-22074/com.example.xxxxx.exceptionapp W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x40d55ae0)
02-26 22:35:37.866 22074-22074/com.example.xxxxx.exceptionapp E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.RuntimeException: なんかエラー
 at com.example.shinyahosokawa.exceptionapp.SubActivity$1.onClick(SubActivity.java:37)
 at android.view.View.performClick(View.java:4278)
 at android.view.View$PerformClick.run(View.java:17430)
 at android.os.Handler.handleCallback(Handler.java:725)
 at android.os.Handler.dispatchMessage(Handler.java:92)
 at android.os.Looper.loop(Looper.java:213)
 at android.app.ActivityThread.main(ActivityThread.java:5092)
 at java.lang.reflect.Method.invokeNative(Native Method)
 at java.lang.reflect.Method.invoke(Method.java:511)
 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:797)
 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:564)
 at dalvik.system.NativeStart.main(Native Method)

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        Button b = (Button) findViewById(R.id.call_sub1);
        b.setOnClickListener(
                new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Intent i = new Intent(getBaseContext(), SubActivity.class);
                        startActivity(i);
                    }
                }
        );


        Button singleton = (Button) findViewById(R.id.showsingleton);
        singleton.setOnClickListener(
                new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        int hash = SingletonClass.getInstance().hashCode();
                        Toast.makeText(getBaseContext(), "singleton#hash: " + hash, Toast.LENGTH_SHORT).show();
                    }
                }
        );

    }
}
public class SubActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sub);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);


        Button b = (Button) findViewById(R.id.button);
        b.setOnClickListener(
                new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        throw new  RuntimeException("なんかエラー");
                    }
                }
        );


    }

}
public class SingletonClass {

    private static SingletonClass _instance;

    public static final SingletonClass getInstance() {
        if (_instance == null) {
            _instance = new SingletonClass();
        }
        return _instance;
    }

    private SingletonClass() {
        // private for singleton
    }

}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

0

参考URL→ライフサイクルの理解 その2 Process ライフサイクルの理解 その3 Task
私自身、完全には理解していないのですが、要点として

  1. アプリの他にstatic変数の管理などを司るProcess,画面を開いた順番を管理するTaskが存在する
  2. Processの消滅によりstatic変数が消滅しても、画面管理のTaskが生き残ることがある

以上を踏まえると、

  1. 例外が発生すると一旦Processが消滅しアプリが終了するが、Taskは生き残る。
  2. 例外が発生したActivityはTaskから消え、残りのActivityがTaskの記録順にしたがって開かれる
  3. Processが消滅しているため、シングルトンが再生成する

こういうことではないかと思います。余り説明になってないかもしれませんが…

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/02/27 12:00

    回答ありがとうございます。

    参考としていただいたリンク先、良いですね。まずAndroidのメモリ管理について理解しないといけないのかなと感じ始めています。

    リンク先を読んだだけで、結構理解が進みましたが、一方ワラワラと疑問が浮かんできました。

    いったん、メモリ管理について勉強してみたいと思います

    キャンセル

0

詳しい仕様ではなく、今までの経験からでなら答えられます。参考になればいいのですが。

一つのActivityで起こった例外が処理されない場合、例外は処理が行われるまでthrowされ続け、アプリ毎に割り振られた仮想マシンまで到達します。すると仮想マシンは停止するのでアプリ自体が終了します。

その後の処理は例外の発生した箇所がライフサイクルメソッド上かどうかによって変わります。ライフサイクルメソッド外で例外が発生するとアプリケーションは再起動し、すべてのデータが初期化されます。これはログキャットのプロセスIDからも確認できます。一方でライフサイクルメソッド上で例外が発生した場合は再起動せずに、ホーム画面または履歴の一番上にあるアプリケーションに戻ります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/02/27 11:28

    ありがとうございます。

    状況としては、回答にいただいたとおりで、例外発生でプロセスは一度死んでしまい、タスクは生き残っている、そのためタスクの順番に従い、アクティビティを表示しようとするという動きみたいですね。(プロセスが再起動なので、プロセス内で管理していたメモリは初期化される)

    UncaughtExceptionHandlerを設定していたのですが、コールバックでアプリが安全に死ぬような処理を書いたとしても、ログキャット上では再起動する旨が表示されていたので、例外発生時の処理はメモリに頼らない終了処理が必要かなと感じました。

    キャンセル

0

いったんこの質問については、以下の理解としています。

  1. 例外が発生すると一旦Processが消滅しアプリが終了するが、Taskは生き残る。
  2. 例外が発生したActivityはTaskから消え、残りのActivityがTaskの記録順にしたがって開かれる
  3. その際アプリ用のプロセスが再度生成される。
  4. 先ほどのProcessが消滅しているため、シングルトンオブジェクトは別のオブジェクトになる

この場合、アプリケーションがプロセス内のメモリとして持っているのは、ルートアクティビティから遷移していったアクティビティや、アプリで設計されたクラスのオブジェクト達、その他、タスクといったものは、アプリ以外でAndroid OS側で管理しているという認識です。

当初、例外が発生した場合に、UncaughtExceptionHandlerでアプリを終了するためにと言う目的で考えている時に、質問になった例外発生後、VMが再起動するという現象がなんで起こるのだろうという疑問が浮かんだわけです。(例外がおきたアクティビティだけ殺せばいいし、なぜVMの再起動まで必要なのだろうかと)

しかし、回答をいただいて少し勉強する限り、たとえば例外がOutOfMemoryなどのError系だった場合、当然メモリ内の整合性は保てないわけで、プロセスは殺さないといけないわけで、と言う事実を思い浮かべるのでした。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.69%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる