みなさまこんにちは〜!
メモリアインクのすだです。
本日は、
KotlinでBundle、ViewModelを使用した
画面遷移時のデータの受け渡しについて コードを交えて解説していきます!
この記事を読んでわかること…
・Bundleを使用したデータの受け渡し
・ViewModelを使用したデータデータの受け渡し
環境
- Kotlin (ver 1.9.0)
- Android Studio (Giraffe | 2022.3.1 Patch 3)
Bundleを使用したデータの受け渡し
Bundleとは?
BundleはAndroid SDKの一部であり、キーと値のペアの集まりを保持することができるクラスです。
「データを入れる箱」と考えるとイメージしやすいでしょう。
この箱を使って、アプリの異なる部分間でデータを運ぶことができます。
ここでいう「キー」とは文字列型の識別子であり、
「値」とは保存したいデータ(文字列、整数、真偽値、オブジェクトなど)を指します。
Bundleの使い方
- キーとバリューのペア
Bundleを使用する際には、まずデータを「キーとバリューのペア」としてBundleに追加します。
このキーは、後でデータを取り出す際の識別子として機能します。
例えば、ユーザー名を保存する場合、キーとして”user_name”、バリューとして実際のユーザー名を使用します。 - データの取り出し
データを受け取る側では、Bundleから先ほどセットしたキーを使ってデータを取り出します。
このプロセスにより、正確に必要なデータを簡単に取得できます。 - 一方向のデータ交換に向いている
Bundleで渡されるデータは基本的に読み取り専用で、受け取ったデータを変更することは想定されていません。
そのため、データを受け渡したいだけで、その後で受け取ったデータを書き換える必要がない場合に最適な方法です。
コード例
では早速、実装を行なっていきましょう〜!
① ActivityからActivityへ
新しいActivityを開始する際に、IntentにBundleを添付してデータを受け渡します。
Activity 1(データ送信側)
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val intent = Intent(this, SecondActivity::class.java)
val bundle = Bundle()
bundle.putString("key", "value")
intent.putExtras(bundle)
startActivity(intent)
}
}
解説
val bundle = Bundle()
bundle.putString(“key”, “value”)
Bundleオブジェクトを作成し、ドット繋ぎの記法でデータを追加します。putString
は文字列のデータを追加する際に使用されるものですが、
他にも、putInt
(整数)、putBoolean
(真偽値)などなど
データ方に合わせて様々なメソッドが用意されています。
intent.putExtras(data)
そして、putExtras
メソッドを使用して IntentにBundle(データを入れる箱)を添付しています。
Activity 2(データ受け取り側)
class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
val bundle = intent.extras
val value = bundle?.getString("key", "デフォルト値")
}
}
解説
val bundle = intent.extras
2つめのActivityが開始された際に、前のActivityから送られてきた追加のデータ(extras)を取得しています。extras
プロパティ(オブジェクトの状態を保持できる箱)によってこのBundle
にアクセスして、
そこに含まれるデータを取り出す という仕組み。
bundle?.getString(“key”, “デフォルト値”)
ここで、取得したBundle
から特定のデータを取り出しています。
キー(この例では "key"
)に対応する値を「文字列として」取得するというものです。
② Activity(Fragment)からFragmentへ
この場合は、Fragmentを生成する際に、setArguments()メソッドを使用してデータをセットします。
Activity 1(データ送信側)
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_my)
val bundle = Bundle()
bundle.putString("key", "value")
val subFragment = SubFragment()
subFragment.setArguments(bundle)
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, subFragment)
.commit()
}
}
解説
val subFragment = SubFragment()
subFragment.setArguments(bundle)
新しいFragmentインスタンスを生成し、
setArguments()メソッドを使用してBundleをセットしています。
Fragment 1(データ受け取り側)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val data = arguments?.getString("key", "デフォルト値")
}
解説
arguments?.getString(“key”, “デフォルト値”)
arguments
というプロパティを使って、
FragmentにセットされたBundleオブジェクトを参照することができます。
画面遷移のパターンによって、少し書き方が変わってきますね!
慣れるとすぐに認識できるようになるはずです!
ViewModelを使用したデータの受け渡し
ViewModelとは?
ViewModelは、UIのデータを管理するためのコンポーネントです。
たとえば、画面に行って戻ってきたりすると、画面に表示されている情報が消えてしまうことがあります。
これは、「アプリが新しく画面を作り直すから」です。
ここでViewModelを使用することによって画面の情報を「忘れずに保持」しておくことができます。
これにより、データの再読み込みや再計算を防ぎ、アプリのパフォーマンスを向上させることができるのです。
ViewModelの使い方
- ライフサイクルをほとんど考えなくて良い
アプリ画面の状態がどう変わろうと、ViewModelはデータを保持し続けてくれるという特性があります。
アプリを完全に閉じたり、スマホのタスクリストからアプリを消したりすると、onCleared
メソッドが呼ばれデータが消し去られます。 - データの橋渡しのようなイメージ
ViewModelはアプリのUI(ユーザーインターフェース)とデータの間で橋渡しをする役割を果たします。
UIの入力を受けてデータを更新したり、データの変更をUIに反映させたりするシーンで使われることが多いです。 - Activity間の画面遷移では使わない
ViewModelは特定のActivity(またはFragment)に「紐付け」られています。
つまり、ViewModelはそのActivityが持っているデータや状態を管理するためのものであり、
Activityが破棄されるとViewModelもその役目を終えます。
複数のFragmentが同じActivityに紐づいている場合、
Fragment間でViewModelを共有でき、ViewModelを用いて画面遷移時のデータの共有を実現できるのです。
コード例
では早速実装してみましょう!
Fragment1で入力された文字列を、ボタン押下時にFragment2へ送信します。
2つのFragmentのほかに、共有するデータを保持するViewModelを定義します。
SharedViewModel.kt
class SharedViewModel : ViewModel() {
val message = MutableLiveData<String>()
}
解説
ただのLiveDataは変更不可ですが、MutableLiveData
は、値が変更可能なLiveDataです。
LiveDataとは、データの値を保持し、その値の変更を監視することができる箱です。
UIの部品は、LiveDataに格納されているデータの変更を監視し、
データが変更されると自動的に更新されます。
(例えば、天気予報が晴れから雨に変わったとき、アプリの画面に「中身変わったよ〜」と教えてくれる
みたいなイメージですね!)
Fragment 1 (データ送信側)
class FirstFragment : Fragment() {
private val sharedViewModel: SharedViewModel by activityViewModels()
override fun onCreateView(){
// 省略
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
sendButton.setOnClickListener {
val inputMessage = messageEditText.text.toString()
sharedViewModel.input_message.value = inputMessage
}
}
}
解説
sharedViewModel.message.value = inputMessage
ユーザーが入力したメッセージを共有ViewModelに設定します。
ここではデータにinput_message
という名前をつけて、value値にセットしています。
Fragment 2 (データ受け取り側)
class SecondFragment : Fragment() {
private val sharedViewModel: SharedViewModel by activityViewModels()
override fun onCreateView() {
// 省略
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
sharedViewModel.input_message.observe(viewLifecycleOwner, Observer { message ->
messageTextView.text = message
})
}
}
解説
sharedViewModel.input_message
先ほどViewModelにセットしたデータにアクセスしています。
.observe(viewLifecycleOwner, Observer { message ->
messageTextView.text = message
})
observe
メソッドは、データの監視を開始するためのもの。
共有されているデータに設定や変更があったときに、
何かアクション(この例ではテキストビューの更新)を行うように設定しています。viewLifecycleOwner
は、このフラグメントのビューのライフサイクルを監視するオブジェクト。
これにより、フラグメントの画面が表示されている間だけデータの変更を監視し、
画面がなくなれば自動的に監視を停止します。
これは、無駄な処理を避け、アプリのパフォーマンスを保つために重要です。Observer { ... }
は、データに変更があったときに実行されるアクションを定義します。
この部分で「変更があったら、この処理をしてね」とアプリに教えています。
最終的に、messageTextView
という名前のテキストビューにデータを表示しています。
Bundleとは考え方が大きく異なりますね!
あまり複雑でないデータの共有には、ViewModelを使うのもよさそうですね〜!
まとめ
いかがでしたでしょうか〜!
データの受け渡しは、開発を進めていく中で必ず実装するシーンがあるかと思いますので
ぜひ使い方をマスターしてください!
技術者としてのキャリアパスを次のレベルへと進めたい皆様、
未経験からIT・Webエンジニアを目指すなら【ユニゾンキャリア】
自分の市場価値をさらに向上させてみませんか?
それではまた次の記事でお会いしましょう!
コメント