Android核心技术—liveData使用与源码&liveDataBus封装学习

132 阅读4分钟

LiveData简介

LiveData 是一个可以被观察的数据持有类,它可以感知 Activity、Fragment或 Service 等组件的生命周期。简单来说,他主要有一下优点。

它可以做到在组件处于激活状态的时候才会回调相应的方法,从而刷新相应的 UI,不用担心发生内存泄漏 当 config 导致 activity 重新创建的时候,不需要手动取处理数据的储存和恢复。它已经帮我们封装好了。 当 Actiivty 不是处于激活状态的时候,如果你想 livedata setValue 之后立即回调 obsever 的 onChange 方法,而不是等到 Activity 处于激活状态的时候才回调 obsever 的 onChange 方法,你可以使用 observeForever 方法,但是你必须在 onDestroy 的时候 removeObserver。

liveDataBus简单实现

public class LiveDataBus {
    private final Map<String, MutableLiveData<Object>> mBus;
​
    private LiveDataBus() {
        mBus = new ArrayMap<>();
    }
​
    private static abstract class SingleHolder {
        private static final LiveDataBus DATA_BUS = new LiveDataBus();
    }
​
    public static LiveDataBus get() {
        return SingleHolder.DATA_BUS;
    }
​
    public <T> MutableLiveData<T> getChannel(String target, Class<T> type) {
        if (!mBus.containsKey(target)) {
            mBus.put(target, new MutableLiveData<>());
        }
        return (MutableLiveData<T>) mBus.get(target);
    }
​
    public MutableLiveData<Object> getChannel(String target) {
        return getChannel(target, Object.class);
    }
}

到这里我们其实已经实现了liveDataBus的基本功能,我们进行如下测试: 在第一个activity中调用:

LiveDataBus.get().getChannel("myfirst1").setValue("我给你发数据了,你收到了吗");

在第二个activity中注册并接受消息

LiveDataBus.get().getChannel("myfirst1", String.class).observe(this, new Observer<String>() {
            @Override
            public void onChanged(@Nullable String s) {
                Toast.makeText(SecondActivity.this, "我收到了蛋疼的消息" + s, Toast.LENGTH_SHORT).show();
            }
        });

这个时候你会发现在第二个activity打开时会出现toast,但是细心的同学会发现,我是在打开第二个activity之前发的消息,在第二个activity打开的时候订阅的,也就是说,我后订阅却收到了你之前发的消息,那如果你们之前发了几千条消息了,我刚刚订阅,难道要我先处理这几千条数据(这一点很像粘性广播的特性)? 显然,这不是我们想要的效果,我们要的结果是observer在被注册之后才能接收消息,而且接收到的消息也应该是在订阅之后发的消息。

封装LIveDataBUS

下面我们封装个LiveDataBus,可以实现EventBus所有功能,而且还可以区分订阅者,重点不会导致内存泄漏。

//封装思路很简单,就是用个map,key作为数据区分的tag,以MutableLiveData为容器装载数据,就这么简单,

public class LiveDataBus {
    private Map<String, Object> map;
​
    //双重校验锁 单利
    private static volatile LiveDataBus liveDataBus;
     
    private LiveDataBus() {
        //初始化map
        map = new HashMap<>();
    }
     
    public static LiveDataBus getInstance() {
        if (liveDataBus == null) {
            synchronized (LiveDataBus.class) {
                if (liveDataBus == null) {
                    liveDataBus = new LiveDataBus();
                }
            }
        }
        return liveDataBus;
    }
​
 
​
    //封装liveData
    public synchronized <T> MutableLiveData<T> with(String key, Class<T> t) {
      
        //原理就是通过map管理key 和livedata ;key和livedata一一对应,
       //先判断map 中是否包含传进来的key对应的值(liveData),有就直接返回liveData,
         没有就就创建个liveData保存到map里面
     
        if (!map.containsKey(key)) {
            map.put(key, new MutableLiveData<T>());
        }
     
        return (MutableLiveData<T>) map.get(key);
    }
​
 
​
}

在activity使用liveDataBus

public class LiveDataActivity extends AppCompatActivity {
​
​
    private MutableLiveData<List<Bean>> liveData;
    private List<Bean> list = new ArrayList<>();
     
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_live_data);
​
 
​
        /**
         * 使用封装的liveData
         */
        LiveDataBus.getInstance().with("1", Bean.class).observe(this, new Observer<Bean>() {
            @Override
            public void onChanged(Bean bean) {
                Toast.makeText(LiveDataActivity.this, "" + bean.getName(), Toast.LENGTH_SHORT).show();
            }
        });
​
 
​
    }
​
 
​
    /**
     * 使用封装的liveData 发送数据
     */
    public void send(View view) {
        Bean bean = new Bean("测试");
        LiveDataBus.getInstance().with("1", Bean.class).setValue(bean);
     
    }
​
 
​
}

liveData源码解析

那么为什么会出现这种情况呢?抱着疑惑我们翻看一下liveData的源码:

首先我们看到liveData持有了一个ObserverWrapper的集合,那么这个ObserverWrapper是什么东东呢?接着看:

我们看到ObserverWrapper其实是LiveData的一个内部类,他把观察者observer包裹了,并且记录了当前observer的状态(mActive是否活跃)、上一个版本(mLastVersion)。 我们再看一下我们调用的observe方法:

在这里我们看到了我们的observer被包裹成了LifecycleBoundObserver,他其实继承了ObserverWrapper。 接下来我们看看我们发送数据时做了些啥:

当我们调用setValue方法时,它会调用dispatchingValue方法完成:

接着调用了considerNotify(initiator):

如上图,我们看到当observer.mLastVersion >= mVersion时方法就直接return了,没有再执行onChanged()方法,所以我们可以猜想我们是不是可以通过控制这两个变量的值来实现我们想要的结果呢?于是乎我们先来捋捋这两个变量 那么mVersion怎么赋值的:

static final int START_VERSION = -1;
private int mVersion = START_VERSION;
​
@MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;//每次我们调用setValue时,mVersion加1
        mData = value;
        dispatchingValue(null);
    }

那么mLastVersion 又是怎么赋值的呢:

我们看到mLastVersion每次都是赋值为START_VERSION,而这个常量我们在上面看到他的值是-1,而且在上图中我们可以看到在considerNotify方法中每次调用onChanged方法之前,都会把mVersion赋值给observer.mLastVersion。 好看完源码,我们思考一下,我们能不能再创建新的ObserverWrapper的时候,直接把mVersion的值赋给mLastVersion,这样就符合(observer.mLastVersion >= mVersion)这一条件了,就不会再继续执行onChanged方法了。

好的分析完了,以上就是liveData的简单介绍与使用,还有liveDataBus的封装实现以及liveData的源码解析;更多有关Android开发相关的知识需要可以参考传送直达↓↓↓ :link.juejin.cn/?target=htt…里面技术版块划分为30多个技术文档,供大家进阶高级Android。

总结

使用封装的总线,只能发送bean数据,如果你的数据是集合什么的需要封装到bean里面。其他跟Evnetbus一样。如果你想使用原生的也可以。