アプリが再開するのではなく再起動する


194

うまくいけば、解決策ではないにしても、少なくとも行動の説明を誰かが私に理解してくれることを願っています。

問題:

一部のデバイスでは、ランチャーアイコンを押すと現在のタスクが再開されます。その他のデバイスでは、初期起動インテントが起動されます(効果的にアプリを再起動します)。なぜこれが起こるのですか?

詳細:

「ランチャーアイコン」を押すと、アプリが正常に起動します。つまり、最初の名前でActivityアクションandroid.intent.action.MAINとカテゴリを指定してインテントが起動されますandroid.intent.category.LAUNCHER。ただし、常にそうであるとは限りません。

ほとんどのデバイスでは、アプリが既に実行されている後にランチャーアイコンを押すと、そのプロセスで現在実行中のアクティビティが再開されます(最初のアクティビティではありませんActivity)。OSメニューの「最近のタスク」から選択した場合と同じように再開します。これは、すべてのデバイスで必要な動作です。

ただし、選択した他のデバイスでは、異なる動作が発生します。

  • Motorola Xoomでは、ランチャーアイコンを押すと、現在実行中の内容に関係なく、アプリは常に最初の起動を開始しActivityます。ランチャーアイコンは常に「LAUNCHER」インテントを開始すると思います。

  • サムスンタブ2で、ランチャーアイコンを押すと、アプリをインストールしたばかりの場合、常にイニシャルActivity(Xoomと同じ)が起動しますが、インストール後にデバイスを再起動すると、ランチャーアイコンが代わりに起動しますアプリを再開します。これらのデバイスは、ランチャーアイコンが実行中のタスクを正しく再開できるようにする、デバイスの起動時に「インストール済みアプリ」をルックアップテーブルに追加すると思いますか?

私はそれを多くの答えを読んだ私の問題に似ていますが、単に追加android:alwaysRetainTaskState="true"または使用するlaunchMode="singleTop"にはActivity答えていません。

編集:

このアプリの最新の起動後、最初の再起動後にすべてのデバイスでこの動作が発生し始めていることがわかりました。気が狂っているように思えますが、再起動プロセスを調べても、実際には何が問題なのかを見つけることができません。


1
これは簡単な質問のように思えるかもしれませんが、Xoomの開発オプションで「アクティビティを保持しない」をtrueに設定しましたか?
Andrew Schuster

いいえ(希望します!:))-各アクティビティのライフサイクルとバックグラウンドでのアクティビティをまだ利用できるようにログに記録しました(停止されています-破棄されていません)。OSはfinish()、それらActivityを再開するのではなく、最初のものを再び開始する場合にそれらを要求するようです。
Graeme

1
ホームボタンを押してからランチャーアイコンをクリックした場合、おそらく気づいているように、再開動作はAndroidのデフォルトです。ただし、戻るボタンを押してホーム画面に戻ると、ほとんどの携帯電話でアプリが終了します。アプリを終了するために使用している方法がデバイスごとに異なる可能性はありますか?onKeyUpEventからログアウトして、一部のハード/ sof tkeyが奇妙に処理されていないことを確認できますか?
Nick Cardoso 2014年

2
いいえ-上記の問題は確かです。ホームを使用してアプリをバックグラウンドに配置します(戻るのではなく、アクティビティをfinish()します)。Xoomでは、(Launcherからではなく)タスクリストからアプリを再開することができるため、バックスタックは確実に削除されていません
Graeme

1
バウンティでの回答は、質問で説明されている問題を修正する方法です。自分の回答を「正解」としてマークしました。問題はランチャーのアプリのバグが原因である場合もありますが(回答で述べたように)、特定の問題はタスクの切り替えが原因でした。両方の問題の解決策は、彼の解決策によって修正されます。
Graeme

回答:


238

発生している動作の原因は、API 1以降の一部のAndroidランチャーに存在する問題です。https//code.google.com/p/android/issues/でバグの詳細と考えられる解決策を確認できます。 detail?id = 2373

これは、Samsungデバイスやカスタムランチャー/スキンを使用する他のメーカーでは比較的一般的な問題です。純正のAndroidランチャーで問題が発生するのを見たことはありません。

基本的に、アプリは実際には完全に再起動しているわけではありませんが、起動アクティビティが開始され、アプリがランチャーによって再開されているときにアクティビティスタックの一番上に追加されます。これが事実であることを確認するには、アプリを再開し、起動アクティビティが表示されているときに[戻る]ボタンをクリックします。次に、アプリを再開したときに表示されるはずのアクティビティに移動します。

この問題を解決するために実装することを選択した回避策は、Intent.CATEGORY_LAUNCHERカテゴリと、最初のアクティビティを開始するインテントのIntent.ACTION_MAINアクションを確認することです。これらの2つのフラグが存在し、アクティビティがタスクのルートにない(つまり、アプリが既に実行されている)場合は、最初のアクティビティでfinish()を呼び出します。その正確な解決策はうまくいかないかもしれませんが、同様の解決策が必要です。

これが、初期/起動アクティビティのonCreate()で行うことです。

    if (!isTaskRoot()
            && getIntent().hasCategory(Intent.CATEGORY_LAUNCHER)
            && getIntent().getAction() != null
            && getIntent().getAction().equals(Intent.ACTION_MAIN)) {

        finish();
        return;
    }

4
これまでのところ、これは私にとってはうまくいき、これまでのところ副作用はありません。論理的な仮定に基づくと、それが無効である理由はわかりません。
javahead76 2014

3
これはこのバグに対処する適切な方法だと思います。私のために働く。
ソコロフ2015

3
私のために仕事をしました、約8つの異なるデバイスで検証しました。どうもありがとう!
ajzner shaya

3
WOOOOOWは私の問題を修正し、過去2時間の修正を探していました
Jean Raymond Daher

2
ありがとう@ starkej2。魅力のように働いた。
Rajeev Sahu

54

この質問は2016年にも当てはまります。今日、QAテスターは、Android Mのストックランチャーから再開するのではなく、鉱山を再開するアプリを報告しました。

実際には、システムは起動されたアクティビティを現​​在のtask-stackに追加していましたが、ユーザーには再起動が発生し、作業が失われたように見えました。シーケンスは次のとおりです。

  1. Playストアからダウンロード(またはサイドロードAPK)
  2. Playストアダイアログからアプリを起動:アクティビティAが表示されます[タスクスタック:A]
  3. アクティビティBに移動する[タスクスタック:A-> B]
  4. 「ホーム」ボタンを押します
  5. アプリドロワーからアプリを起動:アクティビティAが表示されます![タスクスタック:A-> B-> A](ユーザーは[戻る]ボタンを押してここからアクティビティ 'B'に移動できます)

注:この問題は、ADB経由でデプロイされたAPKのデバッグでは発生せず、PlayストアからダウンロードされたAPKまたはサイドロードされたAPKでのみ発生します。後者の場合、ステップ5の起動インテントにはフラグIntent.FLAG_ACTIVITY_BROUGHT_TO_FRONTが含まれていましたが、デバッグの場合は含まれていませんでした。アプリがランチャーからコールドスタートされると、問題はなくなります。私の疑いは、タスクが完全にクリアされるまで正しい起動動作を妨げる不正な(より正確には、非標準の)インテントがタスクにシードされていることです。

さまざまなアクティビティ起動モードを試しましたが、これらの設定はユーザーが期待する標準の動作から大きく外れています。アクティビティBでタスクを再開します。ページの下部にある「タスクとバックスタック」のガイドで、予想される動作の次の定義を参照してください「タスクの開始」の下:

この種のインテントフィルターを使用すると、アクティビティのアイコンとラベルがアプリケーションランチャーに表示され、ユーザーはアクティビティを起動して、起動後にいつでも作成したタスクに戻ることができます。

私はこの回答が関連していることを発見し、ユーザーがアプリケーションを開いたときに適切に再開するように、ルートアクティビティ(A)の 'onCreate'メソッドに以下を挿入しました。

                    /**
     * Ensure the application resumes whatever task the user was performing the last time
     * they opened the app from the launcher. It would be preferable to configure this
     * behavior in  AndroidMananifest.xml activity settings, but those settings cause drastic
     * undesirable changes to the way the app opens: singleTask closes ALL other activities
     * in the task every time and alwaysRetainTaskState doesn't cover this case, incredibly.
     *
     * The problem happens when the user first installs and opens the app from
     * the play store or sideloaded apk (not via ADB). On this first run, if the user opens
     * activity B from activity A, presses 'home' and then navigates back to the app via the
     * launcher, they'd expect to see activity B. Instead they're shown activity A.
     *
     * The best solution is to close this activity if it isn't the task root.
     *
     */

    if (!isTaskRoot()) {
        finish();
        return;
    }

更新:このソリューションを、インテントフラグの解析から、アクティビティがタスクのルートに直接あるかどうかのクエリに移動しました。インテントフラグは、MAINアクティビティを開くさまざまな方法(ホームから起動、[上へ]ボタンから起動、Playストアから起動など)で予測およびテストすることが困難です。


4
「アプリがランチャーからコールドスタートされると、問題はなくなります。」これは最も奇妙な部分であり、私もそれを観察しました-最初の起動後にアプリを殺すと、再び正常に動作し始めます。そのような奇妙なバグ。徹底的に分析していただき、解決策をありがとうございました。
オデッド

11
注:Android Studio経由でAPKをインストールした場合でも、アプリのGoogle Playページから[開く]を使用すると、最初に問題をクリアした後(説明どおりにコールドスタートで)問題を再現できます。これは、修正が機能したことを確認するのに非常に役立ちました。
Oded

いい説明だ!
karanatwal.github.io 2017

この説明をありがとう:)
AndroidEnthusiast

2
これは多くのアプリで発生します。Googleフォトは私がテストした主要なものです。
Raghubansh Mani 2017

19

ああ!(tldr;下部の太字のステートメントを参照)

問題を見つけました...と思います。

だから、私は仮定から始めましょう。あなたはランチャーを押すと、それはどちらかのデフォルトを開始しActivityた場合、または、Task前回の起動によって開始されたが開いている、それは前にそれをもたらします。別の言い方をすると-ナビゲーションのいずれかの段階で新旧を作成するTaskfinish、ランチャーはアプリを再開しなくなります。

その仮定が真である場合、それぞれTaskが同じプロセスにあり、最初に作成されたものと同じくらい有効な履歴書候補であることを考えると、それはバグであると確信していますか?

私の問題は、これらのフラグをいくつかから削除することで修正されましたIntents

i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK );

FLAG_ACTIVITY_NEW_TASK新しいを作成することは明らかTaskですが、上記の仮定が有効であることを理解していませんでした。私はこれを犯人と見なし、テストのために削除しましたが、それでも問題が解決されなかったため、却下しました。しかし、私はまだ以下の条件を持っていました:

i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)

Activity上記のフラグを使用して、スプラッシュスクリーンがアプリの「メイン」を開始していました。結局のところ、私が自分のアプリを「再起動」し、それActivityがまだ実行されている場合、私はむしろその状態情報を保持したいと思います。

あなたはそれが新しいものを始めることについて言及していないドキュメントで気づくでしょうTask

設定されていて、起動されているアクティビティが現在のタスクで既に実行されている場合、そのアクティビティの新しいインスタンスを起動する代わりに、その上にある他のすべてのアクティビティが閉じられ、このインテントが(今は上)新しいインテントとしての古いアクティビティ。

たとえば、アクティビティA、B、C、Dで構成されるタスクを考えてみます。DがアクティビティBのコンポーネントに解決されるインテントでstartActivity()を呼び出すと、CとDは終了し、Bは指定されたインテントを受け取りますの結果、スタックはA、Bになります。

上記の例で現在実行中のアクティビティBのインスタンスは、ここで開始する新しいインテントをonNewIntent()メソッドで受け取るか、それ自体が終了して新しいインテントで再起動されます。起動モードが「複数」(デフォルト)であると宣言していて、同じインテントでFLAG_ACTIVITY_SINGLE_TOPを設定していない場合、終了して再作成されます。他のすべての起動モードの場合、またはFLAG_ACTIVITY_SINGLE_TOPが設定されている場合、このインテントは現在のインスタンスのonNewIntent()に配信されます。

この起動モードは、FLAG_ACTIVITY_NEW_TASKと組み合わせて効果的に使用することもできます。タスクのルートアクティビティを開始するために使用すると、そのタスクの現在実行中のインスタンスがフォアグラウンドになり、ルート状態にクリアされます。これは、たとえば、通知マネージャーからアクティビティを起動するときに特に役立ちます。

だから、私は以下のような状況にありました:

  • Aで起動BFLAG_ACTIVITY_CLEAR_TOPA終了します。
  • Bサービスを再起動したいのでA、サービス再起動ロジックとUI(フラグなし)を持つユーザーを送信します。
  • ABFLAG_ACTIVITY_CLEAR_TOPで起動し、A終了します。

この段階で、タスクスタックにある2番目のFLAG_ACTIVITY_CLEAR_TOPフラグが再起動してBいます。これはを破壊しTaskて新しいものを開始する必要があると思います。私の問題を引き起こします。これは、私に尋ねると非常に難しい状況です。

だから、私の仮定がすべて正しい場合:

  • Launcherだけ最初に作成したタスクを再開します
  • FLAG_ACTIVITY_CLEAR_TOP残りののみを再起動する場合Activityは、新しいTask

FLAG_ACTIVITY_CLEAR_TOPは、新しいタスクを作成したり、残っている唯一のアクティビティである場合は、開始しようとしているアクティビティを再起動したりしません。「設定されていて、起動されているアクティビティが現在のタスクですでに実行されている場合、そのアクティビティの新しいインスタンスを起動する代わりに、その上にある他のすべてのアクティビティが閉じられ、このインテントが(今は上に)新しいインテントとしての古いアクティビティ。」
starkej2 14

2
私はそれが意図されたものではないことに気づきました-しかし、試行錯誤を通じて、これは私のインスタンスの場合に偶然に起こります。これらのフラグを削除すると、問題が修正されます。
Graeme 14

これは、すべての条件ですべてのデバイスに完全な履歴書を作成するわけではありません。
danny117 2014

フラグを削除すると、問題が解決しました。ありがとう
Sealer_05

スプラッシュスクリーン/メインスクリーンのシナリオはありますが、スプラッシュからメインへの移行にフラグを使用していませんが、問題は再現可能です-このソリューションは私には機能しません。
ROR

12

Samsungデバイスでも同じ問題が発生しました。多くを検索した後、これらの答えのどれも私にとってはうまくいきませんでした。AndroidManifest.xmlファイルで、launchModesingleInstanceandroid:launchMode="singleInstance")に設定されていることがわかりました。launchMode属性を削除すると問題が解決しました。


確かに、これは私にとってもトリックでした。私は別のSOの質問からのこの回答が役立つことがわかりました:stackoverflow.com/a/21622266/293280。そして、これはさまざまなタイプのlaunchMode値の書き込みです:inthecheesefactory.com/blog/…–
Joshua Pinter

この修正は私にとってうまくいきました!これをマニフェストではなく、メインアクティビティクラスのアクティビティ属性に追加しました。
Calin Vlasin 2017年

@CalinVlasinは、launchModeの使い方を正確に教えてくれませんか?どこに置いたの?現在私はこのようにしていますが、問題を引き起こしています:<activity android:name = "。UI.landing.MyActivity" android:configChanges = "locale | layoutDirection" android:launchMode = "singleTop" android:windowSoftInputMode = "stateAlwaysHidden | adjustResize ">
j2emanue 2017

これも私の問題でした。これは受け入れられた回答(!isTaskRoot ...
behelit

1

私の猫s60では、開発者オプションで「アクティビティを保持しない」を有効にしていました。これを無効にすると、アプリの状態を失うことなくアプリを切り替えることができました...


方法はわかりませんが、これは私のデバイスでオンでした。
realPro

0

この解決策は私にとってうまくいきました:

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            Intent startMain = new Intent(Intent.ACTION_MAIN);
            startMain.addCategory(Intent.CATEGORY_HOME);
            startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(startMain);
            return false;
        }
        else
            return super.onKeyUp(keyCode, event);
    }

クレジット: 戻るボタンをクリックしたときにAndroidアプリケーションを最小化する必要があります

すべてのデバイスで動作するわけではありませんが、戻るボタンが押されたときにホームボタンの動作を正常に作成し、アクティビティを終了するのではなく停止します。


興味深いトリックですが、述べられているように問題を解決しません。他の問題/質問にも非常に役立ちます。
Graeme

「戻る」ボタンには特定の目的があり、ユーザーは「戻る」ボタンが本来の目的を果たすことを期待しています。なんらかの方法でそれをオーバーライドすることは間違っており、私の意見では、非常に専門的ではありません。
Bugs Happen

-1

私は同じ問題を抱えていました、原因は:

(Kotlinコード、MainActivity)

override fun onBackPressed() {
    finish()
}

したがって、LoginActivityからMainActivityに移動するとき、これを使用します。

    val intent = Intent(this, MainActivity::class.java)
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
    startActivity(intent)

これらのフラグを使用する場合、MainActivityにonBackPressed()含める必要はありません。バッククリックすると、アプリが自然に終了します。そして、ホームボタンを押してアプリに戻ると、再起動しません。


-2

Androidフォンでこの問題をプログラミングしたり体験したりすることを知らない人のためのソリューション。これは主にAndroidバージョンのアップグレードが原因で発生します(私の仮定のみ)。アップグレード後、すべてのアプリが最適化され、電池使用量が少なくなります。ただし、これによりデバイスの速度が低下します。

の解き方

設定>>アプリ>>アプリ設定に移動します(画面上のどこにでも設定記号を探します-デバイスによって異なります)>>バッテリーの最適化(または同様のオプション[ここに画像の説明を入力] [1]オン)>> すべて移動アプリを「最適化されていない」状態にします(手動で1つずつ実行する必要があります。一部の電話では許可/禁止される場合があります)。ランチャーアプリは「最適化されていない」必要があります(私の場合、Zen UIランチャー-これは私が推測する犯人です-時間があれば、別のアプリを最適化/最適化せずに再起動してみてください)。スマートフォンを再起動してください。(データ/セーフモードをリセットする必要はなく、トラブルもありません)

今すぐマルチタスクを試してください。:)ランチャーアイコンを押すと、現在のタスクが再開されます。:)お使いのデバイスは、バッテリーを心配しないでください、とにかくそれは消耗します。


-8

ユーザーにとって貴重です。最近使用したアプリのリストに数週間座った後でも完璧な履歴書。

それはユーザーにとっては履歴書のように見えますが、実際には本格的なスタートです。

背景: タスクを開始していないメインアクティビティ内のアプリが使用するメモリは、簡単に再利用できます。OSは、onCreateに渡された元のバンドルでアプリを再起動するだけです。ただし、元のバンドルにを追加してonSaveInstanceState、OSによってアプリが再起動されたときにインスタンスの状態を復元することができ、アプリが再起動されたか再開されたかに誰も気づきません。古典的な地図プログラムを例にとってみましょう。ユーザーがマップ上の位置に移動してから、ホームキーを押します。2週間後、このマッピングアプリは、facebook、pandora、candy crushとともに最近のアプリのリストに残っています。OSは、最近使用したアプリの名前を保存するだけでなく、アプリの起動に使用した元のバンドルも保存します。ただし、プログラマーはonSaveInstanceState これで、元のバンドルには、アプリを構築するために必要なすべての資料と情報が含まれ、再開されたように見えます。

例: アプリがアンロードされ、数週間後に最近のアプリのリストから再起動する必要がある場合に備えて、現在のカメラ位置をonSaveInstanceStateに保存します。

@Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);
        // save the current camera position;
        if (mMap != null) {
            savedInstanceState.putParcelable(CAMERA_POSITION,
                    mMap.getCameraPosition());
        }
    }



@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // get the exact camera position if the app was unloaded.
        if (savedInstanceState != null) {
            // get the current camera position;
            currentCameraPosition = savedInstanceState
                    .getParcelable(CAMERA_POSITION);
        }

注:このonRestoreInstanceState方法を使用することもできますが、でインスタンスを復元する方が簡単onCreateです。

これは、アプリで何が起こっている可能性が高いです。一部のデバイスでは、アプリはメモリを解放するためにアンロードされます。はい、役立つフラグがいくつかありますが、フラグはアプリのすべてのニュアンスを拾い上げるわけではなく、フラグはあなたのように何週間も生き続けることはありませんonSaveInstanceState。完璧な2週間後の履歴書をコーディングする必要があります。それは複雑なアプリにとって簡単な作業ではありませんが、私たちはあなたの後ろにいて、支援するためにここにいます。

幸運を


これは、一般的なメモリの問題やデフォルトの「一時停止状態」の状態によるものではありません。私は多くのデバイス(大容量メモリと一部低メモリのデバイス)でアプリを試しました。
Graeme 14

これが、永続的なデータをonPauseに保存する理由です私が毎日使用している電話でアプリを2週間も再開するように試み、2週間後にonCreateメソッドが呼び出され、保存したバンドルでosが渡されることをお知らせしますonSaveSessionStateと私は、バンドル内のデータを使用して、アクティビティを残したままの状態で表示します。だから私の回答から3日しか経っていないので、2週間のテストを完了することはできません。概要:アプリはバックグラウンドでいつでもシャットダウンできます。
danny117

@ danny117グレームが経験している問題を正確に理解しているとは思いません
starkej2

グレームの問題を理解しています。一部のデバイスでは、アプリが再開するとonCreateが呼び出されます。画面を回転させるだけでアプリを強制終了するHTC EVO(Gingerbread)とまったく同じように聞こえます。書類を見て、それはアプリがのonCreateに復元できるように述べていdeveloper.android.com/reference/android/app/...
danny117

@ danny117正しいですが、彼が抱えている問題は、アプリが再開されたときに再作成されている単一のアクティビティとは関係ありませんが(予想されます)、間違ったアクティビティが開始されています
starkej2
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.