Jetpack(二)LiveData

二、LiveData

1. 作用

• LiveData 一个可观测的数据持有类
• 数据可以被观察者订阅
• 能够感知组件(Fragment、Activity、Service)的生命周期
• 只有在组件出于激活状态才会通知观察者有数据更新

2.优势

• 确保UI和数据状态匹配
当数据发生改变的时候,会自动通知UI进行更新
• 避免内存泄漏
Observers 绑定到 Lifecycle 对象上,当与其关联的 lifecycle 被销毁的时候,它们会自动被清理
• 避免了由于 Activity 停止而导致的闪退
Observer 绑定的 Lifecycle 处于非活跃状态时,不会收到任何 LiveData 事件
• 不再需要手动处理生命周期
LiveData 具有生命周期感知能力,它会自动对这些进行管理
• 数据总处于最新状态
Lifecycle 由非活跃状态变为活跃状态时,它将收到最新的数据
• 系统配置更改时,进行数据的保存和恢复,及 UI 的恢复
配合 ViewModel 可以规避旋转屏幕等问题
• 资源共享
可以使用单例模式来扩展 LiveData,这样能达到数据变化的时候,通知所有的观察者

3. 使用
3.1. 创建 LiveData

• 创建 LiveData 实例,让其持有特定的数据类型
• 通常是将 LiveData 放在 ViewModel 中使用

// 1.创建 LiveData
private val currentName: MutableLiveData by lazy {
    MutableLiveData()
}
3.2. 创建 Observe

• 创建 Observer 对象,并实现 onChanged() ,在此定义 LiveData 持有的数据改变时做何操作
• 可在此更新 UI ,一般 Observer 在 UI controller 中创建,比如 Activity 或者 Fragment

// 2.创建 Observe
val nameObserver = Observer { newName ->
    binding.data = newName
}
3.3. Observer 添加到 LiveData

observe(LifecycleOwner owner, Observer observer)
• owner : LifecycleOwner对象,LiveData 能监听生命周期的能力来源
• observer : 监听器对象 Observer

// 3.Observer 添加到 LiveData
currentName.observe(this@MainActivity, nameObserver)
3.4. 改变 LiveData 值

• 在UI线程通过 value 改变 LiveData 值
• 在子线程通过 postValue() 修改 LiveData 值

// 点击时改变 LiveData 值
binding.button.setOnClickListener {
    // 4.UI 线程通过 value 修改 LiveData 值
    currentName.value = "2234"
}
// 点击时改变 LiveData 值
binding.button.setOnClickListener {
    Thread {
        var num = 0
        while (num < 5) {
            try {
                Thread.sleep(1000)
            } catch (e: InterruptedException) {
                e.printStackTrace()
            }
            // 4.子线程通过 postValue() 修改 LiveData 值
            currentName.postValue((++num).toString())
        }
    }.start()
}
4. 其他
4.1. 扩展 LiveData

• 如需观察者处于 active 状态时做操作,可通过继承 LiveData 或者 MutableLiveData后复写onActive()onInactive()

class StockLiveData(symbol: String) : LiveData() {

    private val stockManager = StockManager(symbol)

    // setValue(T) 方法将更新 LiveData 实例的值,并将更改通知给任何活跃观察者。
    private val listener = { price: BigDecimal ->
        value = price
    }

    // 当 LiveData 对象具有活跃观察者时,会调用 onActive() 方法。
    // 这意味着,您需要从此方法开始观察股价更新。
    override fun onActive() {
        stockManager.requestPriceUpdates(listener)
    }

    // 当 LiveData 对象没有任何活跃观察者时,会调用 onInactive() 方法。
    // 由于没有观察者在监听,因此没有理由与 StockManager 服务保持连接。
    override fun onInactive() {
        stockManager.removeUpdates(listener)
    }
}
4.2.转换 LiveData
  1. Transformations.map()
    • 可以通过Transformationsmap 操作符 修改数据
    • 可以将数据转换为其他类型

    // ====== Transformations.map 处理 类型转换 ======
    Transformations.map(currentName) {
        Function { input -> "修改$input" }
    }.observe(this@MainActivity, { newName ->
        binding.data = newName.toString()
    })
    
    // ====== Transformations.map 处理 类型转换 (lambda简化后) ======
    Transformations.map(currentName) { input -> "修改$input" }.observe(this, { newName ->
        binding.data = newName
    })
    
  2. Transformations.switchMap()

    • 可以通过TransformationsswitchMap() 操作符 通过room 做数据查询等

    // ====== Transformations.map 处理 类型转换 ======
    val userLiveData = Transformations.switchMap(currentName, object : Function> {
        override fun apply(input: String?): LiveData {
            // 根据 userId 返回一个 LiveData,可通过 room 获取
            return dao.getUser()
        }
    })
    // ====== Transformations.map 处理 类型转换 (lambda简化后)  ======
    val userLiveDataL = Transformations.switchMap(currentName, Function> {
        // 根据 userId 返回一个 LiveData,可通过 room 获取
        dao.getUser()
    })
    
  3. 自定义CustomTransformations
    • 如有更复杂需求可通过 MediatorLiveData 自定义 transformations
    Transformations 源码就是通过 MediatorLiveData 实现二次转发
    • 里面其实主要用的就是MediatorLiveData,通过该类能组合多个LiveData源。当任何一个LiveData源发生改变的时候,MediatorLiveDataObservers 都会被触发。比如有两个LiveData,一个是从数据库获取,一个是从网络获取。通过MediatorLiveData就能做到,当二者任何一个获取到最新数据,就去触发监听。

    public class Transformations {
    
        private Transformations() {
        }
    
        @MainThread
        @NonNull
        public static  LiveData map(
                @NonNull LiveData source,
                @NonNull final Function mapFunction) {
            final MediatorLiveData result = new MediatorLiveData<>();
            result.addSource(source, new Observer() {
                @Override
                public void onChanged(@Nullable X x) {
                    result.setValue(mapFunction.apply(x));
                }
            });
            return result;
        }
    
        @MainThread
        @NonNull
        public static  LiveData switchMap(
                @NonNull LiveData source,
                @NonNull final Function> switchMapFunction) {
            final MediatorLiveData result = new MediatorLiveData<>();
            result.addSource(source, new Observer() {
                LiveData mSource;
    
                @Override
                public void onChanged(@Nullable X x) {
                    LiveData newLiveData = switchMapFunction.apply(x);
                    if (mSource == newLiveData) {
                        return;
                    }
                    if (mSource != null) {
                        result.removeSource(mSource);
                    }
                    mSource = newLiveData;
                    if (mSource != null) {
                        result.addSource(mSource, new Observer() {
                            @Override
                            public void onChanged(@Nullable Y y) {
                                result.setValue(y);
                            }
                        });
                    }
                }
            });
            return result;
        }
    
        @MainThread
        @NonNull
        public static  LiveData distinctUntilChanged(@NonNull LiveData source) {
            final MediatorLiveData outputLiveData = new MediatorLiveData<>();
            outputLiveData.addSource(source, new Observer() {
    
                boolean mFirstTime = true;
    
                @Override
                public void onChanged(X currentValue) {
                    final X previousValue = outputLiveData.getValue();
                    if (mFirstTime
                            || (previousValue == null && currentValue != null)
                            || (previousValue != null && !previousValue.equals(currentValue))) {
                        mFirstTime = false;
                        outputLiveData.setValue(currentValue);
                    }
                }
            });
            return outputLiveData;
        }
    }
    

Demo地址 : LiveData[module]

2020年9月2日

你可能感兴趣的:(Jetpack(二)LiveData)