SimpleAdapter
参考1: 研修2日目
参考2: SimpleAdapter
MutableList<MutableMap<String, *>>型のデータ構造をとるAdapterクラス。
MutableList
「キーと値をもち、要素数が可変」なMutableMap<String, *>型のデータを、各インデックスに格納したリスト。
SimpleAdapterの生成
定義
SimpleAdapter(
context: Context!,
data: MutableList<out MutableMap<String!, *>!>!,
resource: Int
from: Array<String>!
to: IntArray!
)
// パラメータ
// context: コンテキストとなるアクティビティオブジェクト
// data: リスト形式ビューに反映するリストデータ
// resource: リスト形式ビューの各Itemのレイアウトを表現するR値
// from: MutableMapのキーのみを格納した配列
// to: Item内の複数のビュー(=TextView)を識別するR値(=ID)を格納した配列
// -> toで指定したビュー(=TextView)に対して、
// fromで指定したキーに対応する値を格納
値を加工して表示するListView
// 発展: 値を加工したListViewの生成
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
...
val nameList = createNameList()
val from = arrayOf("name", "sex")
val to = intArrayOf(R.id.tvName, R.id.imSex)
// Adapterオブジェクトの生成
val adapter = SimpleAdapter(
applicationContext,
nameList,
R.layout.row,
from,
to
)
// AdapterにViewBinderオブジェクトをセット
adapter.viewBinder = CustomViewBinder()
// リストデータを紐づけるListViewの定義
val lvPhones = findViewById<ListView>(R.id.lvNameList)
// ListViewにAdapterオブジェクトをセット
lvPhones.adapter = adapter
}
// 加工するリストデータを生成するメソッド
private fun createNameList(): MutableList<MutableMap<String, Any>> {
// 加工するリストデータを記述
... // 最終的に"return <リストデータ>"を記述
}
// MutableMapの値を基にデータを加工するクラス
private inner class CustomViewBinder: SimpleAdapter.ViewBinder {
// MutableMapの値を基にデータを加工
// -> ListView生成時に自動的に実行される
override fun setViewValue(
view: View,
data: Any,
textRepresentation: String
): Boolean {
// データの加工処理
... // 最終的に"return true/false"を記述
// true: データのバインドが実行された場合
// false: データのバインドが実行されなかった場合
}
}
}
画面の追加
参考: 研修1日目
アプリに表示される文字列を除き、アプリの1画面を構成しているのは、以下の3つ。
- アプリ内処理を担う、
app/javaフォルダのアクティビティクラス(=.ktファイル)- 画面構成を担う、
app/res/layoutフォルダのレイアウトファイル(=.xmlファイル)- 1.および2.を認識する、
app/manifestsフォルダのAndroidManifest.xmlファイル
画面を追加する場合は、AndroidManifest.xmlファイルにactivityタグを記述する必要がある。
※Android Studioは、New Activityの作成時に、アクティビティの追加にあたって必要な処理を自動的に行う。
Androidにおける画面遷移
遷移先の画面は、遷移元の画面の前面に表示される。
遷移先から戻る場合は、遷移先の画面が消滅し、背面に隠れていた遷移元の画面が表示される挙動をとる。
インテント(Intent)
参考: インテント
参考2: インテントのクラスメソッド
画面遷移にあたり、画面(=アクティビティ)を起動するクラス。
遷移元アクティビティと遷移先アクティビティの橋渡し役を担う。
Intentクラスのインスタンス化(実体化)
定義
Intent(packageContext: Context!, cls: Class<*>!)
// パラメータ
// packageContext: 遷移元のアクティビティオブジェクト(=コンテキスト)
// cls: Javaクラス化した遷移先アクティビティ
// -> KotlinのクラスをJavaに変換する場合は、"<Kotlinクラス名>::class.java"と記述
Intentオブジェクトへのデータの格納
インテントを通じてデータをやり取りする場合、Extraデータ(=追加情報)をIntentオブジェクトに追加する。
定義
putExtra(name: String!, value: String?): Intent
// パラメータ
// name: 格納するデータの名称
// value: 格納するデータ
遷移先アクティビティの起動(画面遷移)
定義
Activity.startActivity(intent: Intent!): Unit
// パラメータ
// intent: 画面遷移を実現するIntentオブジェクト
サンプルコード
class MainActivity: AppCompatActivity() {
...
// リスナクラス
private inner class ListItemClickListener: AdapterView.OnItemClickListener {
// "タップ"イベント検知時の処理(イベントハンドラ)
override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
// "タップ"されたItemの定義
// parent: AdapterView
// getItemAtPosition(): 指定したIndex(position)のtext値を取得(返り値はAny型)
val item = parent?.getItemAtPosition(position) as MutableMap<String, String>
// 指定したキーの値
val menuName = item["name"]
val menuPrice = item["price"]
// 画面遷移を実現するIntentオブジェクトの生成
// Intent(packageContext:cls:): Intentオブジェクトの生成
// packageContext: 遷移元のアクティビティオブジェクト(=コンテキスト)
// cls: Javaクラス化した遷移先アクティビティ
val intent2MenuThanks = Intent(
this@MainActivity,
MenuThanksActivity::class.java
)
// Intentオブジェクトへのデータの格納
// putExtra(name:value:): Intentオブジェクトにデータを格納
// name: 格納するデータの名称
// value: 格納するデータ
intent2MenuThanks.putExtra("menuName", menuName)
intent2MenuThanks.putExtra("menuPrice", menuPrice)
// 遷移先アクティビティの起動
// Context.startActivity(intent:): Intentオブジェクトによる画面遷移の実行
// intent: Intentオブジェクト
startActivity(intent2MenuThanks)
}
}
}
apply関数を用いたIntentオブジェクトの生成・定義
// 発展: apply関数の使用
// 本来はこっち
// 画面遷移を実現するIntentオブジェクトの生成
val intent2MenuThanks = Intent(
this@MainActivity,
MenuTahnksActivity::class.java
)
// Intentオブジェクトへのデータの格納
intent2MenuThanks.putExtra("menuName", menuName)
intent2MenuThanks.putExtra("menuPrice", menuPrice)
// apply関数(スコープ関数)を用いる場合
// -> applyブロック{...}内では、インスタンス変数(intent2MenuThanks)の記述が不要
val intent2MenuThanks = Intent(
this@MainActivity,
MenuTahnksActivity::class.java
).apply {
putExtra("menuName", menuName)
putExtra("menuPrice", menuPrice)
}
遷移先アクティビティの終了
定義
finish(): Unit
遷移先による遷移元の値取得
遷移元のデータはIntentオブジェクトが保持しているため、遷移先アクティビティでintentプロパティを用いてデータを取得する。
文字列(String)
定義
Intent.getStringExtra(name: String!): String?
// パラメータ
// name: Intentオブジェクト(=intentプロパティ)に格納されたデータの名称
数値(Int)
定義
Intent.getIntExtra(name: String!, defaultValue: Int): Int
// パラメータ
// name: Intentオブジェクト(=Activity.intent)に格納されたデータの名称
// defaultValue: 取得するデータの初期値
// <- 指定したnameのデータが存在しない場合のnullを避ける
サンプルコード
class MenuThanksActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
...
// Intentオブジェクトが保持するデータの取得
val menuName = intent.getStringExtra("menuName")
val menuPrice = intent.getStringExtra("menuPrice")
// 値を反映する遷移先ビューの定義
val tvMenuName = findViewById<TextView>(R.id.tvMenuName)
val tvMenuPrice = findViewById<TextView>(R.id.tvMenuPrice)
// 遷移先ビューの値(=TextView.text)の変更
tvMenuName.text = menuName
tvMenuPrice.text = menuPrice
}
}
レイアウトファイルによるリスナ定義
参考: タップイベントのイベント処理
イベントを検知するリスナを定義する方法は以下の2つ。
Activityファイルでリスナクラスを定義レイアウトファイルにandroid:onClick属性を追加し、その属性値と一致するイベントハンドラをActivityファイルに記述
※フラグメントでは実装不可
サンプルコード
<Button
...
android:onClick="onBackButtonClick" <!-- リスナ定義 -->
/>
class MenuThanksActivity: AppCompatActivity() {
...
// "タップ"イベント検知時の処理(イベントハンドラ)
// ※実装にあたって制約が存在(後述)
fun onBackButtonClick(view: View) {
...
}
}
制約
レイアウトファイルでリスナの定義を行う場合、イベントハンドラは以下の要件を満たす必要がある。
publicメソッドであること(Kotlinではpublicが規定値)返り値がない(=Unit型である)ことView型1つのみの引数をとること