LiveData相关基本使用及去除黏性数据的方法

目录

  • 一、LiveData的基本使用
    • [1. 使用方式一](#1. 使用方式一)
    • [2. 使用方式二](#2. 使用方式二)
    • [3. 使用方式三](#3. 使用方式三)
  • [二、LiveData 去除黏性数据的方法](#二、LiveData 去除黏性数据的方法)
    • [1. 去除黏性的Java版本](#1. 去除黏性的Java版本)
    • [2. 去除黏性的Kotlin版本](#2. 去除黏性的Kotlin版本)

一、LiveData的基本使用

1. 使用方式一

MyLiveData.kt

复制代码
package com.example.mylivedata.simple1

import androidx.lifecycle.MutableLiveData

object MyLiveData {  // 单例

    // 懒加载
    val info : MutableLiveData<String> by lazy { MutableLiveData<String>() }
}

MainActivity.kt

复制代码
package com.example.mylivedata.simple1

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
import androidx.lifecycle.Observer
import com.example.mylivedata.R
import kotlin.concurrent.thread

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

        val textView : TextView = findViewById(R.id.tv_textView)

        // TODO 1.观察者 环节
        MyLiveData.info.observe(this, Observer<String> { t ->
            textView.text = t // 更新UI
        })

        // 完整写法  new Observer 重写onChange方法
        MyLiveData.info.observe(this, object : Observer<String> {
            override fun onChanged(t: String?) {
                textView.text = t  // 更新UI
            }

        })

        // TODO 2.触发数据改变  环节
        MyLiveData.info.value = "default"  // setValue  主线程

        thread {
            Thread.sleep(3000)
            MyLiveData.info.postValue("三秒钟后,修改了哦")  // postValue 子线程
        }

        thread {
            Thread.sleep(6000)
            MyLiveData.info.postValue("六秒钟后,修改了哦")  // postValue 子线程
        }

    }
}

2. 使用方式二

MyLiveData.kt

复制代码
package com.example.mylivedata.simple2

import androidx.lifecycle.MutableLiveData

object MyLiveData {  // 单例

    // 这里为data的MutableLiveData 懒加载初始化(懒加载:用到时才加载)
    val data : MutableLiveData<String> by lazy { MutableLiveData<String>()}

    init {
        // data.value = "dafault" // 违背 在子线程setValue(SetValue在主线程中执行)
        data.postValue("test")  // 子线程 执行postValue(postValue在子线程中执行)
    }

}

MyServer.kt

复制代码
package com.example.mylivedata.simple2

import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.util.Log
import kotlin.concurrent.thread

// 模拟后台推送
class MyServer : Service() {
    override fun onBind(intent: Intent?): IBinder? = null

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        thread {
            for ( x in 1 .. 1000) {
                Log.d("MyServer", "服务器给你推送消息(叮咚声响),消息内容是:${x}")
                MyLiveData.data.postValue("服务器给你推送消息啦,消息内容是:${x}")
                Thread.sleep(2000)  // 2秒推送一次
            }
        }
        return super.onStartCommand(intent, flags, startId)
    }
}

MainActivity2.kt

复制代码
package com.example.mylivedata.simple2

import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.mylivedata.R
import java.util.*

class MainActivity2 : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)

        // 启动服务
        val button = findViewById<Button>(R.id.bt)
        button.setOnClickListener {
            startService(Intent(this, MyServer::class.java))
            Toast.makeText(this, "推送服务器启动成功", Toast.LENGTH_SHORT).show()
        }

        // 观察者 界面可见的情况下,才能做事情
        MyLiveData.data.observe(this, androidx.lifecycle.Observer {
            Log.d("MyServer", "界面可见,说明用户在查看列表界面啦,更新信息列表UI界面:${it}")
            Toast.makeText(this, "更新消息列表UI界面成功:${it}", Toast.LENGTH_SHORT).show()
        })

    }
}

3. 使用方式三

该方式使用的是黏性数据

MyLiveData.kt

复制代码
package com.example.mylivedata.simple3

import androidx.lifecycle.MutableLiveData

object MyLiveData {

    // 这里的data的MutableLiveData 懒加载初始化(懒加载:用到时才加载)
    val data : MutableLiveData<String> by lazy { MutableLiveData<String>() }

}

MainActivity3.kt

复制代码
package com.example.mylivedata.simple3

import android.content.Intent
import android.os.Bundle
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import com.example.mylivedata.R

class MainActivity3 : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main3)

        val button = findViewById<Button>(R.id.button)
        button.setOnClickListener {
            MyLiveData.data.value = "我就是我,不一样的烟火"

            startActivity(Intent(this, MainActivity4::class.java))
        }
    }
}

MainActivity4.kt

复制代码
package com.example.mylivedata.simple3

import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import com.example.mylivedata.R

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

        // 后观察数据,居然能够收到 前面修改的数据,这就是 数据黏性
       /*
       MyLiveData.data.observe(this, Observer {
            Toast.makeText(this, "观察者数据变化:${it}", Toast.LENGTH_SHORT).show()
        })
        */
        MyLiveData.data.observe(this, object : Observer<String> {
            override fun onChanged(t: String?) {
                Toast.makeText(this@MainActivity4, "观察者数据变化:$t", Toast.LENGTH_SHORT).show()
            }

        })

        // 此观察者 和handler没有区别,一股脑的执行(极端的情况,可以用)
        // 但是需要手动考虑释放工作
        //MyLiveData.data.observeForever {  }
    }

    override fun onDestroy() {
        super.onDestroy()
        // 手动释放
        //MyLiveData.data.removeObserver()
    }
}

二、LiveData 去除黏性数据的方法

1. 去除黏性的Java版本

OkLiveDataBusJava.java

复制代码
package com.example.mylivedata.simple4;

import androidx.annotation.NonNull;
import androidx.arch.core.internal.SafeIterableMap;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 单例模式 去掉粘性事件  Java版本
 */
public class OkLiveDataBusJava {

    // 存放订阅者
    private Map<String, BusMutableLiveData<Object>> bus;
    private static OkLiveDataBusJava liveDataBus = new OkLiveDataBusJava();

    private OkLiveDataBusJava() {
        bus = new HashMap<>();
    }

    public static OkLiveDataBusJava getInstance() {
        return liveDataBus;
    }

    // 注册订阅者
    public synchronized <T> BusMutableLiveData<T> with(String key, Class<T> type) {
        if (bus.containsKey(key)) {
            bus.put(key, new BusMutableLiveData<>());
        }
        return (BusMutableLiveData<T>) bus.get(key);
    }

    public static class BusMutableLiveData<T> extends MutableLiveData<T> {
        @Override
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
            super.observe(owner, observer);  // 启用系统的功能,不写就破坏了
            hook(observer);
        }

        private void hook(Observer<? super T> observer) {
            try {
                // TODO 1.得到mLastVersion
                // 获取到LiveData类中的mObservers对象
                Class<LiveData> liveDataClass = LiveData.class;
                Field mObserversField = liveDataClass.getDeclaredField("mObservers");
                mObserversField.setAccessible(true);
                // 获取到这个成员变量的对象
                Object mObserversObject = mObserversField.get(this);
                // 得到map对象的class对象   private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = new SafeIterableMap<>();
                Class<?> mObserversClass = mObserversObject.getClass();
                // 获取到mObservers对象的get方法
                Method get = mObserversClass.getDeclaredMethod("get", Object.class);
                get.setAccessible(true);
                // 执行get方法
                Object invokeEntry = get.invoke(mObserversObject, observer);
                // 取到entry中的value
                Object observerWrapper = null;
                if (invokeEntry != null && invokeEntry instanceof Map.Entry) {
                    observerWrapper = ((Map.Entry) invokeEntry).getValue();
                }
                if (observerWrapper == null) {
                    throw new NullPointerException("observerWrapper is null");
                }

                // 得到observerWrapper的类对象
                // observerWrapper.getClass() 获取的是LifecycleBoundObserver类对象
                // observerWrapper类是LifecycleBoundObserver类的父类
                Class<?> supperClass = observerWrapper.getClass().getSuperclass();
                Field mLastVersion = supperClass.getDeclaredField("mLastVersion");
                mLastVersion.setAccessible(true);

                // TODO 2.得到mVersion
                Field mVersion = liveDataClass.getDeclaredField("mVersion");
                mVersion.setAccessible(true);

                // TODO 3.mLastVersion = mVersion
                Object mVersionValue = mVersion.get(this);
                mLastVersion.set(observerWrapper, mVersionValue);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

2. 去除黏性的Kotlin版本

OKLiveDataBusKT.kt

复制代码
package com.example.mylivedata.simple4

import android.util.Log
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import java.lang.NullPointerException
import java.lang.reflect.Field
import java.lang.reflect.Method

/**
 * 单例模式 去掉黏性事件(有关闭黏性的开关)KT版本
 */
object OKLiveDataBusKT {

    // 存放订阅者
    private val bus : MutableMap<String, BusMutableLiveData<Any>> by lazy { HashMap<String, BusMutableLiveData<Any>>() }

    // 暴露一个函数,给外界注册,订阅者关系
    fun <T> with(key : String, type : Class<T>, isStack : Boolean = true) : BusMutableLiveData<T> {
        if (!bus.containsKey(key)) {
            bus[key] = BusMutableLiveData(isStack)
        }
        return bus[key] as BusMutableLiveData<T>
    }

    class BusMutableLiveData<T> private constructor() : MutableLiveData<T>() {
        var isStack : Boolean = false

        // 次构造
        constructor(isStack: Boolean) : this() {
            this.isStack = isStack
        }

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

            if (!isStack) {
                hook(observer)
                Log.d("abc", "Kotlin版本 不启用黏性")
            } else {
                Log.d("abc", "Kotlin版本 启用黏性")
            }
        }

        private fun hook(observer: Observer<in T>) {
            // TODO 1.得到mLastVersion
            // 获取到LiveData的类中的mObservers对象
            val liveDataClass = LiveData::class.java
            val mObserversField = liveDataClass.getDeclaredField("mObservers")
            mObserversField.isAccessible = true  // 私有修饰可以访问

            // 获取到这个成员变量的对象 Kotlin Any == Java Object
            val mObserversObject : Any = mObserversField.get(this)

            // 得到map对象的class对象  private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = new SafeIterableMap<>();
            val mObserversClass : Class<*> = mObserversObject.javaClass

            // 获取到mObservers对象的get方法, protected Entry<K, V> get(K k)
            val get : Method = mObserversClass.getDeclaredMethod("get", Any::class.java)
            get.isAccessible = true  // 私有修饰也可以访问

            // 执行get方法
            val invokeEntry : Any = get.invoke(mObserversObject, observer)

            // 取到entry中的value
            var observerWrapper : Any? = null
            if (invokeEntry != null && invokeEntry is Map.Entry<*, *>) {
                observerWrapper = invokeEntry.value
            }
            if (observerWrapper == null) {
                throw NullPointerException("observerWrapper is null")
            }

            // 得到observerWrapper的类对象
            val supperClass : Class<*> = observerWrapper.javaClass.superclass
            val mLastVersion : Field = supperClass.getDeclaredField("mLastVersion")
            mLastVersion.isAccessible = true

            // TODO 2.得到mVersion
            val mVersion : Field = liveDataClass.getDeclaredField("mVersion")
            mVersion.isAccessible = true

            // TODO 3.mLastVersion = mVersion
            val mVersionValue = mVersion.get(this)
            mLastVersion.set(observerWrapper, mVersionValue)
         }
    }
}

MainActivity.kt

复制代码
package com.example.mylivedata.simple4

import android.content.Intent
import android.os.Bundle
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import com.example.mylivedata.R

class MainActivity : AppCompatActivity() {

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

        // LiveData发生消息通知所有的观察者数据变化了
        // KT版本 旧数据  黏性数据
        OKLiveDataBusKT.with("data1", String::class.java).value = "liveData  kotlin数据"
        // Java版本
        OkLiveDataBusJava.getInstance().with("data2", String::class.java).value = "livaData java数据"

        // 点击事件,跳转到下一个Activity
        val button = findViewById<Button>(R.id.button)
        button.setOnClickListener {
            startActivity(Intent(this, MainActivity2::class.java))
        }
    }
}

MainActivity2.kt

复制代码
package com.example.mylivedata.simple4

import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import com.example.mylivedata.R
import kotlin.concurrent.thread

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

        // Kotlin版本订阅观察者
        OKLiveDataBusKT.with("data1", String::class.java).observe(this, Observer(){
            Toast.makeText(this, "Kotlin版本的观察者:${it}", Toast.LENGTH_SHORT).show()
            Log.d("abc", "Kotlin版本的观察者:${it}")

        })

        // Java版本订阅观察者(Java是模拟剔除黏性的)
        OkLiveDataBusJava.getInstance().with("data2", String::class.java).observe(this, Observer() {
            Toast.makeText(this, "Java版本的观察者:${it}", Toast.LENGTH_SHORT).show()
            Log.d("abc", "Java版本的观察者:${it}")
        })

        thread {
            Thread.sleep(2000)
            OKLiveDataBusKT.with("data1", String::class.java).postValue("2222")
        }

        thread {
            Thread.sleep(4000)
            OkLiveDataBusJava.getInstance().with("data2", String::class.java).postValue("4444")
        }

    }
}
相关推荐
Kapaseker10 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
A0微声z2 天前
Kotlin Multiplatform (KMP) 中使用 Protobuf
kotlin
alexhilton3 天前
使用FunctionGemma进行设备端函数调用
android·kotlin·android jetpack
lhDream3 天前
Kotlin 开发者必看!JetBrains 开源 LLM 框架 Koog 快速上手指南(含示例)
kotlin
RdoZam3 天前
Android-封装基类Activity\Fragment,从0到1记录
android·kotlin
Kapaseker4 天前
研究表明,开发者对Kotlin集合的了解不到 20%
android·kotlin
糖猫猫cc4 天前
Kite:两种方式实现动态表名
java·kotlin·orm·kite
如此风景4 天前
kotlin协程学习小计
android·kotlin
Kapaseker5 天前
你搞得懂这 15 个 Android 架构问题吗
android·kotlin
zh_xuan5 天前
kotlin 高阶函数用法
开发语言·kotlin