《Android編程權(quán)威指南》第 19 章第二篇驾诈,補充完 BeatBox 應(yīng)用啦徽职。
第一篇地址:
https://juejin.cn/post/7032485144078319653
六谅阿、導(dǎo)入 assets
創(chuàng)建 BeatBox 類郑藏,AssetManager 類可以訪問 assets渗柿。
class BeatBox(private val assets: AssetManager) {
fun loadSounds(): List<String> {
try {
val soundNames = assets.list(SOUNDS_FOLDER)!!
Log.d(TAG, "Found ${soundNames.size} sounds")
return soundNames.asList()
} catch (e: Exception) {
e.printStackTrace()
Log.e(TAG, "Could not list assets", e)
return emptyList()
}
}
}
AssetManager.list(String) 能列出指定目錄下的所有文件名堵第,傳入聲音資源所在的目錄兆旬,就能看到其中的所有.wav文件假抄。
在 MainActivity 中創(chuàng)建 BeatBox 實例,并調(diào)用 loadSounds() 函數(shù)爵憎。
beatBox = BeatBox(assets)
beatBox.loadSounds()
運行結(jié)果如下慨亲,可以看到已經(jīng)讀到 assets 里的文件。
七宝鼓、使用 assets
- 創(chuàng)建 Sound 管理類刑棵,使用 String.split(String).last() 分離出文件名,再使用 String.removeSuffix(String) 刪除.wav后綴愚铡。
private const val WAV = ".wav"
class Sound(val assetPath: String) {
val name = assetPath.split("/").last().removeSuffix(WAV)
}
- 在 BeatBox.loadSounds() 中創(chuàng)建 Sound 對象集合蛉签。
class BeatBox(private val assets: AssetManager) {
private val sounds: List<Sound>
init {
sounds = loadSounds()
}
fun loadSounds(): List<Sound> {
val soundNames: Array<String>
try {
soundNames = assets.list(SOUNDS_FOLDER)!!
} catch (e: Exception) {
e.printStackTrace()
Log.e(TAG, "Could not list assets", e)
return emptyList()
}
val sounds = mutableListOf<Sound>()
soundNames.forEach { fileName ->
val assetPath = "$SOUNDS_FOLDER/$fileName"
val sound = Sound(assetPath)
sounds.add(sound)
}
return sounds
}
}
- 綁定 Sound 對象集合
private inner class SoundAdapter(private val sounds:List<Sound>):RecyclerView.Adapter<SoundHolder>(){
...
override fun getItemCount() = sounds.size
}
- 傳入聲音資源(MainActivity.kt)
adapter = SoundAdapter(beatBox.sounds)
運行結(jié)果:
八、綁定數(shù)據(jù)
- 創(chuàng)建 SoundViewModel 類并添加綁定函數(shù)沥寥。
class SoundViewModel {
var sound: Sound? = null
set(sound) {
field = sound
}
val title: String?
get() = sound?.name
}
- 綁定至視圖模型
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.pyn.beatbox.SoundViewModel" />
</data>
<Button
android:layout_width="match_parent"
android:layout_height="120dp"
android:text="@{viewModel.title}"
tools:text="Sound name" />
</layout>
- 關(guān)聯(lián)使用視圖模型
private inner class SoundHolder(private val binding:ListItemSoundBinding):RecyclerView.ViewHolder(binding.root){
init {
binding.viewModel = SoundViewModel()
}
fun bind(sound:Sound){
binding.apply {
viewModel?.sound = sound
executePendingBindings()
}
}
}
...
override fun onBindViewHolder(holder: SoundHolder, position: Int) {
val sound = sounds[position]
holder.bind(sound)
}
- 綁定數(shù)據(jù)觀察
class SoundViewModel : BaseObservable() {
var sound: Sound? = null
set(sound) {
field = sound
notifyChange()
}
@get:Bindable
val title: String?
get() = sound?.name
}
調(diào)用 notifyChange()碍舍,就是通知綁定類,視圖模型對象上所有可綁定屬性都已更新邑雅。
運行結(jié)果:
九片橡、深入學(xué)習(xí):數(shù)據(jù)綁定再探
有關(guān)數(shù)據(jù)綁定(DataBinding)庫更加深入的介紹請參考:
https://developer.android.com/topic/libraries/data-binding
lambda 表達式「布局里面也可以使用 lambda 表達式寫短回調(diào)」
比如給 item 中的 button 添加點擊時間可以寫成:
android:onClick="@{() -> viewModel.onButtonClick()}"
數(shù)據(jù)綁定還有一些方便的語法可用。最方便的一個是使用單引號代替雙引號淮野,它還有 null 自動處理機制捧书。
數(shù)據(jù)綁定默認(rèn)會把綁定表達式解讀為屬性函數(shù)調(diào)用。
比如要定義一個 app:isGone 屬性骤星,基于某個布爾值來設(shè)置所有 View 的可見性经瓷,可以這么做:
@BindingAdapter("app:isGone")
fun bindIsGone(view: View, isGone: Boolean) {
view.visibility = if (isGone) View.GONE else View.VISIBLE
}
TextViewBindingAdapter 就為 TextView 提供了一些特別的屬性操作。你可以在Android Studio 里看看它們的源碼洞难。當(dāng)然也有搜到 AutoCompleteTextViewBindingAdapter舆吮、CheckedTextViewBindingAdapter 這些類,可自行查查看看队贱。
十色冀、深入學(xué)習(xí):LiveData和數(shù)據(jù)綁定
class SoundViewModel{
val title :MutableLiveData<String?> = MutableLiveData()
var sound: Sound? = null
set(sound) {
field = sound
title.postValue(sound?.name)
}
}
private inner class SoundAdapter(private val sounds:List<Sound>):RecyclerView.Adapter<SoundHolder>(){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
SoundHolder{
...
binding.lifecycleOwner = this@MainActivity
return SoundHolder(binding)
}
...
}
其他
BeatBox 項目 Demo 地址:
https://github.com/visiongem/AndroidGuideApp/tree/master/BeatBox