「コードの最初の行」 第 2 章: アクティビティの探索 アクティビティ

まずはアクティビティの基本的な使い方

簡単に理解すると、アクティビティとは表示されるページであり、通常はページごとに 1 つのアクティビティです。

1. プロジェクトを手動で作成する

新しいプロジェクトを作成し、「NoActivity の追加」を選択します。この時点で生成されたプロジェクトの場合、java の下のパッケージにはアクティビティはありません。したがって、新しいアクティビティを作成する必要があります。
com.example.activitytest package-New-Activity-Empty Activity を右クリックすると、アクティビティを作成するためのダイアログ ボックスが表示されます。アクティビティに FirstActivity という名前を付け、[レイアウト ファイルの生成] と [ランチャー アクティビティ] の 2 つのオプションはチェックしません。
「レイアウト ファイルの生成」にチェックを入れると、FirstActivity に対応するレイアウト ファイルが自動的に作成されます。LauncherActivity にチェックを入れると、FirstActivity が現在のプロジェクトのメイン アクティビティとして自動的に設定されます。初めてアクティビティを手動で作成するため、これらは自動的に生成されます一時的なものです。すべてをチェックしないでください。以下で 1 つずつ手動で完了します。
ここに画像の説明を挿入

public class FirstActivity extends AppCompatActivity {
    
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
    }
}

プロジェクト内のアクティビティはすべて、アクティビティの onCreate() メソッドをオーバーライドする必要があり、新しく作成されたアクティビティがデフォルトで書き込まれています。

2. レイアウトを作成してロードする

前にも述べたように、Android プログラムの設計ではロジックとビューの分離に注意を払っています。各アクティビティがレイアウトに対応することが最善です。レイアウトはインターフェイスのコンテンツを表示するために使用されるため、手動でレイアウト ファイルを作成します今。
app/src/main/resディレクトリ-新規ディレクトリを右クリックすると、新規ディレクトリ作成画面が表示されるので、ここでまずlayoutという名前のディレクトリを作成します。次に、レイアウト ディレクトリを右クリックし、[レイアウト リソース ファイル] をクリックすると、新しいレイアウト リソース ファイルを作成するウィンドウが表示されます。このレイアウト ファイルに名前を first laout とし、ルート要素をデフォルトとします。
次に、ボタンのコードを記述します。

<Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="测试按钮"/>
android:id 是给当前的元素定义一个唯一标识符,之后可以在代码中对这个元素进行操作。你可能会对@+id/button 1这种语法感到陌生,但如果把加号去掉,变成@id/button 1,这样你就会觉得有些熟悉了吧,这不就是在 XML中引用资源的语法吗?只不过是把 string 替换成了id。是的,如果你需要在XML中引用一个id,就使用@id/id name 这种语法,而如果你需要在XML中定义一个id,则要使用@+id/id name 这种语法。

随后android:layout width 指定了当前元素的宽度,这里使用match parent 表示让当前元素和父元素一样宽。android:layout height 指定了当前元素的高度,这里使用 wrap content 表示当前元素的高度只要能刚好包含里面的内容就行。android:text 指定了元素中显示的文字内容

このようにして、レイアウト ファイルが作成され、その後、レイアウトをアクティビティにロードする必要があります

protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
+        setContentView(R.layout.first_layout);
}

次に、このアクティビティを AndroidManifest ファイルに登録します。

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyApplicationTest">
        <activity
            android:name=".FirstActivity"
            android:exported="true" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

アクティビティが登録されていることがわかります。ただし、intent-filter タグ内の 2 行のコードが欠落しています。前に述べたように、これらの 2 行のコードは、FirstActivity がこのプロジェクトのメイン アクティビティであることを示しています。携帯電話でアプリケーション アイコンをクリックすると、このアクティビティが最初に起動されます。
このように書いた後、プロジェクトを実行すると効果が確認できます。
ここに画像の説明を挿入
つまり、プロセスは次のようになります。

1,创建新的活动
2,创建新的layout布局
3,在活动中引入创建的layout
4,在manifext文件中注册活动。

3. アクティビティでトーストを使用する

上にボタンが書かれているので、この時点でボタンを取得してイベントをバインドすることができます。

setContentView(R.layout.first_layout);
Button button1=(Button) findViewById(R.id.button);
button1.setOnClickListener(new View.OnClickListener() {
    
    
    @Override
    public void onClick(View view) {
    
    
        Toast.makeText(FirstActivity.this, "测试toast", Toast.LENGTH_SHORT).show();
    }
});

ここで findViewById が返すのはビュー オブジェクトであり、これがボタン オブジェクトに変換され、setOnClickListener メソッドを呼び出してボタンのリスナーを登録していることがわかります。ボタンがクリックされると、リスナーの onClick メソッドが実行されます。
ここで、onClick メソッドの内容をカスタマイズする必要があります。
Toast の使い方は非常に簡単で、静的メソッド makeText() で Toat オブジェクトを作成し、show() を呼び出して Toast を表示します。ここで、makeText() メソッドは 3 つのパラメータを渡す必要があることに注意してください。

第一个参数是 Context,也就是 Toast要求的上下文,由于活动本身就是一个 Context 对象,因此这里直接传人 FirstActivity.this 即可。
第二个参数是 Toast 显示的文本内容。
第三个参数是 Toast显示的时长,有两个内置常量可以选择 Toast.LENGTH SHORT和 Tast.LENGTH LONG

4. アクティビティ内のメニューを使用する

まず、res ディレクトリの下にメニュー フォルダを作成し、res ディレクトリ-新規-ディレクトリをクリックし、フォルダ名メニューを入力して、OK をクリックします。次に、このフォルダーの下に main という名前の新しいメニュー ファイルを作成し、メニュー フォルダー-New-Menu リソース ファイルを右クリックして、次のコードを追加します。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/add_item"
        android:title="Add" />
    <item
        android:id="@+id/remove_item"
        android:title="Remove" />
</menu>

つまり、res にはすべてのリソース ファイルがあり、ここにメニューのレイアウト内容が記述されており、それを表示するには対応するアクティビティにマウントする必要があります。その後、FirstActivity に戻って onCreateOptionsMenu() メソッドを書き換えます。書き換え方法は Ctrl+O ショートカット (Mac の場合は Control + O) を使用します。

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    
    
        getMenuInflater().inflate(R.menu.main,menu);
        return true;
    }

getMenuInflater() メソッドを通じて MenuInflater オブジェクトを取得し、その inflate() メソッドを呼び出して現在のアクティビティのメニューを作成できます。

inflate()方法接收两个参数,第一个参数用于指定我们通过哪一个资源文件来创建菜单,这里当然传入 r.menu.main。第二个参数用于指定我们的菜单项将添加到哪一个Menu对象当中,这里直接使用onCreateOptionsMenu()方法中传人的 menu参数然后给这个方法返回 true,表示允许创建的菜单显示出来,如果返回了 false,创建的菜单将无法显示。

もちろん、単にメニューを表示するだけでは不十分で、ただ見るためだけにメニューを定義するのではなく、本当に使えるメニューにすることが重要なので、メニュー応答イベントを再度定義する必要があります。FirstActivity の on0optionsItemSelected() メソッドを書き換えます。

@Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
    
    
        switch (item.getItemId()){
    
    
            case R.id.add_item:
                Toast.makeText(this, "增加按钮被点击", Toast.LENGTH_SHORT).show();
                break;
            case R.id.remove_item:
                Toast.makeText(this, "移除按钮被点击", Toast.LENGTH_SHORT).show();
                break;
            default:
        }
        return true;
    }

on0optionsItemSelected() メソッドで、 item.getItemId() を呼び出してクリックしたメニュー項目を特定し、独自のロジック処理を各メニュー項目に追加します。上で述べたように、android:id="@+id/add_item" は add_item に ID を追加するため、ここで R.id.add_item はその ID を取得できます。それでメニューが作成されます。

5. アクティビティを破棄する

インターフェイス上で、戻るキーを押すと現在のアクティビティを破棄できます。ただし、コードで実装する場合は、Activity クラスが提供するfinish() メソッドを使用でき、アクティビティ内でこのメソッドを呼び出すことで、現在のアクティビティを破棄できます。

button1.setOnClickListener(new View.OnClickListener() {
    
    
      @Override
      public void onClick(View view) {
    
    
          finish();
      }
  });

このようにして、ボタンをクリックすると現在のアクティビティが破棄されます。

2. インテントを使用してアクティビティ間を往復する

上記ではアクティビティが作成されましたが、プロジェクトにアクティビティが 1 つだけ存在することは不可能です。複数のアクティビティ間を移動するにはどうすればよいでしょうか? これを完了するにはインテントを使用する必要があります。

1. 2 番目のアクティビティを構築する

アクティビティを右クリックし、新しい空のアクティビティを作成し、[レイアウト ファイルの生成] をオンにして、レイアウト ファイルに Second_layout という名前を付けます。ただし、[ランチャー アクティビティ] オプションはオンにしないでください。
[完了] をクリックして Android Studio の作成を完了します。これにより、SecondActivity、java、および 2 番目のlayoutxml ファイルが自動的に生成されます。ただし、自動生成されたレイアウト コードは現時点では少し複雑かもしれません。ここでは引き続き最も使い慣れた LinearLayout を使用し、2 番目のlayout.xml を編集します。

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".SecondActivity">

    <Button
        android:id="@+id/button2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="第二个按钮" />
</androidx.constraintlayout.widget.ConstraintLayout>

次に、 SecondActivity を見てください。エディターがこのレイアウトへの参照を作成しました。

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

次に、このアクティビティをマニフェスト ファイルに登録すると、自動的に登録されたことがわかりますが、メインのアクティビティではないため、intent-filter タグは必要ありません。

<activity
    android:name=".FirstActivity"
    android:exported="true" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<activity
    android:name=".SecondActivity"
    android:exported="true" />

ここで 2 番目のアクティビティが作成されました。次の問題は、このアクティビティをどのように開始するかです。インテントを使用する必要があります。

2. 明示的なインテントを使用してアクティビティの切り替えを完了する

インテントは、Android プログラムのコンポーネント間で通信するための重要な方法であり、現在のコンポーネントが実行したいアクションを示すだけでなく、異なるコンポーネント間でデータを転送することもできます。インテントは通常、アクティビティの開始サービスの開始ブロードキャストの送信などのシナリオで使用できます。ここでは立ち上げ活動についてのみ説明します。
インテントには大きく分けて「明示的インテント」と「暗黙的インテント」の2種類がありますが、まずは明示的インテントの使い方について見ていきましょう。

Intent有多个构造函数的重载,其中一个是Intent(Context packageContext,Class<?>cls)。这个构造函数接收两个参数。
第一个参数 Context 要求提供一个启动活动的上下文。
第二个参数 class 则是指定想要启动的目标活动,通过这个构造函数就可以构建出 Intent 的“意图”。
 Activity类中提供了一个startActivity()方法,这个方法是专门用于启动活动的,它接收一个 Intent 参数,这里我们将构建好的 Intent 传入startActivity()方法就可以启动目标活动了。

具体的なコードは次のとおりです。

 Button button1=(Button) findViewById(R.id.button);
        button1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent=new Intent(FirstActivity.this,SecondActivity.class);
                //这里这两个参数,指定从当前活动跳转目标活动。
                startActivity(intent);
            }
        });

このようにボタンをクリックすると、2ページ目に遷移することができます。最初のページのアクティビティが破棄されていないことに注意してください。新しいアクティビティが古いアクティビティにオーバーレイされていることがわかります。2ページ目の現在のアクティビティを破棄するので、最初のアクティビティに進みます。

3. 暗黙的なインテントを使用する

明示的なインテントと比較すると、暗黙的なインテントはより暗黙的であり、どのアクティビティを開始するかを明確に示すのではなく、アクションやカテゴリなどの一連のより抽象的な情報を指定し、システムに渡されます。意図を分析し、開始する適切なアクティビティを見つけるのに協力してください。
タグの下の <intent-filter の内容を構成することで、現在のアクティビティが応答できるアクションとカテゴリを指定し、AndroidManifest.xml を開いて次のコードを追加できます。

 <activity
            android:name=".SecondActivity"
            android:exported="true" >
            <intent-filter>
                <action android:name="com.example.myapplicationtest.ACTION_START" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

ラベルでは、現在のアクティビティが com.example.activitytest.ACTIONSTART アクションに応答できることを示し、ラベルには追加情報が含まれています。これは、現在のアクティビティが応答できるインテントに含まれる可能性のあるカテゴリをより正確に示します。に。と のコンテンツがインテントで指定されたアクションとカテゴリに同時に一致する場合にのみ、このアクティビティはインテントに応答できます。
FirstActivity のボタンのクリック イベントを変更します。コードは次のとおりです。

        button1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent=new Intent("com.example.myapplicationtest.ACTION_START");
                startActivity(intent);
            }
        });

Intent の別のコンストラクターを使用してアクション文字列を直接渡し、com.example.activitytest.ACTION START アクションに応答できるアクティビティを開始したいことを示していることがわかります。応答するには同じ時刻に一致する必要があると言われませんでしたか? 指定されたカテゴリがある場所が表示されないのはなぜですか? これは、android.intent、category.DEFAULT がデフォルトのカテゴリであり、これが呼び出されるからです。 startActivity() メソッドが呼び出されたとき、このカテゴリがインテントに自動的に追加されます。その後、対応するアクティビティを見つけて開始できます。
各インテントに指定できるアクションは 1 つだけですが、複数のカテゴリを指定できます。現時点では、インテントにはデフォルト カテゴリが 1 つしかないため、別のカテゴリを追加しましょう。
FirstActivity のボタンのクリック イベントを変更します。コードは次のとおりです。

        button1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent=new Intent("com.example.myapplicationtest.ACTION_START");
                intent.addCategory("com.example.myapplicationtest.MY_CATEGORY");
                startActivity(intent);
            }
        });

ここに追加した後、ボタンをクリックしても対応するカテゴリが見つからないため、対応するアクティビティに応答させるには、menifext にカテゴリ宣言を追加する必要があります。

            <intent-filter>
                <action android:name="com.example.myapplicationtest.ACTION_START" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="com.example.myapplicationtest.MY_CATEGORY"/>
            </intent-filter>

4. 暗黙的インテントを使用して他のプログラムのアクティビティを開始する

Implicit Intentを利用すると、自分のプログラム内でアクティビティを開始できるだけでなく、他のプログラムのアクティビティも開始できるため、複数のAndroidアプリ間で機能を共有することが可能になります。たとえば、アプリケーションで Web ページを表示する必要がある場合、ブラウザを自分で実装する必要はありません (実際には不可能ですが、システム ブラウザを呼び出してこの Web ページを開くだけで十分です。)
FirstActivity コードのクリック イベントのボタン:

        button1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent=new Intent(Intent.ACTION_VIEW);
                intent.setData(Uri.parse("http://www.baidu.com"));
                startActivity(intent);
            }
        });

次に、menifest でこのコード行を変更し、無視を追加します (変更しない場合、エラーが発生します)。

            <intent-filter  tools:ignore = "AppLinkUrlError">
                <action  android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="http"/>
            </intent-filter>

このようにして、ボタンをクリックするとポップアップ ウィンドウが表示され、アクティビティ 3 を開くか、デフォルトのブラウザを開くか、アクティビティを選択できます。
これは、ボタン イベントが複数のアクティビティに一致するためです。したがって、ユーザーが選択できるポップアップ ウィンドウが必要になります。
達成される効果:
ここに画像の説明を挿入
次に、システムの電話帳を開くことを見てみましょう。

  button1.setOnClickListener(new View.OnClickListener() {
    
    
      @Override
      public void onClick(View view) {
    
    
          Intent intent=new Intent(Intent.ACTION_DIAL);
          intent.setData(Uri.parse("100861"));
          startActivity(intent);
      }
  });

5. データを次のアクティビティに渡す

フロントエンドの言葉で言えば、ジャンプをルーティングするときにパラメータを渡す方法です。

传递参数:intent.putExtra("extra_data",data);
接收参数: 	Intentintent=getIntent();
			String data=intent.getStringExtra("extra_data");
 			Log.d("EecondActivity",data);

最初のアクティビティでデータを渡します。

        button1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                String data="这是要传递的数据";
                Intent intent=new Intent(FirstActivity.this,SecondActivity.class);
                intent.putExtra("extra_data",data);
                startActivity(intent);
            }
        });

2 番目のアクティビティでパラメータを受け取ります。

 Intentintent=getIntent();
 String data=intent.getStringExtra("extra_data");
 Log.d("EecondActivity",data);

6. データを前のアクティビティに戻す

現在のアクティビティを破棄するのが戻るキーであれ、コードfinish()であれ、アクティビティが破棄されるときに前のアクティビティにデータを渡すことができます。これには、アクティビティで startActivityForResult() メソッドを使用する必要があります。このメソッドは、アクティビティの開始にも使用されますが、このメソッドは、アクティビティが破棄されたときに前のアクティビティに結果を返すことを想定しています。

startActivityForResult()方法接收两个参数,
第一个参数还是 Intent,
第二个参数是请求码,用于在之后的回调中判断数据的来源。

最初のアクティビティのクリック イベントに次のように記述します。

       button1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                String data="这是要传递的数据";
                Intent intent=new Intent(FirstActivity.this,SecondActivity.class);
                startActivityForResult(intent,1);//请求码传入唯一值用来明确是它启动的活动即可,这里用1
            }
        });

次に、2 番目のアクティビティでボタンのクリック イベントを登録し、データを返すロジックをクリック イベントに追加します。

 public void onClick(View view) {
    
    
    Intent intent=getIntent();
    intent.putExtra("data_return","返回给上一个活动的信息");
    setResult(RESULT_OK,intent);//这个方法专门用于向上一个活动返回数据
    //第一个参数:用于返回处理结果,RESULT_OK是内置常量-1
    //第二个参数:带有参数的Intent
    finish();
}

startActivityForResult() メソッドを使用して SecondActivity を開始するため、SecondActivity が破棄された後に前のアクティビティの onActivityResult() メソッドが呼び戻されるため、以下に示すように、返されたデータを取得するには FirstActivity でこのメソッドを書き直す必要があります。

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    
    
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode){
    
    
            //。由于在一个活动中有可能调用startActivityForResult()方法去启动很多不同的活动
            // 每一个活动返回的数据都会回调到onActivityResult()这个方法中,
            // 因此我们首先要做的就是通过检查 requestCode 的值来判断数据来源。
            // 确定数据是从SecondActivity返回的之后,我们再通过 resultCode 的值来判断处理结果是否成功。
            case 1:
                if(resultCode==RESULT_OK){
    
    
                    String returnedData=data.getStringExtra("data_return");
                    Log.d("FirstActivity",returnedData);
                }
                break;
            default:
        }
    }

この後、startActivityForResult を使用してアクティビティ 1 のアクティビティ 2 を開くため、アクティビティ 2 に入り、ボタンをクリックしてアクティビティを破棄します。アクティビティ 1 の onActivityResult メソッドで監視でき、内部コードを実行して、どのアクティビティが返されたかを特定できます。 requestCode に従ってトリガーし、対応するコードを実行します。
しかし、Back が 2 番目のアクティビティを破棄した場合、明らかにコールバックは実行されません。では、どうすれば解決できるでしょうか?
これは、2 番目のアクティビティで onBackPressed() メソッドをオーバーライドすることで解決できます。

    @Override
    public void onBackPressed() {
    
    
        Intent intent=getIntent();
        intent.putExtra("data_return","返回给上一个活动的信息");
        setResult(RESULT_OK,intent);//这个方法专门用于向上一个活动返回数据
        //第一个参数:用于返回处理结果,RESULT_OK是内置常量-1
        //第二个参数:带有参数的Intent
        finish();
    }

3、アクティビティのライフサイクル

1. リターンスタックの概念

ここに画像の説明を挿入
つまり、各アクティビティはスタック内のレイヤーであり、ps のレイヤー概念と同様に、ユーザーは上から下に見ていきます。

2. アクティブ状態

各アクティビティのライフサイクルには 4 つの状態があります。
動作状況:

就是处在栈顶的活动

一時停止状態

不处于栈顶,但是用户仍然可见的活动(顶层活动不覆盖全页,就会让底下的人活动可见了)

停止状態

当一个活动不处于顶层,并且不可见的时候。这时候系统仍然保留相应的状态和成员变量,但可能被回收。

破壊された状態

当活动从栈中移除的时候就变成了销毁状态。

3. アクティビティのライフサイクル

onCreate()。它会在活动第一次被创建的时候调用。你应该在这个方法中完成活动的初始化操作,比如说加载布局、绑定事件等。【完整】
口 onstart()。这个方法在活动由不可见变为可见的时候调用。【可见】
口 onResume()。这个方法在活动准备好和用户进行交互的时候调用。此时的活动一定位于返回栈的栈顶,并且处于运行状态。【前台】
口 onPause()。这个方法在系统准备去启动或者恢复另一个活动的时候调用。我们通常会在这个方法中将一些消耗 CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶活动的使用。【前台】
口onstop()。这个方法在活动完全不可见的时候调用。它和 onPause()方法的主要区别在于,如果启动的新活动是一个对话框式的活动,那么 onPause()方法会得到执行,而onstop()方法并不会执行。【可见】
口 onDestroy()。这个方法在活动被销毁之前调用,之后活动的状态将变为销毁状态。【完整】
口 onRestart()。这个方法在活动由停止状态变为运行状态之前调用,也就是活动被重新启动了。

4. 体験活動のライフサイクル

ここに画像の説明を挿入
いくつかの新しいアクティビティ、メイン アクティビティのレイアウトを作成します。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="启动活动页1"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="启动弹窗页2"/>

</LinearLayout>

主な活動:

package com.example.activitylifecycletest;

import androidx.annotation.LongDef;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {
    
    

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d("TAG", "onCreate: ");
        Button startNormalActivity=(Button) findViewById(R.id.button);
        Button startDialogActivity=(Button) findViewById(R.id.button2);
        startNormalActivity.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent=new Intent(MainActivity.this,NormalActivity.class);
                startActivity(intent);
            }
        });
        startDialogActivity.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent=new Intent(MainActivity.this,DialogActivity.class);
                startActivity(intent);
            }
        });
    }

    @Override
    protected void onStart() {
    
    
        super.onStart();
        Log.d("TAG", "onStart: ");
    }

    @Override
    protected void onResume() {
    
    
        super.onResume();
        Log.d("TAG", "onResume: ");
    }

    @Override
    protected void onPause() {
    
    
        super.onPause();
        Log.d("TAG", "onPause: ");
    }

    @Override
    protected void onStop() {
    
    
        super.onStop();
        Log.d("TAG", "onStop: ");
    }

    @Override
    protected void onDestroy() {
    
    
        super.onDestroy();
        Log.d("TAG", "onDestroy: ");
    }

    @Override
    protected void onRestart() {
    
    
        super.onRestart();
        Log.d("TAG", "onRestart: ");
    }
}

5. アクティビティのリサイクル前にアクティビティ データを一時的に保存する

前述したように、アクティビティは非表示になると停止状態になり、この時点でアクティビティが再利用される可能性があります。フォームなどのページの場合、クリックして戻ってしまうと直前に入力した情報が失われてしまうという事態を避けるためです。
私たちは、リサイクルされる活動について耳を傾けられるようにしたいと考えています。アクティビティがリサイクルされると、関数がトリガーされます。データを一時的に保存します。このアクティビティに戻るときは、値を再割り当てします。
Activity オブジェクトは、数値を保存するための次の API を提供します。

    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
    
    
        //当前活动被销毁前会执行这里的代码
        super.onSaveInstanceState(outState);
        String testData="这是存储的一些信息";
        //存储对应数据类型的数据
        outState.putString("data_key",testData);
    }

番号を取得するにはどうすればよいですか? アクティビティの onCreate() メソッドは、バンドルをパラメータとして渡します。つまり、バンドルを通じて数値を取得することに注意してください。

 if(savedInstanceState!=null){
    
    
     String testData=savedInstanceState.getString("data_key");
     Log.d("取出来的数的值", testData);
 }

6. アクティビティ開始モード

アクティビティを開始するには、standard、singleTop、singleTask、singleInstance の 4 つの方法があります。AndroidManifest.xmlのタグにandroid:launchMode属性を指定することで起動モードを選択できます。
[標準]
標準は、デフォルトのアクティビティ起動方法です。アクティビティが開始されると、アクティビティはタスク スタックの最上位にプッシュされます。上で作成したアクティビティはすべて、この起動方法を使用します。
新しいプロジェクトを開き、ボタンを作成し、アクティビティに次のコードを記述します。

    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        Log.d("新创建", "onCreate: ");
        setContentView(R.layout.first_layout);
        Button button1=(Button) findViewById(R.id.button);
        button1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent=new Intent(FirstActivity.this,FirstActivity.class);
                startActivity(intent);
            }
        });
    }

このとき、ボタンを 2 回クリックすると、さらに 2 つの現在のアクティビティ FirstActivity が作成され、プログラムを終了するには Return キーを 3 回押す必要があります。
[singleTop]
singleTop モードを使用する場合、アクティビティの開始時に戻りスタックの最上位がすでにアクティビティであることが判明した場合は、新しいアクティビティ インスタンスを作成せずに、それを直接使用できます。
menifext ファイルを変更します。

 <activity
     android:name=".FirstActivity"
     android:launchMode="singleTop"
     android:exported="true">
     <intent-filter>
         <action android:name="android.intent.action.MAIN" />
         <category android:name="android.intent.category.LAUNCHER" />
     </intent-filter>
 </activity>

この時点でボタンをもう一度クリックしても、新しいアクティビティは作成されません。ただし、非スタック アクティビティを作成する場合は、通常どおり作成されます。
[singleTask]
singleTop は、スタックの最上位にアクティビティが繰り返し作成される問題を解決するだけで、ABABACA のような A アクティビティが繰り返し作成される問題は解決できません。そこで、再び singleTask が登場します。これにより、アクティビティが一意であることが保証され、すでに存在する場合は作成されず、直接再利用されます。それをスタックからスタックの一番上に直接移動します。
[singleInstance]
上記の 3 つは、各アクティビティ スタック内にアクティビティのインスタンスが 1 つだけ存在することを実現しています。なぜシングルインスタンスがまだ存在するのですか?
これは、複数のアプリが存在する可能性があるためです。abc のような場合、複数のコール スタック ABC が存在することになります。
これで、アクティビティ H が作成され、abc の 3 つのプログラムすべてによって呼び出されます。3 つのアクティビティ スタックに入ることになるのではないでしょうか。つまり、3 つのインスタンスが作成されます。
この問題を解決するには、singleInstance を使用します。その原理は、新しいアクティビティ スタックを作成することです。現在のアクティビティをこの新しいアクティビティ スタックに置き、他のプログラムがこのアクティビティ スタックを共有できるようにします。
ここに画像の説明を挿入
この時点で、次のように 3 つの新しいアクティビティ ABC を作成し、AC を android:launchMode="singleTop" に設定し、B を singleInstance に設定すると、A が B にジャンプしてから C にジャンプできます。

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyApplicationTest">
        <activity
            android:name=".ThirdActivity"
            android:launchMode="singleTop"
            android:exported="true" >
        </activity>
        <activity
            android:name=".FirstActivity"
            android:launchMode="singleTop"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".SecondActivity"
            android:launchMode="singleInstance"
            android:exported="true">
        </activity>
    </application>

次に、ページに最初のアクティビティを書き込み、2 番目のアクティビティにジャンプし、さらに 3 番目のアクティビティにジャンプします。結果のアクティビティ スタックは、以下に示すように 2 つになります。
ここに画像の説明を挿入
つまり、
singleInstance がアクティビティに設定され、アクティビティは作成後に共有アクティビティ スタックに個別に配置されます。singleTop を設定する他の人は、通常どおり独自のアクティビティ スタックに入ります。
実際の使用では、プログラムが複数ある場合、アクティブなスタックが複数存在し、共有スタックを共有します。
アクティビティ スタックの戻り値は、スタックが空に戻るまで次のアクティビティ スタックに到達しません。
つまり、この時点で Enter キーを押すと、まず共有スタック内の thirdActivity から firstActivity に移動し、次に SecondActivity に移動します。

7. イベントのベストプラクティス

[現在どのアクティビティにいるかを確認する]
新しい通常の Java クラスを作成し、com.example.myApplicationTest-new-Java クラスを右クリックして、新しいクラスを作成し、AppCompatActivity を継承させ、Oncreate を書き換えて、現在のアクティビティを出力します。名前:

public class BaseActivity extends AppCompatActivity {
    
    
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        Log.d("当前活动", getClass().getSimpleName());
    }
}

次に、アクティビティ 123 にこのクラスを継承させます。したがって、各アクティビティが開かれたときに、現在のアクティビティの名前が出力されるという効果が得られます。ここで重要なのは super.onCreate(savedInstanceState) で、親クラスの onCreate が実行されるので、出力できます。
[いつでもどこでもプログラムを終了する] 上
の singleInstance に示すように、 thirdActivity にいるとき、プログラムを終了するにはリターン キーを 3 回押す必要があります。ここで、プログラムを直接閉じますか?
すべてのアクティビティを管理するための新しい配列を作成するだけで済みます。プログラムを直接終了したい場合は、この配列をトラバースして、finish() の形式ですべてのアクティビティを破棄します。次に、現在のプロセスを強制終了します。
新しい ActivityCollector クラスを作成します。

public class ActivityCollector {
    
    
    //新建一个类型为List,内容为Activity类型的数组activities
    public static List<Activity> activities =new ArrayList<Activity>();
    //定义方法,往activities数组中添加值
    public static void addActivity(Activity activity){
    
    
        activities.add(activity);
    }
    //定义方法,从activities中移除值
    public static  void removeActivity(Activity activity){
    
    
        activities.remove(activity);
    }
    //移除所有活动
    public static void finishAll(){
    
    
        for (Activity activity : activities) {
    
    
            if(!activity.isFinishing()){
    
    
                activity.finish();
            }
        }
    }
}

次に、前のポイントの BaseActivity のコードを変更し、このアクティビティを各アクティビティの先頭の配列に追加します。アクティビティが破棄されるたびに、配列からクラスを削除します。

public class BaseActivity extends AppCompatActivity {
    
    
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        Log.d("当前活动", getClass().getSimpleName());
        ActivityCollector.addActivity(this);
    }

    @Override
    protected void onDestroy() {
    
    
        super.onDestroy();
        ActivityCollector.removeActivity(this);
    }
}

このようにして、プログラムを直接終了する場合は、ActivityCollector.finishAll() を直接呼び出してすべてのアクティビティを破棄できます。

public class ThirdActivity extends BaseActivity {
    
    

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.third_layout);
        Button button3=(Button) findViewById(R.id.button3);
        button3.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                ActivityCollector.finishAll();
            }
        });
    }
}

【アクティビティのベストな書き方】
前述の通り、アクティビティ間でデータの受け渡しが可能ですが、複数のパラメータを渡したい場合は、先ほどの方法に従って次のように記述します。

 public void onClick(View view) {
    
    
     Intent intent=new Intent(SecondActivity.this,ThirdActivity.class);
     intent.putExtra("param1","data1");
     intent.putExtra("param2","data2");
     startActivity(intent);
 }

しかし、次のようにする方が合理的で保守が簡単です。

    //在SecondActivity中定义一个方法,启动活动传参专用
    public static void actionStart(Context context, String data1, String data2){
    
    
        Intent intent=new Intent(context,ThirdActivity.class);
        intent.putExtra("param1","data1");
        intent.putExtra("param2","data2");
        context.startActivity(intent);
    }

次に、onCreate の 1 行で直接実行します。

 public void onClick(View view) {
    
    
       //直接调用这个方法
       SecondActivity.actionStart(SecondActivity.this,"data1","data2");
   }

おすすめ

転載: blog.csdn.net/weixin_42349568/article/details/128806721