SlideShare a Scribd company logo
新しくなった画面間の
データ連携を知ろう
About Me
早川 勉(sokume)
stmn.inc/GDG Nagoya organizer
1. Activity データ連携、これまでとこれから
2. Fragment データ連携、これまでとこれから
3. まとめ
新しくなった画面間のデータ連携を知ろう
“このセッションで取り上げている内容には
一部 alpha版、beta版の機能が含まれてお
り、今後変更されていく可能性がありま
す。”
【調査環境】
Android Studio 4.0.2
【追加ライブラリ】
"androidx.activity:activity-ktx:1.2.0-beta01"
"androidx.fragment:fragment-ktx:1.3.0-beta01"
Activity データ連携、
これまでとこれから
● UIや画面を持つコンポーネントの一つ
● ライフサイクルを持っている
● 他のActivity と連携する事が可能
など
Activity とは?
● 暗黙的Intent 連携
● 明示的Intent 連携
連携の種類
● リクエストを元に、対応できるActivityを呼び出す
○ 電話をする、地図を表示する、画像を取得するなど
● 呼び出したActivityがデータを送ってくれたり処理
したりしてくれる
● 主に別のプロジェクトに含まれるActivityとの連携
に使われる
暗黙的Intent 連携
● リクエストを送る先を明確にしていしActivityを呼
び出す
● 呼び出したActivityがデータを送ってくれたり処理
したりしてくれる
● 主に、自分のプロジェクトに含まれるActivityとの
連携に使われる
明示的Intent 連携
1. リクエストを作る
2. 起動する
3. 結果を取得する
これまでの暗黙的Intentの連携処理
リクエストをつくる
// 画像を取得
val nextIntent =
Intent(Intent.ACTION_GET_CONTENT)
.addCategory(Intent.CATEGORY_OPENABLE)
.setType("image/*")
起動する
// 起動処理
startActivityForResult(nextIntent, REQUEST_CODE)
結果を取得する
// 結果を取得
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE){
// 連携結果を元に処理を実施する部分
if (resultCode == RESULT_OK){
// 処理がOKのとき
}else if (resultCode == RESULT_CANCELED){
// キャンセルしたとき
}
}
}
class MainActivity : AppCompatActivity(R.layout.activity_main) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
nextButton.setOnClickListener {
val nextIntent = Intent(Intent.ACTION_GET_CONTENT)
.addCategory(Intent.CATEGORY_OPENABLE)
.setType("image/*")
startActivityForResult(nextIntent, REQUEST_CODE)
}
}
// 結果を取得
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE){
// 連携結果を元に処理を実施する部分
if (resultCode == RESULT_OK){
// 処理がOKのとき
}else if (resultCode == RESULT_CANCELED){
// キャンセルしたとき
}
}
}
・・・//省略
}
ボタン押下
class MainActivity : AppCompatActivity(R.layout.activity_main) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
nextButton.setOnClickListener {
val nextIntent = Intent(Intent.ACTION_GET_CONTENT)
.addCategory(Intent.CATEGORY_OPENABLE)
.setType("image/*")
startActivityForResult(nextIntent, REQUEST_CODE)
}
}
// 結果を取得
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE){
// 連携結果を元に処理を実施する部分
if (resultCode == RESULT_OK){
// 処理がOKのとき
}else if (resultCode == RESULT_CANCELED){
// キャンセルしたとき
}
}
}
・・・//省略
}
ボタン押下
1. リクエストを作る
2. 起動する
3. 結果を取得する
これまでの明示的Intent処理
リクエストをつくる
// MainActivity2を呼び出すリクエスト
val nextIntent =
Intent(this, MainActivity2::class.java)
起動する
// 起動処理
startActivityForResult(nextIntent, REQUEST_CODE)
結果を取得する
// 結果を取得
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE){
// 連携結果を元に処理を実施する部分
if (resultCode == RESULT_OK){
// 処理がOKのとき
}else if (resultCode == RESULT_CANCELED){
// キャンセルしたとき
}
}
}
class MainActivity : AppCompatActivity(R.layout.activity_main) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
nextButton.setOnClickListener {
val nextIntent = Intent(this, MainActivity2::class.java)
startActivityForResult(nextIntent, REQUEST_CODE)
}
}
// 結果を取得
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE){
// 連携結果を元に処理を実施する部分
if (resultCode == RESULT_OK){
// 処理がOKのとき
}else if (resultCode == RESULT_CANCELED){
// キャンセルしたとき
}
}
}
・・・//省略
}
ボタン押下
class MainActivity : AppCompatActivity(R.layout.activity_main) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
nextButton.setOnClickListener {
val nextIntent = Intent(applicationContext, MainActivity2::class.java)
startActivityForResult(nextIntent, REQUEST_CODE)
}
}
// 結果を取得
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE){
// 連携結果を元に処理を実施する部分
if (resultCode == RESULT_OK){
// 処理がOKのとき
}else if (resultCode == RESULT_CANCELED){
// キャンセルしたとき
}
}
}
・・・//省略
}
ボタン押下
● アクションが増えると結果を受ける処理が肥大化しや
すい😨
● Int型の数値で呼び出し元を判定するので重複しそう
なところが嫌だったり😟
これまでの実装で悩ましいポイント
class MainActivity : AppCompatActivity(R.layout.activity_main) {
override fun onCreate(savedInstanceState: Bundle?) {
     ・・・
nextButton1.setOnClickListener {
val nextIntent = Intent(applicationContext, MainActivity2::class.java)
startActivityForResult(nextIntent1, REQUEST_CODE1)
}
nextButton2.setOnClickListener {
val nextIntent = Intent(applicationContext, MainActivity3::class.java)
startActivityForResult(nextIntent2, REQUEST_CODE2)
}
}
// 結果を取得
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE1){
// 連携結果を元に処理を実施する部分
・・・//省略
}
     if (requestCode == REQUEST_CODE2){
・・・//省略
}
}
companion object{
private const val REQUEST_CODE1 = 100
private const val REQUEST_CODE2 = 101
}
}
ボタン押下1
ボタン押下2
1. 結果を取得する為の登録を行う
2. 起動する
これからの暗黙的Intentの処理
結果を取得する為の登録を行う
// 結果取得の登録
val registerResult =
registerForActivityResult
(ActivityResultContracts.GetContent()) { uri: Uri? →
//結果を取得した処理
}
起動する
// 起動処理
registerResult.launch("image/*")
class MainActivity : AppCompatActivity(R.layout.activity_main) {
private val registerResult =
registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? →
Log.d("result", "activity: $uri")
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
nextButton.setOnClickListener {
registerResult.launch("image/*")
}
}
・・・//省略
}
ボタン押下
1. データ連携クラスを作る(呼び出すクラス)
2. 結果を取得する為の登録を行う
3. 起動する
これからの明示的Intentの処理
データ連携クラスを作る
// MainActivity2のデータ連携クラス
class Main2ActivityResultContract : ActivityResultContract<Int,Main2Result?>()
{
override fun createIntent(context: Context, input: Int): Intent {
return Intent(context, MainActivity2::class.java).apply {
putExtra(ID_KEY, input)
}
}
override fun parseResult(resultCode: Int, intent: Intent?): Main2Result? {
if (resultCode == RESULT_OK){
return intent?.run {
Main2Result(
getIntExtra(ID_KEY,0),
getStringExtra(NAME_KEY) ?: "")
}
}
return null
}
・・・省略
}
データ連携クラスを作る
// MainActivity2のデータ連携クラス
class Main2ActivityResultContract : ActivityResultContract<Int,Main2Result?>()
{
override fun createIntent(context: Context, input: Int): Intent {
return Intent(context, MainActivity2::class.java).apply {
putExtra(ID_KEY, input)
}
}
override fun parseResult(resultCode: Int, intent: Intent?): Main2Result? {
if (resultCode == RESULT_OK){
return intent?.run {
Main2Result(
getIntExtra(ID_KEY,0),
getStringExtra(NAME_KEY) ?: "")
}
}
return null
}
・・・省略
}
データ連携クラスを作る
// MainActivity2のデータ連携クラス
class Main2ActivityResultContract : ActivityResultContract<Int,Main2Result?>()
{
override fun createIntent(context: Context, input: Int): Intent {
return Intent(context, MainActivity2::class.java).apply {
putExtra(ID_KEY, input)
}
}
override fun parseResult(resultCode: Int, intent: Intent?): Main2Result? {
if (resultCode == RESULT_OK){
return intent?.run {
Main2Result(
getIntExtra(ID_KEY,0),
getStringExtra(NAME_KEY) ?: "")
}
}
return null
}
・・・省略
}
結果を取得する為の登録を行う
// 結果取得の登録
val registerResult =
registerForActivityResult(Main2ActivityResultContract())) {
result: Main2Result? →
// 結果を取得した処理
}
起動する
// 起動処理
registerResult.launch(12345)
class MainActivity : AppCompatActivity(R.layout.activity_main) {
private val registerResult =
registerForActivityResult(Main2ActivityResultContract()) { result: Main2Result? →
Log.d("result", "activity: $result")
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
nextButton.setOnClickListener {
registerResult.launch(12345)
}
}
・・・//省略
}
ボタン押下
class MainActivity : AppCompatActivity(R.layout.activity_main) {
private val registerResultM2 =
registerForActivityResult(Main2ActivityResultContract()) { result: Main2Result? →
Log.d("result", "activity: $result")
}
private val registerResultM3 =
registerForActivityResult(Main3ActivityResultContract()) { result: Main3Result? →
Log.d("result", "activity: $result")
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
nextButton1.setOnClickListener {
registerResultM2.launch(12345)
}
nextButton2.setOnClickListener {
registerResultM3.launch(12345)
}
}
・・・//省略
}
ボタン押下
ボタン押下
● Activityを使われるクラスで、
ActivityResultContractを利用し
インプット(入力値)、アウトプット(結果)を
明確に指定できる。
● 呼び出す側の結果取得処理の肥大化を防げる
● 呼び出す側はデータの不一致などを気にする必要が減
る。
point
Fragmentのデータ連携
のこれまでとこれから
● UIを持つコンポーネントの一つ
● ライフサイクルを持っている
● 同じFragmentManagerに属するFragment と連携
する事が可能
など
Fragment とは?
1. 次のFragmentを作る
2. FragmentManagerに登録する
3. 結果を取得する
これまでのFragmentの連携処理
次のFragmentを作る
val nextFragment =
NextFragment.newInstance("param_n_1","param_n_2")
nextFragment.setTargetFragment(this,REQUEST_CODE)
FragmentManagerに登録する
requireActivity()
.supportFragmentManager
.beginTransaction()
.replace(R.id.content,nextFragment)
.addToBackStack(null)
.commit()
結果を取得する
override fun onActivityResult
(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE){
// 連携結果を元に処理を実施する部分
if (resultCode == AppCompatActivity.RESULT_OK){
// 処理がOKのとき
}
}
}
class TopFragment : Fragment() {
・・・//省略
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
nextButton.setOnClickListener {
val nextFragment = NextFragment.newInstance("param_n_1","param_n_2")
nextFragment.setTargetFragment(this,REQUEST_CODE)
requireActivity()
.supportFragmentManager
.beginTransaction()
.replace(R.id.content,nextFragment)
.addToBackStack(null)
.commit()
}
}
// 結果を取得
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE){
// 連携結果を元に処理を実施する部分
if (resultCode == RESULT_OK){
// 処理がOKのとき
}
}
}
・・・//省略
}
ボタン押下
結果を返却する(呼び出し先アプリ)
targetFragment?.apply {
val intent = Intent()
intent.putExtra(Intent.EXTRA_TEXT, "fragment")
onActivityResult(targetRequestCode, RESULT_OK, intent)
}
requireActivity()
.supportFragmentManager.run {
popBackStack()
}
1. 次のFragmentを作る
2. 結果の取得先を登録する
3. FragmentManagerに登録する
これからのFragmentの連携処理
次のFragmentを作る
val nextFragment =
NextFragment.newInstance("param_n_1","param_n_2")
結果の取得先を登録する
setFragmentResultListener(REQUEST_KEY) { key, data →
// 結果の受信処理
if (key == REQUEST_KEY){
}
}
FragmentManagerに登録する
requireActivity()
.supportFragmentManager
.beginTransaction()
.replace(R.id.content,nextFragment)
.addToBackStack(null)
.commit()
class TopFragment : Fragment() {
・・・//省略
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
nextButton.setOnClickListener {
val nextFragment = NextFragment.newInstance("param_n_1","param_n_2")
setFragmentResultListener(REQUEST_KEY) { key, data →
// 結果の受信処理
if (key == REQUEST_KEY){
}
}
requireActivity()
.supportFragmentManager
.beginTransaction()
.replace(R.id.content,nextFragment)
.addToBackStack(null)
.commit()
}
}
・・・//省略
}
ボタン押下
結果を返却する(呼び出し先アプリ)
val bundle = Bundle().apply {
putString(Intent.EXTRA_TEXT, "fragment")
}
requireActivity()
.supportFragmentManager.run {
setFragmentResult(REQUEST_KEY,bundle)
popBackStack()
}
● FragmentManagerが結果の返却を管理する
● ライフサイクルに合わせてデータの返却をしてくれる
● FragmentなのにonActivityResult()を利用する
必要がなくなった
point
まとめ
● ActivityとFragmentのデータ連携は新しい方法
がきっとスタンダートになるだろうから、積極的に
使っていくと良さそう。
● まだ検索するとこれまでの実装方法がたくさんでて
くるから、古い方法も一応知っておこうと良いと思
う。
まとめ
● https://developer.android.com/training
/basics/intents/result
↑日本語ページは内容が古いのでご注意を😅
● https://developer.android.com/training/basics/fragme
nts/pass-data-between
参考URL
“引き続き GDG DevFest 2020をお
楽しみください🎉”

More Related Content

PDF
【Android勉強会】第一回Activity & intent
PPT
Gaej Jdo
PDF
Try Jetpack
KEY
Google App Engine for Java
PDF
Tokyo GTUG Bootcamp2010
PDF
OnActivityResult - おまえら!もうonActivityResultでswitchとif書く時代は終わりだぞ!
PPTX
学生向けAndroid勉強会(入門編)
PDF
"あんざいゆき" x "秋葉ちひろ" はカンファレンスアプリをどう作るのか?
【Android勉強会】第一回Activity & intent
Gaej Jdo
Try Jetpack
Google App Engine for Java
Tokyo GTUG Bootcamp2010
OnActivityResult - おまえら!もうonActivityResultでswitchとif書く時代は終わりだぞ!
学生向けAndroid勉強会(入門編)
"あんざいゆき" x "秋葉ちひろ" はカンファレンスアプリをどう作るのか?

Similar to GDG DevFest 2020 Android data linkage info (6)

PDF
Androidの通信周りのコーディングについて
ODP
OSC2011 Androidハンズオン
PPT
Android Hacks - Hack8
PPTX
初めてのAndroid開発
KEY
[ABC2012S]Android2x/3x/4x対応アプリ開発Tips
PDF
Xamarin 基礎講座
Androidの通信周りのコーディングについて
OSC2011 Androidハンズオン
Android Hacks - Hack8
初めてのAndroid開発
[ABC2012S]Android2x/3x/4x対応アプリ開発Tips
Xamarin 基礎講座
Ad

GDG DevFest 2020 Android data linkage info