しばらくAndroidの開発から遠ざかっていたのだが、古いアプリのメンテナンスでAndroid Studioを起動したら驚いた。長い間不変だったstartActivityForResult()が非推奨になっていた。代わりに導入されたのがActivityResultLauncherというオブジェクトらしい。
startActivityForResult()は結果を返すアクティビティを起動するメソッドで、結果はonActivityResult()で受け取って処理するのが今までのやり方だった。
void openSubActivity() {
int requestCode = 1;
Intent intent = new Intent(this, SubActivity.class);
//SubActivityを開く
startActivityForResult(intent, requestCode );
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//SubActivityからの結果を受け取る
if (requestCode == 1) {
if (resultCode == RESULT_OK) {
int a = data.getIntExtra("key", 0);
Toast.makeText(this, String.valueOf(a), Toast.LENGTH_SHORT).show();
}
}
}
ただ、このやり方はコードが分散してしまう傾向があり、可読性があまりよくなかった。複数の異なるActivityを扱う場合はonActivityResult()内で分岐する必要もある。それらの問題を解決するため、ActivityResultLauncherが導入された……のかどうか知らないが、とりあえず既存のアプリをこの新しいやり方に書き換えることにした。
ところが、どんなふうにコーディングするのかネットで検索してみたところ、出てくるサンプルがKotlinで記述してあるものばかりで、JAVAのサンプルがほとんどない。うーむ、もうAndroidの開発言語はKotlinが主流になったのだろうか? とはいっても古いアプリはJAVAで記述してあるので新しいコードもJAVAで書かなければならない。
仕方なくGoogleの解説ページに載っているサンプルや、検索で出てきたKotlinのコードを参考にしてなんとか動かせたので、同じくJAVAのサンプルを欲しているプログラマのために、ActivityResultLauncherを使った結果を返すActivityを起動するJAVAプログラムを記しておこうと思う。
サンプルプログラム
レイアウトファイル
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<Button
android:id="@+id/open_sub_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="サブ画面" />
</RelativeLayout>
activity_sub.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/sub_edit"
android:layout_margin="3dp"
android:text="何か入力"/>
<EditText
android:id="@+id/sub_edit"
android:layout_centerInParent="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
JAVAファイル
MainActivity.java
public class MainActivity extends AppCompatActivity {
/******* メンバ変数 *******/
final Context context = this;
//SubActivityを開くActivityResultLauncher
final ActivityResultLauncher<Intent> subactivityLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
//MainActivityに戻った時の処理を定義
if (result.getResultCode() == RESULT_OK) {
Intent data = result.getData();
String message = data.getStringExtra("message_key");
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "** no input **", Toast.LENGTH_SHORT).show();
}
}
}
);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnSubActivity = findViewById(R.id.open_sub_button);
btnSubActivity.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//ボタンクリック時SubActivityを開く
Intent intent = new Intent(context, SubActivity.class);
subactivityLauncher.launch(intent);
}
});
}
}
SubActivity.java
public class SubActivity extends AppCompatActivity {
/**** メンバ変数 ****/
EditText editText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sub);
editText = findViewById(R.id.sub_edit);
}
@Override
public void finish() {
//EditTextの入力結果をセットする
int result;
String message = editText.getText().toString();
if (message.length() == 0) {
result = RESULT_CANCELED;
} else {
result = RESULT_OK;
}
Intent intent = new Intent();
intent.putExtra("message_key", message);
setResult(result,intent);
super.finish();
}
}
アプリを起動すると次のようになる
サンプルコードのハイライト部分がActivityの新しい起動方法を記述してある部分である。
registerForActivityResult()メソッドでActivityResultLauncherのインスタンスを作成して変数subactivityLauncherに代入している。IntentにアクティビティのクラスをセットしてsubactivityLauncher.launch(intent)で起動する。
registerForActivityResult()の第一変数はlaunch()メソッドの引数の型と、結果を受け取るコールバックの引数の型を定義するオブジェクトのようだ、new ActivityResultContracts.StartActivityForResult()で、それぞれIntentとActivityRasultがセットされる。
第二引数は起動元アクティビティに戻った時に結果を処理するコールバックだ。