Android Jetpack(6):LiveData

LiveData介绍

LiveData也是Google I/O 大会上发布的架构组件, LiveData 是一个可以被观察的数据持有类,它可以感知 Activity、Fragment或Service 等组件的生命周期。

  • LiveData是一个可被观察的数据持有者类,它可以通过添加观察者被其他组件观察其变更。
  • 不过它和其他的可观察对象不同,它会与生命周期相关联,比如Activity的生命周期,LiveData能确保仅在Activity处于活动状态下才会更新。也就是说当观察者处于活动状态,才会去通知数据更新。
  • 如在Activity中如果数据更新了但Activity已经是destroy状态,LivaeData就不会通知Activity(observer)。当然。LiveData的优点还有很多,如不会造成内存泄漏等。
  • LiveData通常会配合ViewModel来使用,ViewModel负责触发数据的更新,更新会通知到LiveData,然后LiveData再通知活跃状态的观察者。
  • LiveData可以避免内存泄漏,这个作用可以说是很实用了,因为要想避免内存泄漏,必须要感知到生命周期,而原本并没有提供额外的方法,像Glide采用了一个透明的Fragment来感知Activity的生命周期,这虽然是一个可行的方法,但总感觉并不是一个最优的方法。

简单地说,LiveData是一个数据持有类。它具有以下特点:

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

为什么要引进 LiveData

一,保证数据与界面的实时更新

LiveData采用了观察者模式设计,其中LiveData是被观察者,当数据发生变化时会通知观察者进行数据更新。通过这点,可以确保数据和界面的实时性。

二,有效避免内存泄漏

这是因为LiveData能够感知到组件的生命周期,它可以做到在组件处于激活状态的时候才会回调相应的方法,从而刷新相应的 UI,当组件状态处于destoryed状态时,观察者对象会被remove。

比如Activity的生命周期,LiveData能确保仅在Activity处于活动状态下(生命周期处于onStart与onResume时)才会更新,也就是说当观察者处于活动状态,才会去通知数据更新,当生命周期处于onStop或者onPause时,不回调数据更新,直至生命周期为onResume时,立即回调。

三,Activity/Fragment销毁掉时不会引起崩溃

这是因为组件处于非激活状态时,在界面不会收到来自LiveData的数据变化通知。这样规避了很多因为页面销毁之后,修改UI导致的crash。

四,不需要手动处理生命周期

LiveData能够感知组件的生命周期,所以就完全不需要在代码中告诉LiveData组件的生命周期状态。

五,始终能够保持最新数据

生命周期从非活跃状态切换到活跃状态的时候,能够实时的接收最新的数据。

组件在前台的时候能够实时收到数据改变的通知,这是可以理解的。当组件从后台到前台来时,LiveData能够将最新的数据通知组件,这两点就保证了组件中和数据相关的内容能够实时更新。

六,能够应对配置更改

我们知道,当你把数据存储在组件中时,当configuration change(比如语言、屏幕方向变化)时,组件会被recreate,然而系统并不能保证你的数据能够被恢复的。当我们采用LiveData保存数据时,因为数据和组件分离了。当组件被recreate,数据还是存在LiveData中,并不会被销毁。

由于LiveData保存数据的时候,组件和数据是分离的,所以在配置更改(如横竖屏切换等)的时候,即便组件被重新创建,因为数据还保存在LiveData中,这样也能够做到实时的更新。比如 config 导致activity 重新创建的时候,不需要手动取处理数据的储存和恢复,它已经帮我们封装好了。

七,资源共享

通过继承LiveData类,然后将该类定义成单例模式,在该类封装监听一些系统属性变化,然后通知LiveData的观察者。

单例模式扩展LiveData对象并包装成系统服务,以便在应用程序中进行共享,需要该资源的只需要观察LiveData即可。

LveData在MVVM中的角色

2018年 google的AAC(Android Architecture Components)。一套组合的Jetpack组件库,使得ViewModel具有生命周期感知能力,同时也有了数据的感知能力(LiveData)
在这里插入图片描述

理解LiveData图

在这里插入图片描述
不同于rxjava的观察模式,这里仅通知处于active状态的观察者。

一旦观察者回复Resume状态,就会收到最新的数据(有利有弊,特殊场景)。

LiveData的使用

Android开发中 MVX的开发架构设计,生命周期的感知对于Controller/Presenter/ViewModel不是天然可知。

回想一下,在你的项目中,是不是经常会碰到这样的问题,当网络请求结果回来的时候,你经常需要判断 Activity 或者 Fragment 是否已经 Destroy, 如果不是 destroy,才更新 UI。而当你如果使用 Livedata 的话,因为它是在 Activity 处于 onStart 或者 onResume 的状态时,他才会进行相应的回调,因而可以很好得处理这个问题,不必谢一大堆的 activity.isDestroyed()。接下来,让我们一起来看一下 LiveData 的使用。

LiveData几种使用方式

  • 直接使用LiveData对象
  • 继承LiveData类

LiveData依赖

目前Jetpack组件已经包含在AndroidX中,AndroidX是Jetpack的包含的支持库的具体位置,所以如果项目以及迁移到了AndroidX了,就不需要额外导包。如果没有兼容AndroidX 那么需要在gradle中进行配置。

ViewModel 的依赖,可以查看官方文档,导入最新的版本。

官网地址

java

	   def lifecycle_version = "2.2.0"
        def arch_version = "2.1.0"

        // ViewModel
        implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
        // LiveData
        implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"

kotlin

    def lifecycle_version = "2.2.0"
    def arch_version = "2.1.0"

    // ViewModel
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
    // LiveData
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"


LiveData使用方式1:直接使用LiveData对象

通常使用LiveData有4个步骤:

  1. 创建LiveData实例来保存数据,常常是配合ViewModel一起工作;
  2. 定义一个Observer的观察者对象,如果有数据更新会通过观察者的onChanged()方法来同步到UI上面;
  3. 将观察者Observer通过observe()方法进行绑定。
  4. 更新Livedata对象存储的数据;

LiveData 是一个抽象类,它的实现子类有 MutableLiveData ,MediatorLiveData。在实际使用中,用得比较多的是 MutableLiveData。他常常结合 ViewModel 一起使用。

创建LiveData实例

Android文档中建议LiveData配合ViewModel使用更加哦,其实呢,你也可以不使用ViewModel,但是一定要做到LiveData中保存的数据和组件分离。

首先,我们先写一个类继承我们的 ViewModel:

class MainViewModel() : ViewModel() {

    private var liveData = MutableLiveData<String>()

    var i = 0

    fun getLiveData(): MutableLiveData<String> {
        return liveData
    }
}

创建Observer对象,作为参数传入LiveData.observe()方法添加观察者

我们在 Activity 中创建 ViewModel,并监听 ViewModel 里面 数据的变化,当数据改变的时候,我们 设置给 textView,显示在界面上。这样我们就完成了对 数据源的观察。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //setContentView(R.layout.activity_main)

        val binding =
            DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)

        //过时 2.2.0-alpha02 以前的版本是通过下面的方式,新版本已弃用。
        //val mainViewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
        val mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)

        //创建一个观察者来观察数据的变化
        val observer: Observer<String> = object : Observer<String> {
            override fun onChanged(t: String?) {
                binding.textView.text = t
            }
        }

        //订阅
        mainViewModel.getLiveData().observe(this, observer)

        //点击按钮更新数据
        binding.btn.setOnClickListener {
            mainViewModel.getLiveData().value = "hello ${mainViewModel.i++}"
        }
    }
}

最后当我们数据源改变的时候,我们需要调用 livedata 的 setValue 或者 postvalue 方法。他们之间的区别是, 调用 setValue 方法,Observer 的 onChanged 方法会在调用 serValue 方法的线程回调,而postvalue 方法,Observer 的 onChanged 方法将会在主线程回调。

LiveData有2个方法通知数据改变

setValue(value):同步,接收端数据回调与发送端同一个线程
postValue(value):异步,接收端在主线程回调数据

注意:

获取mainViewModel方式,代码中只有一个this参数,需要加入依赖lifecycle-extensions。

val mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'

LiveData使用方式2:自定义类继承LiveData类

除了直接使用LiveDatad对象外,我们还可以通过集成LiveData类来定义适合特定需求的LiveData。

Livedata 主要有几个方法

void observe (LifecycleOwner owner, Observer observer)  

在给定所有者的生命周期内将给定观察者添加到观察者列表中
void onActive () 

此方法是当处于激活状态的observer个数从01时,该方法会被调用。
当 LiveData 对象具有活跃观察者时,会调用 onActive() 方法。这意味着,您需要从此方法开始观察数据更新。
void onInactive ()  

此方法是当处于激活状态的observer个数从1变为0时,该方法会被调用。
当 LiveData 对象没有任何活跃观察者时,会调用 onInactive() 方法。

observeForever:

  • 跟 observe 方法不太一样的是,它在 Activity 处于 onPause ,onStop, onDestroy的时候,都可以回调 obsever 的 onChange 方法,但是有一点需要注意的是,我们必须手动 remove obsever,否则会发生内存泄漏。
  • 当 Actiivty 不是处于激活状态的时候,如果你想 livedata setValue 之后立即回调 obsever的onChange 方法,而不是等到 Activity 处于激活状态的时候才回调 obsever 的 onChange 方法,你可以使用observeForever 方法,但是你必须在 onDestroy 的时候 remove Observer。

自定义 Livedata观察网络状态变化

首先我们自定义一个 Class NetworkLiveData,继承 LiveData,重写它的 onActive 方法和 onInactive 方法

在 onActive 方法中,我们注册监听网络变化的广播,即ConnectivityManager.CONNECTIVITY_ACTION。在 onInactive 方法的时候,我们注销广播。

public class NetworkLiveData extends LiveData<NetworkInfo> {

    private final Context mContext;
    static NetworkLiveData mNetworkLiveData;
    private NetworkReceiver mNetworkReceiver;
    private final IntentFilter mIntentFilter;

    private static final String TAG = "NetworkLiveData";

    public NetworkLiveData(Context context) {
        mContext = context.getApplicationContext();
        mNetworkReceiver = new NetworkReceiver();
        mIntentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
    }

    public static NetworkLiveData getInstance(Context context) {
        if (mNetworkLiveData == null) {
            mNetworkLiveData = new NetworkLiveData(context);
        }
        return mNetworkLiveData;
    }

    @Override
    protected void onActive() {
        super.onActive();
        Log.d(TAG, "onActive:");
        mContext.registerReceiver(mNetworkReceiver, mIntentFilter);
    }

    @Override
    protected void onInactive() {
        super.onInactive();
        Log.d(TAG, "onInactive: ");
        mContext.unregisterReceiver(mNetworkReceiver);
    }

    private static class NetworkReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            ConnectivityManager manager = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo activeNetwork = manager.getActiveNetworkInfo();
            getInstance(context).setValue(activeNetwork);

        }
    }
}

这样,当我们想监听网络变化的时候,我们只需要调用相应的 observe 方法即可,方便又快捷。

NetworkLiveData.getInstance(this).observe(this, new Observer<NetworkInfo>() {
    @Override
    public void onChanged(@Nullable NetworkInfo networkInfo) {
        Log.d(TAG, "onChanged: networkInfo=" +networkInfo);
    }
});

构造器有参数的ViewModel

我们的 ViewModel 是通过ViewModelProvider(this).get(MainViewModel::class.java)方法创建出来的,如果我们要携带参数,怎么办?

当我们的ViewModel需要进行构造器需要穿参数的时候,就不能像上面一样进行实例化了。而需要借助于ViewModelProvider的Fatory来进行构造。

class MainViewModel(val name: String) : ViewModel() {

    private val mainLiveData = MutableLiveData<String>()

    fun loadData() {
        mainLiveData.postValue("xyh$name")
    }

    fun getMainLiveData(): MutableLiveData<String> {
        return mainLiveData
    }

    class MainViewModelFactory(private val name: String) : ViewModelProvider.Factory {
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            return MainViewModel(name) as T
        }
    }
}

可以看到在MainViewModel有一个内部类基础自ViewModelProvider.Factory接口。并重写了create方法。这个方法返回一个ViewModel这里我们就是要实例化MainViewModel对象,因此这里返回一个MainViewModel对象,可以看到参数这时候就通过MainViewModelFactory传给了MainViewModel了。

这时候不光是MainViewModel要进行修改,在进行MainViewModel的获取的时候也是需要进行相应的修改的:

        val mainViewModel = ViewModelProvider(
            this,
            MainViewModel.MainViewModelFactory("赵丽颖")
        ).get(MainViewModel::class.java)

Factory 是一个接口,它只有一个 create 方法:

public interface Factory {
    /**
     * Creates a new instance of the given {@code Class}.
     * <p>
     *
     * @param modelClass a {@code Class} whose instance is requested
     * @param <T>        The type parameter for the ViewModel.
     * @return a newly created ViewModel
     */
    @NonNull
    <T extends ViewModel> T create(@NonNull Class<T> modelClass);
}

在实际当中,我们的做法是:实现 Factory 接口,重写 create 方法,在create 方法里面调用相应的构造函数,返回相应的实例。

Fragment和 Activity之间之间共享数据

Fragment和 Activity 之间共享数据

Fragment 和所依附的 Activity,因而他们的 ViewModel 实例是相同的,从而可以做到共享数据。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        supportFragmentManager.beginTransaction().replace(R.id.flContent,MyFragment()).commit()

		//Activity传递数据到ViewModel
        val mainViewModel = ViewModelProvider(this,
                MainViewModel.MainViewModelFactory("赵丽颖")).get(MainViewModel::class.java)

        mainViewModel.loadData()
        mainViewModel.getMainLiveData().observe(this, {
            Log.e("xyh", "MainActivity: $it")
        })
    }
}
class MyFragment : Fragment() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val mainViewModel = activity?.let { ViewModelProvider(it).get(MainViewModel::class.java) }

        mainViewModel?.loadData()

        mainViewModel?.getMainLiveData()?.observe(this, {
            Log.e("xyh", "MyFragment:$it")

            //获取activity的共享数据
            Log.e("xyh", "MyFragment name=${mainViewModel.getName()} ")
        })
    }
}
class MainViewModel(private val name: String) : ViewModel() {

    private val mainLiveData = MutableLiveData<String>()

    fun loadData() {
        mainLiveData.postValue("zly")
    }

    class MainViewModelFactory(private val name: String) : ViewModelProvider.Factory {
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            return MainViewModel(name) as T
        }
    }

    fun getMainLiveData(): MutableLiveData<String> {
        return mainLiveData
    }

    fun getName(): String {
        return name
    }
}

这样,MainActivity和 Fragment中的 ViewModel 是同一个实例。即 Activity 和 Fragment 共享数据。

Fragment和Fragment之间共享数据

一个Activity中的多个Fragment相互通讯是很常见的。之前每个Fragment需要定义接口描述,所属Activity将二者捆绑在一起。此外,每个Fragment必须处理其他Fragment未创建或不可见的情况。通过使用ViewModel可以解决这个痛点,这些Fragment可以使用它们的Activity共享ViewModel来处理通讯。

class ShareViewModel:ViewModel()  {

    private val mutableLiveData = MutableLiveData<String>()

    fun setData(value:String) {
        mutableLiveData.value = value
    }

    fun getData(): LiveData<String> {
        return mutableLiveData
    }
}

class Fragment1 : Fragment() {

    private lateinit var mBinding: Fragment1Binding

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        mBinding = DataBindingUtil.inflate<Fragment1Binding>(
            inflater,
            R.layout.fragment1,
            container,
            false
        )
        return mBinding.root
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        val viewModel = ViewModelProvider(activity!!).get(ShareViewModel::class.java)

        mBinding.btn.setOnClickListener {
            viewModel.setData("xyh")
        }
    }

}

class Fragment2 : Fragment() {

    private lateinit var mBinding: Fragment2Binding

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        mBinding = DataBindingUtil.inflate<Fragment2Binding>(
            inflater,
            R.layout.fragment2,
            container,
            false
        )
        return mBinding.root
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        val viewModel = ViewModelProvider(activity!!).get(ShareViewModel::class.java)

        viewModel.getData().observe(viewLifecycleOwner, Observer {
            mBinding.tv.text = it
        })
    }

}

注意:上面两个Fragment都用到了如下代码来获取ViewModel,activity返回的是同一个宿主Activity,因此两个Fragment之间返回的是同一个SharedViewModel对象。

val viewModel = ViewModelProvider(activity!!).get(ShareViewModel::class.java)

这种方式的好处包括:

  • Activity不需要做任何事情,也不需要知道通讯的事情
  • Fragment不需要知道彼此,除了SharedViewModel进行联系。如果它们(Fragment)其中一个消失了,其余的仍然能够像往常一样工作。
  • 每个Fragment有自己的生命周期,而且不会受其它Fragment生命周期的影响。事实上,一个Fragment替换另一个Fragment,UI的工作也不会受到任何影响。

全局共享数据

说到全局共享数据,我们想一下我们的应用全景,比如说我的账户数据,这个对于整个 App 来说,肯定是全局共享的。有时候,当我们的数据变化的时候,我们需要通知我们相应的界面,刷新 UI。如果用传统的方式来实现,那么我们一般才采取观察者的方式来实现,这样,当我们需要观察数据的时候,我们需要添加 observer,在界面销毁的时候,我们需要移除 observer。

但是,如果我们用 LiveData 来实现的话,它内部逻辑都帮我们封装好了,我们只需要保证 AccountLiveData 是单例的就ok,在需要观察的地方调用 observer 方法即可。也不需要手动移除 observer,不会发生内存泄漏,方便快捷。

这里 AccountLiveData 的实现就不贴出来了,可以参考上面的 NetworkLiveData 实现。

MediatorLiveData

MutableLiveData的子类,中介者,媒介,将多个liveData的数据,合并处理成一个LiveData。
在这里插入图片描述
mediator的liveData可以监听A,B两个数据源的变化,通过addSource后,并响应A/B的变化,转化为mediator的变化。

MediatorLiveData是一个LiveData的子类,它将活跃状态或者非活跃状态传播到源LiveData上;也就是说它相当于是一个中间商,通过addSource进行注册的LiveData,当数据进行更新时通过中间商倒一手再进行处理。

MediatorLiveData 可以接管普通的 LiveData,使得当 LiveData 有数据更新的时候,MediatorLiveData 也能够 “收到响应”。

我们看一下官方介绍的两个场景:

  1. 有多个LiveData,我们想要同时监听这两个数据源,只要他们之中有一个数据源更新则接收到通知

我们看一下具体需要怎么做:

class MainViewModel:ViewModel() {

    //数据源1
    val liveData1=MutableLiveData<String>().apply {
        value="zly1"
    }

    //数据源2
    val liveData2=MutableLiveData<String>().apply {
        value="zly2"
    }

    val mediatorLiveData=MediatorLiveData<String>()

    init {
        //为mediator addSource,监听其他的liveData
        mediatorLiveData.addSource(liveData1, Observer {
            mediatorLiveData.value=it  
        })

        mediatorLiveData.addSource(liveData2, Observer {
            mediatorLiveData.value=it
        })
    }
}
        //通过改变数据源1或者2的数据,接收到更新
        viewModel.mediatorLiveData.observe(this, Observer {
            Log.e("xyh", "onCreate: $it")
        })
  1. 如果数据源变化频繁,我们想要只检测前10个数据变化,之后取消数据观察,我们可以用中间商这么做:
liveDataMerger.addSource(liveData1, new Observer() {
    private int count = 1;
    
    @Override public void onChanged(@Nullable Integer s) {
      count++;
      //1.当数据源1更新后,通知中间商进行更新
      liveDataMerger.setValue(s);
      //2.满足条件后,我们进行取消
      if (count > 10) {
          liveDataMerger.removeSource(liveData1);
      }
    }
});

如果inactive()下,A,B都变化,则resume后,也只接受最新的变化。

MediatorLiveData 应用场景

假设我们需要获取数据,然后将数据的内容展示到UI上,我们有两种方式获取数据,第一种就是拿本地的数据,第二种就是拿网络的数据。我们可以定义两个 MutableLiveData ,对应两种不同方式获取的数据,因为是同一种数据类型,所以我们可以通过 MediatorLiveData 使用 addSource() 来接管两个 MutableLiveData ,并且传入同一个 Observer,这样我们就只需要在 Observer 中进行操作即可……(细思其实并没什么卵用)

Transformations

Transformations 类是 LiveData 的一个功能扩展类,其是一个私有化构造方法的工具类,且只提供 3 个方法使用,虽然数量不多,但胜在实用,这三个方法分别是:

  1. map
  2. switchMap
  3. distinctUntilChanged

map

类似于 RxJava 的 map 操作符、Kotlin 中数组的扩展函数 map,其实 Transformations 的 map 方法也是一个转化的功能。

class MainViewModel : ViewModel() {

    val liveData = MutableLiveData<String>().apply {
        value = "zly"
    }

    //	通过 Transformations.map 返回一个 LiveData
    val mapLiveData = Transformations.map(liveData, Function<String, String> {
        it.plus(" xyh")
    })
}
        viewModel.mapLiveData.observe(this, Observer {
            Log.e("xyh", "onCreate: $it")
        })

控制台输出:

onCreate: zly xyh

map() 方法的第二个参数的类型有两个泛型,事实上第一个个泛型的类型是确定的,那就是对应 map() 方法第一个参数 LiveData 的泛型,那么第二个泛型就是控制返回的 LiveData 的类型。改造上面的例子:

class MainViewModel : ViewModel() {

    val liveData = MutableLiveData<String>().apply {
        value = "zly"
    }

    //	通过 Transformations.map 返回一个 LiveData
    val mapLiveData = Transformations.map(liveData, Function<String, Int> {
        it.length
    })
}

控制台输出:

onCreate: 3

Kotlin 扩展写法:

 val mapLiveData =liveData.map { it.plus("xyh") }

switchMap

看名字,是不是又联想到了 RxJava 的 switchMap 操作符?

实际上 Transformations 的 switchMap 也是一样的功能:舍弃原来的 LiveData,创建一个新的 LiveData 来接管它的变化。

class MainViewModel : ViewModel() {

    val liveData = MutableLiveData<String>().apply {
        value = "zly"
    }

    //	通过 Transformations.switchMap返回一个 LiveData
    val switchMapData = Transformations.switchMap(liveData, Function {
        return@Function  MutableLiveData<String>().apply {
            this.value = it.plus("xyh")
        }
    })
}

控制台输出:

zly xyh

对比一下 map() 方法,switchMap() 显得如此的不堪……但存在即合理,它的也有它的使用场景。

我们先对比一下 switchMap() 和 map() 的使用过程:map() 的操作已经是在消费上层 LiveData 的值,而 switchMap() 同样使消费了上层 LiveData 的值,但是它又创建了新的生产者,所以其真实的消费并不是由 switchMap() 来执行的。

知道了这点后,我们就可以比较清晰的了解 switchMap() 的使用场景了:那就是通过其创建一个新的 LiveData,并且我们可以在其间做一些操作,无论是单纯的转变类型,或是时间上的耗时操作……

Kotlin 扩展:

val switchMapData = liveData.switchMap {
        return@switchMap MutableLiveData<String>().apply {
            this.value = it.plus("world")
        }
    }

distinctUntilChanged

这个方法也能够返回一个监听 source 的 LiveData,当源 LiveData 发生变化 ,其返回的 LiveData 也能够发生变化……这可不就是map()吗?但不同的是,如果源 LiveData 一直进行 setValue()/postValue() 同一个值,那么返回的 LiveData 只接收第一次返回的值,除非源 LiveData 设置新的值。

	private val originData = MutableLiveData<String>()
	//	通过 Transformations.distinctUntilChanged 返回一个 LiveData
	val newData = Transformations.distinctUntilChanged(originData)
	newData.observe(this, Observer {
            Log.e("newData",it)
    })
	//	点击按钮给 originData 赋值
    btn.setOnClickListener {
        originData.value = "Hello"
    }

然后疯狂的点击按钮,而控制台只有一行输出,并且通过源码我们也能够发现它没有转换类型的功能,source 的类型是怎样的,那么返回的 LiveData 的类型就是怎样的。

Kotlin 扩展:

val newData = originData.distinctUntilChanged()

Transformations 的 3 个函数都十分的具有实用性,在具体的开发过程中,我们在业务层完全就可以依赖 LiveData 去实现值的传递的过程,甚至是变换的过程。使用起来也具有较强的灵活性、技巧性。

LiveData使用问题

Android开发 SingleLiveEvent解决LiveData或者MutableLiveData多次回调的问题

只要使用过一段时间的LiveData就会发现,LiveData会经常多次回调数据。我们经常碰到的这个问题。

场景1:

使用LiveData作为事件Event不合适:
通过liveData的Event跳转详情页,手动点击触发 observe中true则跳转,返回首页,则liveData重新active,则再次跳转。(不应尝试多次变更,不建议愚蠢的手动reset)

场景2:

我们的ViewModel里是给Activity持有的并且里面有一个LiveData数据,我们A_Fragment现在获得Activity的ViewModel并且注册LiveData数据成为观察者,这个时候我们setValue()就会让前台的A_Fragment得到一次LiveData数据,接下来操作 A_Fragment 启动 B_Fragment,在返回到A_Fragment。 你会发现只要再次注册LiveData的observe(this, new Observer …),那么A_Fragment里面又会接收到一次LiveData的数据。

为什么会这样呢?

  1. 一部分原因是LiveData的机制,就是向所有前台Fragment或者Activity发送数据。只要注册的观察者在前台就必定会收到这个数据。

  2. 另一部分的原因是对ViewModel理解不深刻,理论上只有在Activity保存的ViewModel它没被销毁过就会一直给新的前台Fragment观察者发送数据。我们需要管理好ViewModel的使用范围。 比如只需要在Fragment里使用的ViewModel就不要给Activity保管。而根Activity的ViewModel只需要做一下数据共享与看情况使用LiveData。

针对liveData用作event的时候,由于即使在inactive状态下,不论有无observer都能set值,并被持有,恢复active即被通知observer,在特定场景下,不适用。(如ViewModel中的liveData,在UI中感知,来跳转界面;就会出现返回界面后,会再次跳转的问题。

处理方案:是判断处理情况,再决定通知事件。

通俗的,低级的方式

// 通俗的,低级的方式
open class LowLiveEvent<out T>(private val content: T) {

    private var hasHandled = false;//标记位


    //如果没有处理,就返回content,否则null
    fun getContentIfNotHandled(): T? {
        return if (hasHandled) {
            hasHandled = true
            content
        } else {
            content
        }
    }

    //不论已经处理与否,都感知变化
    fun peekContent(): T = content
}

使用

//使用 
val liveD = mutableLiveData<LowLiveEvent<String>>()
//
liveD.observe(this,Observer{
    it.getContentIfnotHandled()?.let{
        //do something
    }
})

第二种方法:使用SingleLiveEvent

就是使用一个google大神实现的一个复写类 SingleLiveEvent,其中的机制是用一个原子 AtomicBoolean记录一次setValue。在发送一次后在将AtomicBoolean设置为false,阻止后续前台重新触发时的数据发送。

//SingleLiveEvent 原理类似于上面的,通过AtomicBoolean来标记对比处理情况,
//会选择通知一个处于active的observe变化,但是不确保是哪一个
class SingleLiveEvent<T> : MutableLiveData<T>() {

    private val mPending = AtomicBoolean(false)

    @MainThread
    override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {

        if (hasActiveObservers()) {
            Log.w(
                "SingleLiveEvent",
                "Multiple observers registered but only one will be notified of changes."
            )
        }

        // Observe the internal MutableLiveData
        super.observe(owner, Observer { t ->
            if (mPending.compareAndSet(true, false)) {
                observer.onChanged(t)
            }
        })
    }

    @MainThread
    override fun setValue(t: T?) {
        mPending.set(true)
        super.setValue(t)
    }

    /**
     * Used for cases where T is Void, to make calls cleaner.
     */
    @MainThread
    fun call() {
        value = null
    }
}

LiveData原理和源码分析

原理

观察者模式+ Lifecycle(LiveData 的生命周期感知是由Lifecycle来实现的)。

LiveData既是被观察者,可以被其他观察者观察数据的变化。

LiveData也是观察者,可以观察Activity的生命周期的变化。

LiveData是被观察者,Activity中创建观察者,订阅被观察者LiveData后,被观察者LiveData数据的变化时会通知观察者,当Activity处于活动状态,才会去通知数据更新,通过Lifecycle来监听Activity是否处于活动状态。

源码分析

LiveData

// 注意,他是 abstract class
public abstract class LiveData<T> {

    ...省略其他代码...
     
    // 只有 onStart 后,对数据的修改才会触发 observer.onChanged()
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {}

    // 无论何时,只要数据发生改变,就会触发 observer.onChanged()
    public void observeForever(@NonNull Observer<T> observer) {}

    ...省略其他代码...
}

MutableLiveData

由于 LiveData 是一个 abstract class,我们不能直接生成他的实例。官方有提供他的实现类MutableLiveData。

MutableLiveData实际上就是继承自LiveData,没有什么特别:

public class MutableLiveData<T> extends LiveData<T> {

    /**
     * Creates a MutableLiveData initialized with the given {@code value}.
     *
     * @param value initial value
     */
    public MutableLiveData(T value) {
        super(value);
    }

    /**
     * Creates a MutableLiveData with no value assigned to it.
     */
    public MutableLiveData() {
        super();
    }

    @Override
    public void postValue(T value) {
        super.postValue(value); //postValue内部实际上调用的也是setValue
    }

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}

我们根据在MainActivity 使用LiveData来分析源码

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //setContentView(R.layout.activity_main)

        val binding =
            DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)

        //过时 2.2.0-alpha02 以前的版本是通过下面的方式,新版本已弃用。
        //val mainViewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
        val mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)

        //创建一个观察者来观察数据的变化
        val observer: Observer<String> = object : Observer<String> {
            override fun onChanged(t: String?) {
                binding.textView.text = t
            }
        }

        //订阅一个观察者
        mainViewModel.getLiveData().observe(this, observer)

        //点击按钮更新数据
        binding.btn.setOnClickListener {
            mainViewModel.getLiveData().value = "hello ${mainViewModel.i++}"
        }
    }
}

创建了Livedata 后,需要通过observe方法或者observeForever 方法设置一个回调,这个回调接口就是Observer:

public interface Observer<T> {
    /**
     * Called when the data is changed.
     * @param t  The new data
     */
    void onChanged(T t);
}

一. LiveData的observer方法

observeForever 的实现跟 observe 是类似的,这里我们重点看一下 observe()的实现过程。

  • viewModel.getLiveData()获取到 我们的 LiveData,然后调用LiveData的observer方法,并把当前MainActivity 作为参数传递进去。
  • observer() 方法就是我们分析的入口了,接下来我们看LiveData的observer()方法都做了什么:
public abstract class LiveData<T> {

   private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
            new SafeIterableMap<>();

    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
       
        assertMainThread("observe"); //判断是否是主线程
		
		//标注1
		//LifecycleOwne(MainActivity )当前的状态
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        
        //标注2
        //LifecycleBoundObserver包装了owner和observer,可以感知Activity的生命周期
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        
        //把观察者保存到集合
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        //添加观察者
        //wrapper就可以监听Activity/Fragment的生命周期
        //当UI的生命周期发生变化的时候,就会去回调wrapper中的 onStateChanged
        owner.getLifecycle().addObserver(wrapper);
    }
}
  • 可以看到,当前Activity是作为 LifeCycleOwner 参数传进来的,Activity会默认继承LifecycleOwner,而 LifecycleOwner 可获取到该组件的LifeCycle,也就知道了Activity组件的生命周期的状态。
  • 看标注1处,如果我们的 Activity组件已经是destroy状态的话,将直接返回,不会被加入观察者行列。
  • 如果不是destroy状态,就到标注2处,新建一个 LifecycleBoundObserver 将我们的 LifecycleOwner 和 observer保存起来,然后调用 mObservers.putIfAbsent(observer, wrapper) 将observer和wrapper分别作为key和value存入Map中,putIfAbsent()方法会判断如果 value 已经能够存在,就返回,否则返回null。
  • 如果返回existing为null,说明以前没有添加过这个观察者,就将 LifecycleBoundObserver 作为 owner 生命周期的观察者,也就是作为 Activity生命周期的观察者

二. LiveData作为观察者

LiveData观察Activity生命周期发生变化,LiveData回调接口的调用情况

LifecycleBoundObserver 源码:

  • 我们来看一个当生命周期发生变化的时候,LifecycleBoundObserver都做了那些操作,熟悉LifeCycle的小伙伴,应该会很熟悉,生命周期发生变化时,会调用onStateChanged。
   class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        @NonNull
        final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
            super(observer);
            mOwner = owner;
        }
		
		//STARTED  RESUMED状态时为true
		//表示Activity处于活动状态,可以更新数据
        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

		 //Activity生命周期变化时回调到这里
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            
            // 当Activity的生命周期为DESTROYED,取消对数据变化的监听,移除Observer
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            //改变数据,传递的参数是shouldBeActive(),
            //它会计算看当前的状态是否是STARTED,也就是 onStart-onPause 期间生命周期
            activeStateChanged(shouldBeActive());
        }

        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }

        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }

  • 代码并不多,LifecycleBoundObserver 继承自 ObserverWrapper 并实现了 LifecycleEventObserver 接口,而 LifecycleEventObserver 接口又继承自 LifecycleObserver 接口,那么根据 Lifecycle 的特性,实现了LifecycleObserver接口并且加入 LifecycleOwner 的观察者里就可以感知或主动获取 LifecycleOwner 的状态。

我们继续看下activeStateChanged方法是如何对数据进行处理的,它是ObserverWrapper 类中的一个方法:

    private abstract class ObserverWrapper {
        final Observer<? super T> mObserver;
        //Activity是否处于活动状态
        //Activity生命周期状态为 STARTED  RESUMED状态时为true
        boolean mActive;
        int mLastVersion = START_VERSION;

        ObserverWrapper(Observer<? super T> observer) {
            mObserver = observer;
        }

        abstract boolean shouldBeActive();

        boolean isAttachedTo(LifecycleOwner owner) {
            return false;
        }

        void detachObserver() {
        }

        void activeStateChanged(boolean newActive) {
            // 当前的生命周期和上一次的生命周期状态,是否发生变化,没有发生变化,就直接返回。
            // onStart-onPause 为 true  在这之外的生命周期为false
            if (newActive == mActive) {
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
            mActive = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            LiveData.this.mActiveCount += mActive ? 1 : -1;
            if (wasInactive && mActive) {
            // 这是一个空函数,可在代码中根据需要进行重写
                onActive();
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
             // 这是一个空函数,可在代码中根据需要进行重写
                onInactive();
            }

			//Activity活跃状态
			//结合上面的状态判断,我们知道了,生命周期状态从Inactive 到 Active, 就会调用回调函数
            if (mActive) {
                dispatchingValue(this);
            }
        }
    }

  • dispatchingValue
 void dispatchingValue( ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }
  • considerNotify
 private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
        //
        // we still first check observer.active to keep it as the entrance for events. So even if
        // the observer moved to an active state, if we've not received that event, we better not
        // notify for a more predictable notification order.
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }

为什么在生命周期的活跃状态 从Inactive 到 Active,要去调用livedata设置的回调函数呢?

原因是,在Inactive (在非 onStart-onPause 周期内 )状态,数据发生了变化,然后在回到Active(onStart-onPause 周期内),如果不去调用回调函数,会出现UI的界面,还在显示上一次的数据,所以需要调用回调函数。

再回到代码流程,到了调用dispatchingValue(this);这个函数在数据发生变化,也是会去调用的,所以在后面分析,先来看下,数据发生变化,代码的流程

三. LiveData作为被观察者

LiveData数据发生发生变化,调用回调接口

好了,看完了观察者,那么我们的LiveData什么时候会通知观察者呢?不用想,肯定是数据更新的时候,而数据的更新是我们代码自己控制的。

       //点击按钮更新数据
        binding.btn.setOnClickListener {
            mainViewModel.getLiveData().value = "hello ${mainViewModel.i++}"
        }

LiveData的setValue方法:

   private int mVersion;
   
   @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue"); //检查是否在主线程
        
        mVersion++; //mVersion 表示数据发生了变化
        
        mData = value;  //将要更新的数据赋给mData
		
		//调用 dispatchingValue()方法并传入null,将数据分发给各个观察者
        dispatchingValue(null); 
    }

进入到dispatchingValue方法:

    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            //标注1
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
          	   //标注2
          	   //遍历观察者集合
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                     //通知观察者调用considerNotify()方法
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }
  • 从标注1可以看出,dispatchingValue()参数传null和不传null的区别就是如果传null将会通知所有的观察者,反之仅仅通知传入的观察者。
  • 我们直接看标注2,通知所有的观察者通过遍历mObservers ,将所有的 ObserverWrapper 拿到,实际上就是我们上面提到的LifecycleBoundObserver,通知观察者调用considerNotify()方法,这个方法就是通知的具体实现了。

看下considerNotify 的函数,调用了之前livedata设置的observer的onChanged函数:

    private void considerNotify(ObserverWrapper observer) {
    	//如果观察者不是活跃状态,将不会通知此观察者
        if (!observer.mActive) {
            return;
        }
       
        if (!observer.shouldBeActive()) {
        	// 如果当前的生命周期是非活跃,就不回调onChanged函数,
           // 在LifecycleBoundObserver 中记录状态,当生命周期变为活跃,就回去更新数据
            observer.activeStateChanged(false);
            return;
        }
		//数据发生变化了
        if (observer.mLastVersion >= mVersion) {
            return;
        }

		//Activity活跃状态,就会走到这里
		
        observer.mLastVersion = mVersion;
        //调用LiveData的observer()方法传入的 Observer,然后调用 Observer 的 onChanged((T) mData)	   
        //方法,将保存的数据mData传入,也就实现了更新。
        observer.mObserver.onChanged((T) mData);
    }

在看下我们实现的Observer:

        //创建一个观察者来观察数据的变化
        val observer: Observer<String> = object : Observer<String> {
            override fun onChanged(t: String?) {
                binding.textView.text = t
            }
        }

        //订阅
        mainViewModel.getLiveData().observe(this, observer)

如果哪个控件要根据数据的变更而及时更新,就在onChanged()方法里处理就可以了。到这里,LiveData已经能够分析完了,其实LiveData的实现还是要依赖于Lifecycle

postValue 方法

看完了 setValue,postValue 就很简单了:

    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            // 上一个 post 后还没有执行的 runnable,所以就不需要再 post 了,
            // 但是注意,上面的mPendingData 数据已经是新数据了 
            //用官方的话,就是  If you called this method multiple times before a main thread executed a posted task, only the last value would be dispatched.
            return;
        }
        // postValue 可以从后台线程调用,因为它会在主线程中执行任务
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

    private final Runnable mPostValueRunnable = new Runnable() {
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            //noinspection unchecked
            //这里调用了setValue,和上面分析的流程一样
            setValue((T) newValue);
        }
    };

总结

  • LiveData 内部已经实现了观察者模式,如果你的数据要同时通知几个界面,可以采取这种方式 。
  • 我们知道 LiveData数据变化的时候,会回调 Observer 的 onChange 方法,但是回调的前提是 lifecycleOwner(即所依附的Activity 或者 Fragment) 处于 started 或者 resumed 状态,它才会回调,否则,必须等到 lifecycleOwne 切换到前台的时候,才回调。因此,这对性能方面确实是一个不小的提升。但是,对于你想做一些类似与在后台工作的(黑科技),liveData就不太适合了,你可以使用 observeForever 方法,或者自己实现观察者模式去吧。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
作者codyer,源码ElegantBus,ElegantBus 是一款 Android 平台,基于 LivaData 的消息总线框架,这是一款非常 优雅 的消息总线框架。如果对 ElegantBus 的实现过程,以及考虑点感兴趣的可以看看前几节自吹如果只是想先使用的,可以跳过,直接到跳到使用说明和常见 LivaData 实现的 EventBus 比较消息总线使用反射入侵系统包名进程内 Sticky跨进程 Sticky跨 APP Sticky事件可配置化线程分发消息分组跨 App 安全考虑常驻事件 StickyLiveEventBus:white_check_mark::white_check_mark::white_check_mark::x::x::x::x::x::x::x:ElegantBus:x::x::white_check_mark::white_check_mark::white_check_mark::white_check_mark::white_check_mark::white_check_mark::white_check_mark::white_check_mark:来龙去脉自吹ElegantBus 支持跨进程,且支持跨应用的多进程,甚至是支持跨进程间的粘性事件,支持事件管理,支持事件分组,支持自定义事件,支持同名事件等。之所以称之为最优雅的总线,是因为她不仅实现了该有的功能,而且尽量选用最合适,最轻量,最安全的方式去实现所有的细节。 更值得夸赞的是使用方式的优雅!前言随着 LifeCycle 的越来越成熟,基于 LifeCycle 的 LiveData 也随之兴起,业内基于 LiveData 实现的 EventBus 也如雨后春笋一般拔地而起。出于对技术的追求,看过了无数大牛们的实现,各位大神们思路也是出奇的神通,最基础的 LiveData 版 EventBus 其实大同小异,一个单例类管理所有的事件 LivaData 集合。如果不清楚的可以随便网上找找反正基本功能 LivaData 都支持了,实现 EventBus 只需要把所有事件管理起来就完事了。业内基于 LiveData 实现的 EventBus,其实考虑的无非就是下面提到的五个挑战,有的人考虑的少,有的人考虑的多,于是各种方案都有。ElegantBus 主要是集合各家之优势,进行全方面的考虑而产生的。五个挑战 之 路途险阻挑战一 : 粘性事件背景 LivaData 的设计之初是为了数据的获取,因此无论是观察开始之前产生的数据,还是观察开始之后产生的数据,都是用户需要的数据,只要是有数据,当 LifeCycle 处于激活状态,数据就会传递给观察者。这个我们称之为 粘性数据。 这种设计对于事件来说有时候就不那么友好了,之前的事件用户可能并不关心,只希望收到注册之后发生的事件。挑战二 : 多线程发送事件可能丢失背景 同样是因为使用场景的原因,LivaData 设计在跨线程时,使用 post 提交数据,只会保留最后一次数据提交的值,因为作为数据来说,用户只需要关心现在有的数据是什么。挑战三 : 跨进程事件总线背景 有时候我们应用需要设置多进程,不同模块可能允许在不同进程中,因为单例模式每个进程都有一份实体,所有无法达到跨进程,这时候设计 IP 方案选择。说明 这里提一下为什么不选用广播方式,对广播有一定了解的都知道,全局广播会有信息泄露,信息干扰等问题,而且开销也比较大,因此全局广播并不适合这种情况。 也许有人会说可以用本地广播,然而,本地广播目前来说并不是很好的选择。Google 官方也在 LocalBroadcastManager 的说明里面建议使用 LiveData 替代: 原文地址原文如下:2018 年 12 月 17 日版本 1.1.0-alpha01 中将弃用 androidx.localbroadcastmanager。原因LocalBroadcastManager 是应用级事件总线,在您的应用中使用了层违规行为;任何组件都可以监听来自其他任何组件的事件。 它继承了系统 BroadcastManager 不必要的用例限制;开发者必须使用 Intent,即使对象只存在且始终存在于一个进程中。由于同一原因,它未遵循功能级 BroadcastManager。 这些问题同时出现,会对开发者造成困扰。替换您可以将 LocalBroadcastManager 替换为可观察模式的其他实现。合适的选项可能是 LiveData 或被动流,具体取决于您的用例。更明显的原因是,本地广播好像并不支持跨进程~挑战四 : 跨应用(权限问题以及粘性问题)背景 跨进程相对来说还比较好实现,但是有的时候用户会有跨应用的需求,其实这个也是 IPC 范畴,为什么单独提出

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值