《Android编程权威指南》之数据绑定与MVVM(二)

《Android编程权威指南》第 19 章第二篇,补充完 BeatBox 应用啦。

第一篇地址:

https://juejin.cn/post/7032485144078319653

六、导入 assets

创建 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 中创建 BeatBox 实例,并调用 loadSounds() 函数。

        beatBox = BeatBox(assets)
        beatBox.loadSounds()

运行结果如下,可以看到已经读到 assets 里的文件。

assets

七、使用 assets

  • 创建 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() 中创建 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)

运行结果:

使用assets

八、绑定数据

  • 创建 SoundViewModel 类并添加绑定函数。
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>
  • 关联使用视图模型
    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)
        }
  • 绑定数据观察
class SoundViewModel : BaseObservable() {

    var sound: Sound? = null
        set(sound) {
            field = sound
            notifyChange()
        }

    @get:Bindable
    val title: String?
        get() = sound?.name
}

调用 notifyChange(),就是通知绑定类,视图模型对象上所有可绑定属性都已更新。

运行结果:

demo

九、深入学习:数据绑定再探

有关数据绑定(DataBinding)库更加深入的介绍请参考:

https://developer.android.com/topic/libraries/data-binding

lambda 表达式「布局里面也可以使用 lambda 表达式写短回调」

比如给 item 中的 button 添加点击时间可以写成:

 android:onClick="@{() -> viewModel.onButtonClick()}"

数据绑定还有一些方便的语法可用。最方便的一个是使用单引号代替双引号,它还有 null 自动处理机制。

数据绑定默认会把绑定表达式解读为属性函数调用。

比如要定义一个 app:isGone 属性,基于某个布尔值来设置所有 View 的可见性,可以这么做:

@BindingAdapter("app:isGone")
fun bindIsGone(view: View, isGone: Boolean) {
    view.visibility = if (isGone) View.GONE else View.VISIBLE
}

TextViewBindingAdapter 就为 TextView 提供了一些特别的属性操作。你可以在Android Studio 里看看它们的源码。当然也有搜到 AutoCompleteTextViewBindingAdapter、CheckedTextViewBindingAdapter 这些类,可自行查查看看。

十、深入学习:LiveData和数据绑定

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容