アクティビティが入ってくる


1. Activity、Window、View の関係

さて、最初はそれらの関係を理解し​​たいと思っていましたが、多くの手が必要になり、それらの呼び出しプロセスを調べ始めました...私は 1 時間で 2 つの減点を受けました。確かに、ソース コードを学習するために下に行く人は皆、まだそのレベルに達していない偉大な達人です。以下は私が調べた情報の概要であり、ソース コードの次の部分を読んだ場合は、間違いを遠慮なく指摘してください。概要図を以下に示します。

1.jpg

プロセス分析: Activity は、startActivity を呼び出した後、最終的に Attach メソッドを呼び出し、次に PolicyManager で Ipolicy インターフェイスを実装し、次に Policy オブジェクトを実装して、makenewwindow を呼び出します。 (Context) メソッド。このメソッドは PhoneWindow オブジェクトと PhoneWindow を返します。 これは Window のサブクラスであり、この PhoneWindow には、すべてのアプリケーション ウィンドウのルート View、つまり View のボスである DecorView の内部クラスがあります。 アクティビティを表示するかどうかを直接制御します (古いドライバーの元の言葉を引用します...)。内部には LinearLayout があり、内部には 2 つの FrameLayout があり、それぞれ ActionBar と CustomView をインストールするために使用され、レイアウトは によってロードされます。 setContentView() はこの CustomView に配置されます。

これら 3 つの関係を要約してみましょう: 突飛な比喩を使ってみましょう: これら 3 つのカテゴリをそれぞれ、画家、キャンバス、ブラシで描いたものと呼ぶことができます。 ペインターはブラシ (LayoutInflater.infalte) でパターンを描画し、それをキャンバス (addView) 上に描画します。 最後に表示されます(setContentView)


2. アクティビティ、タスク、バックスタックの概念

次に、タスクとバックスタックという2つの用語が含まれるAndroidのアクティビティの管理メカニズムを理解しましょう!

概念分析:

私たちのアプリは通常複数のアクティビティで構成されており、Android はタスクの概念を提供します。 それは、関連する複数のアクティビティを収集し、そのアクティビティをジャンプして返すことです。もちろん、このタスクは単なる フレームワーク層の概念、AndroidでTaskを実装するデータ構造がBack Stackです! Stack のデータ構造は皆さんご存知かと思いますが、Java にも Stack のコレクション クラスがあります。スタックには次の特徴があります:

先入れ先出し (LIFO)、一般的に使用される操作はプッシュとポップです。最上位はスタックの最上位と呼ばれ、最下位はスタックの最下位と呼ばれます

Android スタックでは、スタックにも上記の特性があります。これがアクティビティの管理方法です。

新しいアクティビティに切り替えると、アクティビティがスタックにプッシュされ、スタックの最上位になります。 ユーザーが「戻る」ボタンをクリックすると、スタックの一番上のアクティビティが飛び出し、その直後のアクティビティがスタックの一番上に来ます。

公式ドキュメントに記載されているフローチャートを見てみましょう:

2.png

プロセス分析:

アプリケーションには 3 つのアクティビティ A1、A2、および A3 があります。ユーザーがランチャーまたはホーム画面でアプリケーション アイコンをクリックすると、 メインの A1 を開始し、次に A1 が A2 を開始し、A2 が A3 を開始します。この時点でスタックには 3 つのアクティビティがあり、これら 3 つのアクティビティは 同じタスク (Task) で、ユーザーがリターン キーを押すと、A3 がポップアップし、ユーザーがもう一度リターン キーを押すと、スタックには A1 と A2 だけが残ります。 A2 をポップアップすると、スタックには A1 だけが残ります。リターン キーを押し続けると、A1 がポップアップします。タスクは削除されます。つまり、プログラムが終了します。

その後、公式文書にある他の 2 つの写真を見て、好奇心からその説明をもう一度読み、グループの人々と話し合いました。

3.png

そして、次のような説明がありました。彼は次のように結論付けました:

4.png

タスクはアクティビティのコレクションであり、実際にはバックスタックはアクティビティを保存するために使用されます。 同時に 1 つのスタックだけが前面にあり、他のスタックは背景にあります。スタックはどのようにして生まれたのでしょうか?

答え: アイコンをクリックしてホーム画面から新しいアプリを開くと、新しいタスクが作成されます。例: アドレス帳アプリのアイコンをクリックしてアプリを開きます。このとき、新しいスタック 1 が作成され、新しく生成されたアクティビティが追加されます。 Address Book APP ですが、この時点では新しいスタックは作成されませんが、引き続きスタック 1 に追加されます。これは Android は、ユーザー エクスペリエンス アプローチを推進しています。つまり、異なるアプリケーションを切り替えると、ユーザーは同じアプリケーションであるかのように感じることができます。 非常に一貫したユーザー エクスペリエンスであり、正式にはシームレスと呼ばれています。 ——————このとき、ホームボタンをクリックしてホーム画面に戻り、スタック 1 がバックグラウンドに入ると、次の 2 つの操作が行われる可能性があります:

1) メニューボタン (四角ボタン) をクリックします。クリックしてプログラムを開くと、スタック 1 が最前面に戻ります。 または、ホーム画面のアドレス帳アイコンをクリックしてアプリを開きます。この時点では、新しいスタックは作成されず、スタック 1 が前面に戻ります。
2) この時点で別のアイコンをクリックして新しいアプリを開くと、この時点で新しいスタック 2 が作成され、スタック 2 が前面に表示されます。 そして、スタック 1 はバックグラウンドに留まり続けます

3) 以降も同じことが当てはまります。



3.タスク管理

1) ドキュメントの翻訳:

それでは、ドキュメントの ManagingTasks から始めてドキュメントを続けてみましょう。おおよその翻訳は次のとおりです:

1) ドキュメントの翻訳

ドキュメントの ManagingTasks から始まる翻訳は次のとおりです:

上記のように、Android は新しく正常に起動されたアクティビティを同じタスクに追加し、複数のタスクを「先入れ先出し」方式で管理します。 Back Stack を使用すると、ユーザーはアクティビティがタスクとどのように対話するか、アクティビティがバック スタックにどのように存在するかを心配する必要がなくなります。 もしかしたら、この通常の管理スタイルを変えたいと考えているかもしれません。たとえば、アクティビティの 1 つを新しいタスクで管理したいとします。 または、特定のアクティビティのみをインスタンス化したい場合、またはユーザーがタスクを離れるときにルート アクティビティを除くタスク内のすべてのアクティビティをクリーンアップしたい場合があります。 AndroidManifest.xml を変更するだけで、これらのことやその他のことを行うことができます。 < activity > は、特別に識別された Intent をコード内で startActivity() に渡すことで簡単に実装できます。 アクティビティの管理。

< activity > で使用できる属性は次のとおりです。 clearTaskOnLaunch

    常にTaskStateを保持
  • finishOnTaskLaunch
  • 使用できる主なインテント フラグは次のとおりです: AG_ACTIVITY_SINGLE_ TOP
  • それでは、それぞれの使い方をご紹介していきましょう:
  • 2) taskAffinity とallowTaskReparenting
  • デフォルトでは、
  • アプリケーション内のすべてのアクティビティには Affinity があり、それらは同じタスクに属します。 同じタスク内にあるかどうかの印として理解できますが、各アクティビティは通過できます。 < activity> の taskAffinity プロパティは別のアフィニティを設定します。 異なるアプリケーションのアクティビティは同じアフィニティを共有でき、同じアプリケーションの異なるアクティビティも共有できます。 別のアフィニティに設定することもできます。 Affinity 属性は 2 つの状況で機能します:
1) アクティビティを開始する Intent オブジェクトに
FLAG_ACTIVITY_NEW_TASK

タグが含まれている場合: startActivity() に渡される Intent オブジェクトに FLAG_ACTIVITY_NEW_TASK タグが含まれている場合、システムは開始する必要があるアクティビティに対して、現在のアクティビティとは異なるタスクを探します。開始されるアクティビティのアフィニティ属性が現在のすべてのタスクのアフィニティ属性と異なる場合、システムはそのアフィニティ属性を持つ新しいタスクを作成し、開始されるアクティビティを新しく作成されたタスク スタックにプッシュします。同じスタック内の Affinity 属性にプッシュされます。 2)

allowTaskReparenting
プロパティがtrueに設定されている アクティビティのallowTaskReparentingプロパティがtrueの場合、同じアフィニティを持つあるタスク(Task1)から別のタスク(Task2)に移動できます(Task2がフォアグラウンドになった場合)。 ユーザーの観点から見て、.apk ファイルに複数の「アプリケーション」が含まれている場合、それらのアクティビティに異なるアフィニティ値を割り当てる必要がある場合があります。

    3) launchMode:

    4 つのオプションの値。これは、起動モードに関する研究の中核であり、以下で詳しく説明します。 それらは次のとおりです: standard (デフォルト)、singleTopsingleTasksingleInstance


    4) スタックをクリアします

    ユーザーがタスクから長時間離れたとき (現在のタスクはタスクに転送されます)バックグラウンド)、システムはタスクのスタックの一番下にあるアクティビティを除くすべてのアクティビティをクリアします。 。このようにして、ユーザーがタスクに戻ると、そのタスクの元のアクティビティのみが残ります。次のプロパティを次のように変更できます。 この行動を変えてください!

    常にTaskStateを保持します: スタックの一番下にあるアクティビティのこのプロパティが true に設定されている場合、上記の状況は発生しません。タスク内のすべてのアクティビティは長期間保存されます。

    clearTaskOnLaunchスタックの一番下にあるアクティビティのこの属性が true に設定されている場合、ユーザーがタスクを離れると、 その後、タスク スタック内のアクティビティは、スタックの一番下のアクティビティだけが残るまでクリアされます。この状況と一致するのは、 alwaysRetainTaskState の逆。ユーザーがほんの少し離れただけでも、タスクは初期状態に戻ります (スタックの一番下のアクティビティのみが残ります)。

    finishOnTaskLaunchはclearTaskOnLaunchに似ていますが、単一のアクティビティに対してのみ動作します。 タスク全体ではなく、操作です。スタックの一番下にあるアクティビティを含む、任意のアクティビティを終了できます。 true に設定すると、現在のアクティビティは現在のセッション中にタスクの一部としてのみ存在します。 ユーザーがアクティビティを終了して戻ってくると、アクティビティは存在しません。


    4. アクティビティの 4 つの読み込みモードの詳細な説明:

    次に、4 つの読み込みモードについて詳しく説明します。 standard (デフォルト)、singleTopsingleTasksingleInstance インターネットを見ていたら、起動モードについて写真とテキストで説明されている記事を見たので、それはとても簡単かもしれません。ここから学びましょう: 次へ:

    元のリンク: アクティビティの起動モードの詳細なグラフィックとテキストの説明: standard、singleTop、singleTask、singleInstance

    英語の原文: Android アクティビティの launchMode: standard、singleTop、 singleTask と singleInstance 読み込みモードの詳細な説明もあります: Android の Activity の 4 つの起動モードと taskAffinity 属性の詳細な説明

    まず概要図を見てみましょう:

    5.png

    モードの詳細な説明:


    標準モード:

    標準起動モード。これは、アクティビティのデフォルトの起動モードでもあります。このモードで開始されたアクティビティは複数回インスタンス化できます。つまり、アクティビティの複数のインスタンスが同じタスク内に存在でき、各インスタンスが Intent オブジェクトを処理します。アクティビティ A の起動モードが標準で、A がすでに起動している場合、A でアクティビティ A を再度起動すると、つまり startActivity(new Intent(this, A.class)) を呼び出すと、A のインスタンスが再び先頭から起動されます。つまり、スタックの現在のステータスは A->A です。

    6.jpg

    7.jpg


    singleTop モード:

    singleTop モードで開始されたアクティビティのインスタンスがタスク スタックの最上位に既に存在する場合、 その後、このアクティビティが再度開始されると、新しいインスタンスは作成されませんが、スタックの最上位にあるインスタンスが再利用されます。 そして、インスタンスの onNewIntent() メソッドが呼び出され、Intent オブジェクトがこのインスタンスに渡されます。 たとえば、A の起動モードが singleTop で、A のインスタンスがスタックの最上位にすでに存在する場合、 次に、startActivity(new Intent(this, A.class)) を呼び出して A を開始するときに、 A のインスタンスは再度作成されませんが、元のインスタンスが再利用され、元のインスタンスの onNewIntent() メソッドが呼び出されます。 この時点では、タスク スタックには A のインスタンスがまだ存在します。アクティビティのインスタンスが singleTop モードで開始された場合 タスク スタックに既に存在するがスタックの最上位にない場合、その動作は標準モードと同じであり、複数のインスタンスが作成されます。

    8.jpg


    シングルタスクモード:

    システム内で許可されるアクティビティインスタンスは 1 つだけです。システムにすでにインスタンスがある場合は、 このインスタンスを保持するタスクは先頭に移動され、インテントは onNewIntent() 経由で送信されます。 そうでない場合は、新しいアクティビティが作成され、適切なタスクに配置されます

    9.jpg

    公式ドキュメントで言及されている問題:

    システムは新しいタスクを作成し、このアクティビティを新しいタスクのルートとしてインスタンス化します これには、taskAffinity を使用した後に終了を設定する必要があります:

    10.jpg

    11.jpg



    シングルインスタンス モード

    では、システムがどのタスクからアクティビティを開始しても、アクティビティ インスタンスが 1 つだけ作成され、新しいタスク スタックの先頭に追加されます。 つまり、このインスタンスによって開始された他のアクティビティは、別のタスクで自動的に実行されます。 アクティビティのインスタンスが再度開始されると、既存のタスクとインスタンスが再利用されます。このインスタンスは呼び出されます onNewIntent() メソッドは、Intent インスタンスをインスタンスに渡します。シングルタスクと同様に、 このようなアクティビティ インスタンスはシステム内に同時に 1 つだけ存在します。

    12.jpg


    5. アクティビティの補足

    アクティビティについてまだ言及されていないことがいくつかあるかもしれないので、ここで場所を確保し、見逃したものはここで埋め合わせます。 まず第一に、これは、オープンソース中国のアクティビティ管理クラスを投稿するというグループ友人の Zhuhai Kun の提案です。これは、誰でも直接使用できます。 プロジェクト中〜

    1)开源中国客户端Activity管理类:

    package net.oschina.app;

    import java.util.Stack;

    import android.app.Activity;
    import android.app.ActivityManager;
    import android .content.Context;


    public class AppManager {

    private static Stack<Activity> activityStack;
    private static AppManager instance;

    private AppManager(){}
    /**
    * 単一インスタンス
    */
    public static AppManager getAppManager(){
    if(instance==null){
    instance=new AppManager();
    }
    return instance;
    }
    /**
    * アクティビティをスタックに追加します
    */
    public void addActivity(Activity activity){
    if(activityStack==null){
    activityStack=new Stack<Activity>();
    }
    activityStack .add(activity);
    }
    /**
    * 現在のアクティビティ (スタックに最後にプッシュされたアクティビティ) を取得します
    */
    public Activity currentActivity(){
    Activity activity=activityStack.lastElement();
    return activity;
    }
    /**
    * 現在のアクティビティ (スタックにプッシュされた最後のアクティビティ) を終了します
    */
    public void finishActivity(){
    アクティビティ activity=activityStack.lastElement();
    finishActivity(アクティビティ);
    }
    /**
    * 指定されたアクティビティを終了します
    */
    public void finishActivity(アクティビティ アクティビティ){
    if(アクティビティ!=null) {
    activityStack.remove(activity);
    activity.finish();
    activity=null;
    }
    }
    /**
    * 指定したクラス名でアクティビティを終了します
    */
    public void finishActivity(Class<?> cls){
    for (アクティビティアクティビティ: activityStack) {
    if(activity.getClass().equals(cls) ){
    finishActivity(activity);
    }
    }
    }
    /**
    * すべてのアクティビティを終了します
    */
    public void finishAllActivity(){
    for (int i = 0, size = activityStack.size(); 私は< サイズ; i++){
    if (null != activityStack.get(i)){
    activityStack.get(i).finish();
    }
    }
    activityStack.clear();
    }

    *アプリケーションを終了します
    * /
    public void AppExit(Context context) {
    try {
    finishAllActivity();
    ActivityManager activityMgr= (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    activityMgr.restartPackage(context.getPackageName());
    System.exit(0);
    } catch (Exception e) { }
    }
    }

    このセクションの概要:

    さて、このセクションはこれで終わりです、少し辛くて理解しにくいですが、とりあえずタスクの全体的なスケジュールをまとめてみましょう。 関連操作:

    • ホームボタンを押して、前のタスクをバックグラウンドに切り替えます
    • ホームボタンを長押しすると、最近実行したタスクのリストが表示されます
    • ランチャーまたはホームスクリーンのアプリアイコンをクリックして、新しいタスクを作成するか、既存のタスクをフォアグラウンドにスケジュールします
    • シングルタスク モードでアクティビティを開始すると、適切なタスクが既に存在するかどうかをシステムが検索し、存在する場合は、タスクがフォアグラウンドにスケジュールされます。タスク。このタスクで開始されるアクティビティのインスタンスがすでに存在する場合は、このインスタンスより上のすべてのアクティビティをクリアし、このインスタンスをユーザーに表示します。この既存のタスク内に開始されるアクティビティのインスタンスがない場合、インスタンスはこのタスクの先頭で開始されます。このタスクが存在しない場合は、新しいタスクが開始され、このシングルタスク モードのアクティビティのインスタンスがこの新しいタスクで開始されます。
    • singleInstance のアクティビティを開始するとき、システム内にこのアクティビティのインスタンスが既に存在するかどうかが検索され、存在する場合は、このインスタンスが配置されているタスクがフォアグラウンドにスケジュールされ、このアクティビティのインスタンスが実行されます。再利用(タスク内にこのアクティビティのみが存在します)。存在しない場合は、新しいタスクが開始され、このシングルインスタンス モードのアクティビティのインスタンスがこの新しいタスクで開始されます。

    このセクションはこれで終わりです。タスクとアクティビティの読み込みモードについては、まだ非常に複雑です。この記事を書くための手順を掲載します。 いくつかの参考資料を自分でチェックしてみてください~


    参考資料: