[Android]startActivityForResult()が非推奨に……その対策

投稿者:

しばらく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();
    }
}

アプリを起動すると次のようになる

(1)起動直後:ボタンタップでサブ画面起動
(2)サブ画面:ここでテキストを入力
(3)メイン画面に戻る:サブ画面の入力結果を受け取りToastで表示

サンプルコードのハイライト部分がActivityの新しい起動方法を記述してある部分である。

registerForActivityResult()メソッドでActivityResultLauncherのインスタンスを作成して変数subactivityLauncherに代入している。IntentにアクティビティのクラスをセットしてsubactivityLauncher.launch(intent)で起動する。

registerForActivityResult()の第一変数はlaunch()メソッドの引数の型と、結果を受け取るコールバックの引数の型を定義するオブジェクトのようだ、new ActivityResultContracts.StartActivityForResult()で、それぞれIntentとActivityRasultがセットされる。
第二引数は起動元アクティビティに戻った時に結果を処理するコールバックだ。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください