Submit Search
GDG DevFest 2020 Android data linkage info
0 likes
278 views
T
tsutomuhayakawa
新しくなった画面間のデータ連携を知ろう
Engineering
Read more
1 of 56
Download now
Download to read offline
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
More Related Content
PDF
【Android勉強会】第一回Activity & intent
Ishin FUKUOKA
PPT
Gaej Jdo
katsu.taira
PDF
Try Jetpack
Hideaki Miyake
KEY
Google App Engine for Java
Takuya Tsuchida
PDF
Tokyo GTUG Bootcamp2010
Takashi EGAWA
PDF
OnActivityResult - おまえら!もうonActivityResultでswitchとif書く時代は終わりだぞ!
Shinobu Okano
PPTX
学生向けAndroid勉強会(入門編)
Itsuki Kuroda
PDF
"あんざいゆき" x "秋葉ちひろ" はカンファレンスアプリをどう作るのか?
Yuki Anzai
【Android勉強会】第一回Activity & intent
Ishin FUKUOKA
Gaej Jdo
katsu.taira
Try Jetpack
Hideaki Miyake
Google App Engine for Java
Takuya Tsuchida
Tokyo GTUG Bootcamp2010
Takashi EGAWA
OnActivityResult - おまえら!もうonActivityResultでswitchとif書く時代は終わりだぞ!
Shinobu Okano
学生向けAndroid勉強会(入門編)
Itsuki Kuroda
"あんざいゆき" x "秋葉ちひろ" はカンファレンスアプリをどう作るのか?
Yuki Anzai
Similar to GDG DevFest 2020 Android data linkage info
(6)
PDF
Androidの通信周りのコーディングについて
Shoichi Takagi
ODP
OSC2011 Androidハンズオン
Katsumi Honda
PPT
Android Hacks - Hack8
Masanori Ohkawara
PPTX
初めてのAndroid開発
tanihiro
KEY
[ABC2012S]Android2x/3x/4x対応アプリ開発Tips
Kenichi Kambara
PDF
Xamarin 基礎講座
Yoshito Tabuchi
Androidの通信周りのコーディングについて
Shoichi Takagi
OSC2011 Androidハンズオン
Katsumi Honda
Android Hacks - Hack8
Masanori Ohkawara
初めてのAndroid開発
tanihiro
[ABC2012S]Android2x/3x/4x対応アプリ開発Tips
Kenichi Kambara
Xamarin 基礎講座
Yoshito Tabuchi
Ad
GDG DevFest 2020 Android data linkage info
1.
新しくなった画面間の データ連携を知ろう
2.
About Me 早川 勉(sokume) stmn.inc/GDG
Nagoya organizer
3.
1. Activity データ連携、これまでとこれから 2.
Fragment データ連携、これまでとこれから 3. まとめ 新しくなった画面間のデータ連携を知ろう
4.
“このセッションで取り上げている内容には 一部 alpha版、beta版の機能が含まれてお り、今後変更されていく可能性がありま す。”
5.
【調査環境】 Android Studio 4.0.2 【追加ライブラリ】 "androidx.activity:activity-ktx:1.2.0-beta01" "androidx.fragment:fragment-ktx:1.3.0-beta01"
6.
Activity データ連携、 これまでとこれから
7.
● UIや画面を持つコンポーネントの一つ ● ライフサイクルを持っている ●
他のActivity と連携する事が可能 など Activity とは?
8.
● 暗黙的Intent 連携 ●
明示的Intent 連携 連携の種類
9.
● リクエストを元に、対応できるActivityを呼び出す ○ 電話をする、地図を表示する、画像を取得するなど ●
呼び出したActivityがデータを送ってくれたり処理 したりしてくれる ● 主に別のプロジェクトに含まれるActivityとの連携 に使われる 暗黙的Intent 連携
10.
● リクエストを送る先を明確にしていしActivityを呼 び出す ● 呼び出したActivityがデータを送ってくれたり処理 したりしてくれる ●
主に、自分のプロジェクトに含まれるActivityとの 連携に使われる 明示的Intent 連携
11.
1. リクエストを作る 2. 起動する 3.
結果を取得する これまでの暗黙的Intentの連携処理
12.
リクエストをつくる // 画像を取得 val nextIntent
= Intent(Intent.ACTION_GET_CONTENT) .addCategory(Intent.CATEGORY_OPENABLE) .setType("image/*")
13.
起動する // 起動処理 startActivityForResult(nextIntent, REQUEST_CODE)
14.
結果を取得する // 結果を取得 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){ // キャンセルしたとき } } }
15.
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){ // キャンセルしたとき } } } ・・・//省略 } ボタン押下
16.
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){ // キャンセルしたとき } } } ・・・//省略 } ボタン押下
17.
1. リクエストを作る 2. 起動する 3.
結果を取得する これまでの明示的Intent処理
18.
リクエストをつくる // MainActivity2を呼び出すリクエスト val nextIntent
= Intent(this, MainActivity2::class.java)
19.
起動する // 起動処理 startActivityForResult(nextIntent, REQUEST_CODE)
20.
結果を取得する // 結果を取得 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){ // キャンセルしたとき } } }
21.
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){ // キャンセルしたとき } } } ・・・//省略 } ボタン押下
22.
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){ // キャンセルしたとき } } } ・・・//省略 } ボタン押下
23.
● アクションが増えると結果を受ける処理が肥大化しや すい😨 ● Int型の数値で呼び出し元を判定するので重複しそう なところが嫌だったり😟 これまでの実装で悩ましいポイント
24.
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
25.
1. 結果を取得する為の登録を行う 2. 起動する これからの暗黙的Intentの処理
26.
結果を取得する為の登録を行う // 結果取得の登録 val registerResult
= registerForActivityResult (ActivityResultContracts.GetContent()) { uri: Uri? → //結果を取得した処理 }
27.
起動する // 起動処理 registerResult.launch("image/*")
28.
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/*") } } ・・・//省略 } ボタン押下
29.
1. データ連携クラスを作る(呼び出すクラス) 2. 結果を取得する為の登録を行う 3.
起動する これからの明示的Intentの処理
30.
データ連携クラスを作る // 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 } ・・・省略 }
31.
データ連携クラスを作る // 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 } ・・・省略 }
32.
データ連携クラスを作る // 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 } ・・・省略 }
33.
結果を取得する為の登録を行う // 結果取得の登録 val registerResult
= registerForActivityResult(Main2ActivityResultContract())) { result: Main2Result? → // 結果を取得した処理 }
34.
起動する // 起動処理 registerResult.launch(12345)
35.
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) } } ・・・//省略 } ボタン押下
36.
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) } } ・・・//省略 } ボタン押下 ボタン押下
37.
● Activityを使われるクラスで、 ActivityResultContractを利用し インプット(入力値)、アウトプット(結果)を 明確に指定できる。 ● 呼び出す側の結果取得処理の肥大化を防げる ●
呼び出す側はデータの不一致などを気にする必要が減 る。 point
38.
Fragmentのデータ連携 のこれまでとこれから
39.
● UIを持つコンポーネントの一つ ● ライフサイクルを持っている ●
同じFragmentManagerに属するFragment と連携 する事が可能 など Fragment とは?
40.
1. 次のFragmentを作る 2. FragmentManagerに登録する 3.
結果を取得する これまでのFragmentの連携処理
41.
次のFragmentを作る val nextFragment = NextFragment.newInstance("param_n_1","param_n_2") nextFragment.setTargetFragment(this,REQUEST_CODE)
42.
FragmentManagerに登録する requireActivity() .supportFragmentManager .beginTransaction() .replace(R.id.content,nextFragment) .addToBackStack(null) .commit()
43.
結果を取得する override fun onActivityResult (requestCode:
Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == REQUEST_CODE){ // 連携結果を元に処理を実施する部分 if (resultCode == AppCompatActivity.RESULT_OK){ // 処理がOKのとき } } }
44.
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のとき } } } ・・・//省略 } ボタン押下
45.
結果を返却する(呼び出し先アプリ) targetFragment?.apply { val intent
= Intent() intent.putExtra(Intent.EXTRA_TEXT, "fragment") onActivityResult(targetRequestCode, RESULT_OK, intent) } requireActivity() .supportFragmentManager.run { popBackStack() }
46.
1. 次のFragmentを作る 2. 結果の取得先を登録する 3.
FragmentManagerに登録する これからのFragmentの連携処理
47.
次のFragmentを作る val nextFragment = NextFragment.newInstance("param_n_1","param_n_2")
48.
結果の取得先を登録する setFragmentResultListener(REQUEST_KEY) { key,
data → // 結果の受信処理 if (key == REQUEST_KEY){ } }
49.
FragmentManagerに登録する requireActivity() .supportFragmentManager .beginTransaction() .replace(R.id.content,nextFragment) .addToBackStack(null) .commit()
50.
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() } } ・・・//省略 } ボタン押下
51.
結果を返却する(呼び出し先アプリ) val bundle =
Bundle().apply { putString(Intent.EXTRA_TEXT, "fragment") } requireActivity() .supportFragmentManager.run { setFragmentResult(REQUEST_KEY,bundle) popBackStack() }
52.
● FragmentManagerが結果の返却を管理する ● ライフサイクルに合わせてデータの返却をしてくれる ●
FragmentなのにonActivityResult()を利用する 必要がなくなった point
53.
まとめ
54.
● ActivityとFragmentのデータ連携は新しい方法 がきっとスタンダートになるだろうから、積極的に 使っていくと良さそう。 ● まだ検索するとこれまでの実装方法がたくさんでて くるから、古い方法も一応知っておこうと良いと思 う。 まとめ
55.
● https://developer.android.com/training /basics/intents/result ↑日本語ページは内容が古いのでご注意を😅 ● https://developer.android.com/training/basics/fragme nts/pass-data-between 参考URL
56.
“引き続き GDG DevFest
2020をお 楽しみください🎉”
Download