【AndroidStudio】Intentで起動元に値を返す方法（ActivityResultLauncher）

#はじめに
AndroidでIntentを扱っていると、MainActivityから何かしらのActivityを呼び出して、呼び出したActivityが終了したら戻り値を受け取ってMainActivityで処理したい場面が良く登場します。ActivityResultLauncherというクラスを利用すれば可能のようですが、公式ドキュメントもQiitaの記事も優しくなかったりして意外と手間取ってしまったので、めちゃくちゃ優しく書いていきます。例のごとく、Javaしか書けないのでJavaで、、、

#戻り値のないIntentのプログラム
まずはベースとなるプログラムを確認していきます。MainActivityで個数を指定して、SubActivityで個数を受け取って表示し、戻るボタンを押したら何もせずにMainActivityに戻り、確定ボタンを押したら個数を返してトーストで表示し、個数をリセットするというプログラムにします。もちろん戻り値なしのものを作るため、SubActivityからMainActivityに値を渡せずに、どっちのボタンを押してもただMainActivityに戻るだけになります。とりあえずソースを書いていきます。インポート文は書いてないので、自分でインポートしてあげてください（赤文字のところにカーソルを持っていくと、import～って書いてあるところが出てくるので、それをクリックしていく）。

```xml:activity_main.xml
<?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"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:orientation="horizontal">
        <TextView
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="0.5"
            android:gravity="center"
            android:text="@string/tvQuantity"/>
        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.4"
            android:layout_marginEnd="10dp">
            <Button
                android:id="@+id/btMinus"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.3"
                android:text="@string/btMinus"/>
            <TextView
                android:id="@+id/tvItemQuantity"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.4"
                android:gravity="center"/>
            <Button
                android:id="@+id/btPlus"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.3"
                android:text="@string/btPlus"/>
        </LinearLayout>

    </LinearLayout>

    <Button
        android:id="@+id/btConfirm"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:layout_gravity="center"
        android:text="@string/btConfirm"/>

</LinearLayout>
```

```java:MainActivity.java
public class MainActivity extends AppCompatActivity {

    int quantity = 0;

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

        TextView tvItemQuantity = findViewById(R.id.tvItemQuantity);
        tvItemQuantity.setText(String.valueOf(quantity));

        Button btMinus = findViewById(R.id.btMinus);
        btMinus.setOnClickListener(v -> {
            if(quantity > 0){
                quantity--;
            }
            tvItemQuantity.setText(String.valueOf(quantity));
        });

        Button btPlus = findViewById(R.id.btPlus);
        btPlus.setOnClickListener(v -> {
            quantity++;
            tvItemQuantity.setText(String.valueOf(quantity));
        });

        Button btConfirm = findViewById(R.id.btConfirm);
        btConfirm.setOnClickListener(v -> {
            Intent intent = new Intent(MainActivity.this, SubActivity.class);
            intent.putExtra("quantity", quantity);
            startActivity(intent);
        });
    }
}
```

```xml:activity_sub.xml
<?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"
    tools:context=".SubActivity"
    android:orientation="vertical">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="@string/tvConfirmTitle"
        android:textSize="20sp"
        android:gravity="center"/>
    <TextView
        android:id="@+id/tvConfirmQuantity"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:textSize="18sp"
        android:gravity="center"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:orientation="horizontal"
        android:gravity="center">
        <Button
            android:id="@+id/btBack"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginEnd="40dp"
            android:text="@string/btBack"/>
        <Button
            android:id="@+id/btDecide"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/btDecide"/>
    </LinearLayout>

</LinearLayout>
```

```java:SubActivity.java
public class SubActivity extends AppCompatActivity {

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

        Intent intent = getIntent();
        int quantity = intent.getIntExtra("quantity", 0);

        TextView tvConfirmQuantity = findViewById(R.id.tvConfirmQuantity);
        tvConfirmQuantity.setText(quantity + "個");

        Button btBack = findViewById(R.id.btBack);
        btBack.setOnClickListener(v -> {
            finish();
        });

        Button btDecide = findViewById(R.id.btDecide);
        btDecide.setOnClickListener(v -> {
            finish();
        });
    }
}
```

上のソースでとりあえず形は完成ですが、SubActivityからMainActivityにデータを飛ばしたいですよね。というわけで、ActivityResultLauncherを利用してデータを飛ばしましょう。

#ActivityResultLauncherを使う
まずSubActivityを少しいじります。SubActivityのbtDecideのonClick処理にIntentでデータを飛ばす処理を追加していきます。

```java:SubActivity.java
btDecide.setOnClickListener(v -> {
//~~~~~~~~~ここから追記~~~~~~~~~~~~~
    Intent resIntent = new Intent();
    resIntent.putExtra("quantity", quantity);
    setResult(Activity.RESULT_OK, resIntent);
//~~~~~~~~~ここまで~~~~~~~~~~~~~~~~
    finish();
});
```
setResultは、MainActivityに戻った際にこれを検証して処理を実行するときに使いますが、とりあえずおまじないみたいなものだと思ってもらって大丈夫です。
次にMainActivityでデータを受け取る処理を書きます。追記していただきたいのは下の方です。

```java:MainActivity.java
public class MainActivity extends AppCompatActivity {

    int quantity = 0;

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

        TextView tvItemQuantity = findViewById(R.id.tvItemQuantity);
        tvItemQuantity.setText(String.valueOf(quantity));

        Button btMinus = findViewById(R.id.btMinus);
        btMinus.setOnClickListener(v -> {
            if(quantity > 0){
                quantity--;
            }
            tvItemQuantity.setText(String.valueOf(quantity));
        });

        Button btPlus = findViewById(R.id.btPlus);
        btPlus.setOnClickListener(v -> {
            quantity++;
            tvItemQuantity.setText(String.valueOf(quantity));
        });

        Button btConfirm = findViewById(R.id.btConfirm);
        btConfirm.setOnClickListener(v -> {
            Intent intent = new Intent(MainActivity.this, SubActivity.class);
            intent.putExtra("quantity", quantity);

            //~~~~~ここstartActivityから変更です
            resultLauncher.launch(intent);
            //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        });
    }

    //~~~~~~~~~~ここから追記~~~~~~~~~~~~~~~~~
    ActivityResultLauncher<Intent> resultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result ->{
        if(result.getResultCode() == RESULT_OK){ //SubActivityのsetResultでRESULT_OKされていれば処理を行います
            //データを受け取ったあとの処理をここに書きます
            Intent resIntent = result.getData();
            quantity = resIntent.getIntExtra("quantity", 0);
            String ToastText = quantity + "個注文しました";
            Toast.makeText(this, ToastText, Toast.LENGTH_LONG).show();
            quantity = 0;
            TextView tvItemQuantity = findViewById(R.id.tvItemQuantity);
            tvItemQuantity.setText(String.valueOf(quantity));
        }
    });
    //~~~~~~~~~ここまで~~~~~~~~~~~~~~~~~~~~~~~
}
```

とりあえずこれでSubActivityからMainActivityにデータを飛ばせました。

構造を説明していきます。
まずMainActivityにActivityResultLauncherのインスタンスを生成し、resultの中にデータを受け取った後の処理を書きます。

```java:MainActivity.java
ActivityResultLauncher<Intent> resultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result ->{
    if(result.getResultCode() == RESULT_OK){ //SubActivityのsetResultでRESULT_OKされていれば処理を行います

    //ここに処理を書く

    }
});
```

そうしたら、SubActivityを起動する処理をstartActivityではなく、生成したActivityResultLauncherのインスタンスのlaunchメソッドで起動します。

```java:MainActivity.java
resultLauncher.launch(intent);
```
SubActivityでデータを受け取るときはいつも通りgetIntent()で受け取れます。
SubActivityからMainActivityにデータを渡すにはIntentに渡したいデータを入れて、setResultでResultCodeを渡します。

```java:SubActivity.java
btDecide.setOnClickListener(v -> {
    Intent resIntent = new Intent();
    //Intentに値を入れる処理をここに書く
    setResult(Activity.RESULT_OK, resIntent);
    finish();
});
```

#まとめ
基本的な流れをまとめます

1.MainActivityでActivityResultLauncherのインスタンスを生成
2.MainActivityでSubActivityに飛ばしたいデータをIntentに入れて、ActivityResultLauncherのlaunchメソッドでSubActivityを起動
3.SubActivityでMainActivityに戻る処理を書くときに、Intentにデータを入れて、ResultCodeをセットしfinishする
4.MainActivityのActivityResultLauncher内で、データを受け取った時の処理を書く

といった感じで進めていけばとりあえず動くかと思います。
kotlinの記事はたくさんあるのにJavaの記事が全然なくてわからん...という方の参考になればと思います。