Activity Result APIによる書き換え

Androidアプリで別アクティビティを起動して、そのアクティビティの処理終了後に元のアクティビティで処理を引き継ぐ処理を記述したい場合、これまでは、ActivityクラスにあるstartActivityForResult()メソッドとonActivityResult()メソッドを組み合わせて使っていた。これが、非推奨になった。代わりに、Activity Result APIを利用するようにとのこと。そこで、Androidアプリ開発の教科書の第15章のCameraIntentSampleを題材にして、コードの対応を紹介しておこうと思う。まず、書籍に記載のstartActivityForResult()+onActivityResult()のコードは以下の通りである。

public class MainActivity extends AppCompatActivity {
  :
  public void onCameraImageClick(View view) {
      :
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, _imageUri);
    startActivityForResult(intent, 200);
  }

  @Override
  public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(requestCode == 200 && resultCode == RESULT_OK) {
      ImageView ivCamera = findViewById(R.id.ivCamera);
      ivCamera.setImageURI(_imageUri);
    }
  }
}

これが、Activity Result APIを使うと、以下のようになる。

public class MainActivity extends AppCompatActivity {
  :
  ActivityResultLauncher<Intent> _cameraLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallbackFromCamera());  // (1)

  public void onCameraImageClick(View view) {
      :
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, _imageUri);
    _cameraLauncher.launch(intent);  // (2)
  }

  private class ActivityResultCallbackFromCamera implements ActivityResultCallback<ActivityResult> {  // (3)
    @Override
    public void onActivityResult(ActivityResult result) {
      if(result.getResultCode() == RESULT_OK) {
        ImageView ivCamera = findViewById(R.id.ivCamera);
        ivCamera.setImageURI(_imageUri);
      }
    }
  }
}

ポイントは、これまでonActivityResult()内に記述していた処理を、ActivityResultCallbackインターフェースをimplementsした専用のコールバッククラスを用意して(3)、onActivityResult()メソッド内に記述し、そのコールバッククラスをもとにActivityResultLauncherを生成するところ(1)。アクティビティの起動は、このActivityResultLauncherのlaunch()メソッドを利用する(2)。
この方式だと、コールバックごとに専用クラスを用意することになり、従来ならrequestCodeによって行っていた分岐が不要になるぶん、確かにコードがスッキリする。なるほど。
Androidアプリ開発の教科書にはKotlin版もあるので、Kotlinでも同様に対比コードを掲載しておこう。

class MainActivity : AppCompatActivity() {
  :
  fun onCameraImageClick(view: View) {
      :
    intent.putExtra(MediaStore.EXTRA_OUTPUT, _imageUri)
    startActivityForResult(intent, 200)
  }

  override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if(requestCode == 200 && resultCode == RESULT_OK) {
      val ivCamera = findViewById<ImageView>(R.id.ivCamera)
      ivCamera.setImageURI(_imageUri)
    }
  }
}

これが、Activity Result APIを使うと、以下のようになる。

class MainActivity : AppCompatActivity() {
  :
  private val _cameraLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult(), ActivityResultCallbackFromCamera())

  fun onCameraImageClick(view: View) {
      :
    intent.putExtra(MediaStore.EXTRA_OUTPUT, _imageUri)
    _cameraLauncher.launch(intent)
  }

  private inner class ActivityResultCallbackFromCamera : ActivityResultCallback<ActivityResult> {
    override fun onActivityResult(result: ActivityResult?) {
      if(result?.resultCode == RESULT_OK) {
        val ivCamera = findViewById<ImageView>(R.id.ivCamera)
        ivCamera.setImageURI(_imageUri)
      }
    }
  }
}