#はじめに
AndroidでIntentを扱っていると、MainActivityから何かしらのActivityを呼び出して、呼び出したActivityが終了したら戻り値を受け取ってMainActivityで処理したい場面が良く登場します。ActivityResultLauncherというクラスを利用すれば可能のようですが、公式ドキュメントもQiitaの記事も優しくなかったりして意外と手間取ってしまったので、めちゃくちゃ優しく書いていきます。例のごとく、Javaしか書けないのでJavaで、、、
#戻り値のないIntentのプログラム
まずはベースとなるプログラムを確認していきます。MainActivityで個数を指定して、SubActivityで個数を受け取って表示し、戻るボタンを押したら何もせずにMainActivityに戻り、確定ボタンを押したら個数を返してトーストで表示し、個数をリセットするというプログラムにします。もちろん戻り値なしのものを作るため、SubActivityからMainActivityに値を渡せずに、どっちのボタンを押してもただMainActivityに戻るだけになります。とりあえずソースを書いていきます。インポート文は書いてないので、自分でインポートしてあげてください(赤文字のところにカーソルを持っていくと、import~って書いてあるところが出てくるので、それをクリックしていく)。
<?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>
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 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>
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でデータを飛ばす処理を追加していきます。
btDecide.setOnClickListener(v -> {
//~~~~~~~~~ここから追記~~~~~~~~~~~~~
Intent resIntent = new Intent();
resIntent.putExtra("quantity", quantity);
setResult(Activity.RESULT_OK, resIntent);
//~~~~~~~~~ここまで~~~~~~~~~~~~~~~~
finish();
});
setResultは、MainActivityに戻った際にこれを検証して処理を実行するときに使いますが、とりあえずおまじないみたいなものだと思ってもらって大丈夫です。
次にMainActivityでデータを受け取る処理を書きます。追記していただきたいのは下の方です。
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の中にデータを受け取った後の処理を書きます。
ActivityResultLauncher<Intent> resultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result ->{
if(result.getResultCode() == RESULT_OK){ //SubActivityのsetResultでRESULT_OKされていれば処理を行います
//ここに処理を書く
}
});
そうしたら、SubActivityを起動する処理をstartActivityではなく、生成したActivityResultLauncherのインスタンスのlaunchメソッドで起動します。
resultLauncher.launch(intent);
SubActivityでデータを受け取るときはいつも通りgetIntent()で受け取れます。
SubActivityからMainActivityにデータを渡すにはIntentに渡したいデータを入れて、setResultでResultCodeを渡します。
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の記事が全然なくてわからん...という方の参考になればと思います。