web-dev-qa-db-ja.com

Androidアプリが強制終了されたときに「onDestroy()」を呼び出さない(ICS)

私はAndroid=アプリをBluetooth通信を使用して(独自のプロトコルを使用して)開発しています。アプリが強制終了された瞬間をキャッチする必要があります。

「onDestroy()」メソッドを使用したかったのですが、アプリが強制終了されるたびに呼び出されるわけではありません。私は、戻るボタンを押したときに呼び出されることに気づきました。まれに、タスクマネージャーからアプリを強制終了したときにも呼び出されます。

問題は、アプリが終了する前の瞬間をどのように捉えればよいかということです。

これが私が使用しようとしたコードです:

@Override
public void onDestroy() {
    sendMessage(msg);
    Log.d("SampleApp", "destroy");
    super.onDestroy();
}

@Override
public void finish(){

    sendMessage(msg);
    Log.d("SampleApp", "finish");
    super.finish();
}

残念ながら、finish()は決して呼び出されず、タスクマネージャーからアプリを閉じるたびにonDestroyが呼び出されません。

どうすればこれを処理できますか?

22
The Good Giant

ドキュメント here に記載されているように、onDestroy()が呼び出されるという保証はありません。代わりに、 onPause() を使用して、アプリがバックグラウンドに移動するたびに実行したいことを行い、アプリが終了したときに実行するコードのみをonDestroy()に残します。

編集:

コメントから、アプリがバックグラウンドになるたびにコードを実行したいようですが、インテントを起動したためにバックグラウンドになった場合はそうではありません。 AFAIK、Androidにはデフォルトでこれを処理するメソッドはありませんが、次のようなものを使用できます:

次のようなブール値を持っている:

boolean usedIntent = false;

インテントを使用する前に、ブール値をtrueに設定します。次に、onPause()で、インテントケースのコードを次のようなifブロックに移動します。

if(usedIntent)
{
//Your code
}

最後に、onResume()でブール値をfalseに再度設定して、意図しない方法でアプリがバックグラウンドに移動された場合に適切に処理できるようにします。

15
Raghav Sood

外部の方法でプロセスが終了した場合(メモリ上の理由で強制終了された場合、またはユーザーがアプリケーションを強制停止した場合)、アプリケーションは追加のコールバックを受け取りません。アプリのクリーンアップのためにアプリがバックグラウンドに入ったときに受け取ったコールバックを処理する必要があります。

finish()は、ユーザーがアクティビティから[戻る]ボタンを押したときにのみシステムによって呼び出されますが、アクティビティを終了して前のアクティビティに戻るためにアプリケーションから直接呼び出されることがよくあります。これは技術的にはライフサイクルコールバックではありません。

onDestroy()は、finish()の呼び出しの結果としてアクティビティでのみ呼び出されるため、主にユーザーが[戻る]ボタンを押したときのみです。ユーザーがHOMEボタンを押すと、フォアグラウンドアクティビティはonPause()onStop()のみを通過します。

これは、Androidは、ユーザーが家に帰るのと別のアクティビティに移動する(アプリなどから)のユーザーを区別するために、アクティビティに多くのフィードバックを提供しない)ことを意味します。 Androidアプリケーションは、密接に統合された単一の概念(他のプラットフォームで慣れ親しんでいるような)よりも、アクティビティの緩いコレクションなので、実際のシステムコールバックはありません。アプリケーション全体としてがいつ前に進められたか、または後戻りされたかを知る。

結局のところ、アプリケーションのANYアクティビティがフォアグラウンドにあるかどうかの知識に依存している場合は、アプリケーションアーキテクチャを再検討することをお勧めしますが、必要に応じて、これを実現するためにフレームワークによりフレンドリーな方法が他にもあるかもしれません。 1つのオプションは、アクティブなときにすべてのServiceがバインドするバインド済みActivityをアプリケーション内に実装することです(つまり、onStart()onStop()の間)。これにより、バインドされたServiceはクライアントがバインドされている間のみ存続するという事実を活用できるため、onCreate()およびonDestroy()メソッドを監視できます。 サービスの現在のフォアグラウンドタスクがアプリケーションの一部ではないことを確認します。

また、Androidアーキテクチャと、Googleによるアーキテクチャの使用方法の詳細をカバーする興味深い記事として、ダイアンハックボーンが作成した この記事 も興味深いかもしれません。

14
Devunwired

同様の問題を解決しました。

最近のアプリリストからスワイプしてアプリケーションが強制終了されたときにサービスを停止する場合にできることを次に示します。

マニフェストファイル内で、サービスのフラグstopWithTasktrueとして保持します。お気に入り:

<service
    Android:name="com.myapp.MyService"
    Android:stopWithTask="true" />

しかし、リスナーの登録を解除して通知などを停止したいという場合は、このアプローチをお勧めします。

  1. マニフェストファイル内で、サービスのフラグstopWithTaskfalseとして保持します。お気に入り:

    <service
        Android:name="com.myapp.MyService"
        Android:stopWithTask="false" />
    
  2. MyServiceサービスで、メソッドonTaskRemovedをオーバーライドします。 (これは、stopWithTaskfalseに設定されている場合にのみ起動されます)。

    public void onTaskRemoved(Intent rootIntent) {
    
        //unregister listeners
        //do any other cleanup if required
    
        //stop service
        stopSelf();  
    }
    

詳細については この質問 を参照してください。コードの他の部分も含まれています。

  1. 以下のようなサービスを開始します

startService(new Intent(this、MyService.class));

お役に立てれば。

2
Naveen Kumar M