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")
        }

    }
}
相关推荐
闲暇部落19 分钟前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
长亭外的少年16 小时前
Kotlin 编译失败问题及解决方案:从守护进程到 Gradle 配置
android·开发语言·kotlin
JIAY_WX16 小时前
kotlin
开发语言·kotlin
麦田里的守望者江1 天前
KMP 中的 expect 和 actual 声明
android·ios·kotlin
菠菠萝宝1 天前
【YOLOv8】安卓端部署-1-项目介绍
android·java·c++·yolo·目标检测·目标跟踪·kotlin
恋猫de小郭1 天前
Kotlin Multiplatform 未来将采用基于 JetBrains Fleet 定制的独立 IDE
开发语言·ide·kotlin
枫__________2 天前
kotlin 协程 job的cancel与cancelAndJoin区别
android·开发语言·kotlin
鸠摩智首席音效师2 天前
如何在 Ubuntu 上配置 Kotlin 应用环境 ?
linux·ubuntu·kotlin
jikuaidi6yuan4 天前
Java与Kotlin在鸿蒙中的地位
java·kotlin·harmonyos
liulanba4 天前
Kotlin的data class
前端·微信·kotlin