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

    }
}
相关推荐
有点感觉1 天前
Android级联选择器,下拉菜单
kotlin
zhangphil1 天前
Android Coil3缩略图、默认占位图placeholder、error加载错误显示,Kotlin(1)
android·kotlin
xvch2 天前
Kotlin 2.1.0 入门教程(二十三)泛型、泛型约束、协变、逆变、不变
android·kotlin
xvch3 天前
Kotlin 2.1.0 入门教程(二十四)泛型、泛型约束、绝对非空类型、下划线运算符
android·kotlin
zhangphil4 天前
Android Coil ImageLoader MemoryCache设置Key与复用内存缓存,Kotlin
android·kotlin
mmsx4 天前
kotlin Java 使用ArrayList.add() ,set()前面所有值被 覆盖 的问题
android·开发语言·kotlin
lavins4 天前
android studio kotlin项目build时候提示错误 Unknown Kotlin JVM target: 21
jvm·kotlin·android studio
面向未来_4 天前
JAVA Kotlin Androd 使用String.format()格式化日期
java·开发语言·kotlin
alexhilton4 天前
选择Retrofit还是Ktor:给Android开发者的指南
android·kotlin·android jetpack
GordonH19914 天前
Kotlin 优雅的接口实现
android·java·kotlin