当前位置: 首页 > news >正文

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

目录

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

一、LiveData的基本使用

1. 使用方式一

MyLiveData.kt

package com.example.mylivedata.simple1import androidx.lifecycle.MutableLiveDataobject MyLiveData {  // 单例// 懒加载val info : MutableLiveData<String> by lazy { MutableLiveData<String>() }
}

MainActivity.kt

package com.example.mylivedata.simple1import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
import androidx.lifecycle.Observer
import com.example.mylivedata.R
import kotlin.concurrent.threadclass 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.simple2import androidx.lifecycle.MutableLiveDataobject 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.simple2import 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? = nulloverride 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.simple2import 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.simple3import androidx.lifecycle.MutableLiveDataobject MyLiveData {// 这里的data的MutableLiveData 懒加载初始化(懒加载:用到时才加载)val data : MutableLiveData<String> by lazy { MutableLiveData<String>() }}

MainActivity3.kt

package com.example.mylivedata.simple3import android.content.Intent
import android.os.Bundle
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import com.example.mylivedata.Rclass 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.simple3import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import com.example.mylivedata.Rclass 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> {@Overridepublic 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中的valueObject 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.得到mVersionField mVersion = liveDataClass.getDeclaredField("mVersion");mVersion.setAccessible(true);// TODO 3.mLastVersion = mVersionObject mVersionValue = mVersion.get(this);mLastVersion.set(observerWrapper, mVersionValue);} catch (Exception e) {e.printStackTrace();}}}
}

2. 去除黏性的Kotlin版本

OKLiveDataBusKT.kt

package com.example.mylivedata.simple4import 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.javaval mObserversField = liveDataClass.getDeclaredField("mObservers")mObserversField.isAccessible = true  // 私有修饰可以访问// 获取到这个成员变量的对象 Kotlin Any == Java Objectval 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中的valuevar observerWrapper : Any? = nullif (invokeEntry != null && invokeEntry is Map.Entry<*, *>) {observerWrapper = invokeEntry.value}if (observerWrapper == null) {throw NullPointerException("observerWrapper is null")}// 得到observerWrapper的类对象val supperClass : Class<*> = observerWrapper.javaClass.superclassval mLastVersion : Field = supperClass.getDeclaredField("mLastVersion")mLastVersion.isAccessible = true// TODO 2.得到mVersionval mVersion : Field = liveDataClass.getDeclaredField("mVersion")mVersion.isAccessible = true// TODO 3.mLastVersion = mVersionval mVersionValue = mVersion.get(this)mLastVersion.set(observerWrapper, mVersionValue)}}
}

MainActivity.kt

package com.example.mylivedata.simple4import android.content.Intent
import android.os.Bundle
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import com.example.mylivedata.Rclass 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数据"// 点击事件,跳转到下一个Activityval button = findViewById<Button>(R.id.button)button.setOnClickListener {startActivity(Intent(this, MainActivity2::class.java))}}
}

MainActivity2.kt

package com.example.mylivedata.simple4import 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.threadclass 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")}}
}

相关文章:

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

目录 一、LiveData的基本使用1. 使用方式一2. 使用方式二3. 使用方式三 二、LiveData 去除黏性数据的方法1. 去除黏性的Java版本2. 去除黏性的Kotlin版本 一、LiveData的基本使用 1. 使用方式一 MyLiveData.kt package com.example.mylivedata.simple1import androidx.lifec…...

【MegaCli】安装MegaCli后执行报参数错误

问题: 刚安装好Mega后执行报错 /opt/MegaRAID/MegaCli/MegaCli64 Fatal error - Command Tool invoked with wrong parameters Exit Code: 0x01 /opt/MegaRAID/MegaCli/MegaCli64 Fatal error - Command Tool invoked with wrong parameters Exit Code: 0x01原因&#xff1a;…...

时间范围选择时选中日期所使用的当日内具体时刻 如00:00:00= 23:59:59

<el-form-item label"审核时间&#xff1a;"><el-date-pickerv-model"auditTime"type"datetimerange"range-separator"至"value-format"yyyy-MM-dd HH:mm:ss"start-placeholder"开始日期"end-placeholde…...

算法面试-深度学习面试题整理(2024.8.29开始,每天下午持续更新....)

一、无监督相关&#xff08;聚类、异常检测&#xff09; 1、常见的距离度量方法有哪些&#xff1f;写一下距离计算公式。 1&#xff09;连续数据的距离计算&#xff1a; 闵可夫斯基距离家族&#xff1a; 当p 1时&#xff0c;为曼哈顿距离&#xff1b;p 2时&#xff0c;为欧…...

Maven之高版本的 lombok 和 tomcat 7 插件冲突问题

高版本的 lombok 和 tomcat 7 插件冲突问题 在开发期间&#xff0c;当我们使用 tomcat7-maven-plugin 来作为运行环境运行我们项目使&#xff0c;如果我们项目中使用了 1.16.20 及以上版本的 lombok 包&#xff0c;项目启动时会报错&#xff1a; for annotations org.apache.…...

微信小程序申请

方案说明&#xff1a; 微信小程序申请步骤有两个过程&#xff0c;目前采用的是第二种方案 第一种方案&#xff1a;直接向微信申请微信小程序 第二种方案&#xff1a;先申请公众号后再通过公众号快速注册并申请小程序 无论申请公众号还是小程序都需要微信认证&#xff0c;微…...

ffmpeg 配合Fiddler抓包操作

首先需要安装和配置ffmpeg 1.扩大音频2倍 ffmpeg -i 2.mp3 -filter:a "volume2.0" 3.mp32.扩大音频4倍 ffmpeg -i 2.mp3 -filter:a "volume4.0" 3.mp33.音视频合成&#xff08;m4s视频和mp3音频合成&#xff09; ffmpeg -i 1.m4s -i 3.mp3 -vcodec cop…...

美团面试拷打:ConcurrentHashMap 为何不能插入 null?HashMap 为何可以?

周末的时候,有一位小伙伴提了一些关于 ConcurrentHashMap 的问题,都是他最近面试遇到的。原提问如下(星球原贴地址:https://t.zsxq.com/11jcuezQs ): 整个提问看着非常复杂,其实归纳来说就是两个问题: ConcurrentHashMap 为什么 key 和 value 不能为 null?ConcurrentH…...

【力扣每日一题】2023.8.29 带因子的二叉树

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目给我们一些元素&#xff0c;让我们用这些元素连接形成特定的二叉树&#xff0c;每种元素可以使用任意次数&#xff0c;形成的二叉树要…...

origin导出pdf曲线超出边框

软件版本 软件版本Word2021Origin2021Adobe Acrobat Pro2023 问题描述 Origin导出的emf格式矢量图片&#xff0c;插入到Word中&#xff0c;显示正常&#xff0c;但是在使用Word导出→创建Adobe PDF→创建Adobe PDF导出PDF文件后&#xff0c;图片曲线就会超出边框&#xff0c…...

由Android10适配到Android12时遇到相关编译失败问题

最近Android系统各大应用商店联合发出公告&#xff0c;处于个人隐私安全考虑&#xff0c;强制APP适配到Android 11及以上版本。下面是其中应用市场的公告&#xff08;顺带提醒没适配的同学&#xff09;&#xff1a; 适配前的开发环境 名称版本Android studioGiraffe | 2022.3…...

高职教育应对ChatGPT应用的策略

一、完善顶层设计&#xff0c;提升技术水平 在推广ChatGPT平台的过程中&#xff0c;高职院校需要关注技术本身的问题。这就需要在国家和地方政府的引导下&#xff0c;引入更完善的技术顶层设计&#xff0c;提高人工智能在高职教育中的运用水平。具体来说&#xff0c;一方面需要…...

Linux 内核编译参数

文章目录 前言1 -Wall2 -Wundef3 -Wstrict-prototypes4 -Wno-trigraphs5 -fno-strict-aliasing6 -fno-common7 -Werror-implicit-function-declaration8 -Wno-format-security9 -fno-delete-null-pointer-checks10 -stdgnu89 前言 # cat /etc/os-release NAME"CentOS Lin…...

vscode使用anaconda自带的python环境在终端运行时报错

目录 具体报错内容官方翻译报错讲人话解决方法 具体报错内容 CommandNotFoundError: Your shell has not been properly configured to use conda activate. If your shell is Bash or a Bourne variant, enable conda for the current user with$ echo ". E:\Anaconda/e…...

葡萄叶病害识别(图像连续识别和视频识别,Python代码,pyTorch框架)

葡萄叶病害识别&#xff08;图像连续识别和视频识别&#xff0c;Python代码&#xff0c;pyTorch框架&#xff09;_哔哩哔哩_bilibili 葡萄数据集 第一个文件夹为 Grape Black Measles&#xff08;葡萄黑麻疹&#xff09;病害&#xff08;3783张&#xff09; Grape Black rot葡…...

Oracle drop删除表如何恢复

摘要&#xff1a; 在 Oracle 数据库管理中&#xff0c;DROP 命令的误操作可能导致数据不可挽回的丢失。然而&#xff0c;Oracle 提供了回收站&#xff08;recycle bin&#xff09;功能&#xff0c;允许用户在删除对象后的一段时间内恢复它们。本文将介绍如何查询、启用和管理回…...

5、监测数据采集物联网应用开发步骤(5.1)

监测数据采集物联网应用开发步骤(4) Sqlite3数据库读写操作开发、异常信息统一处理类开发 本章节需要调用sqlite3及mysql-connector 安装sqlite3 Pip3 install sqlite3 安装mysql-connector pip3 install mysql-connector 验证是否安装成功&#xff0c;python中运行下列…...

ZZULIOJ 1148: 组合三位数之一,Java

ZZULIOJ 1148: 组合三位数之一&#xff0c;Java 题目描述 把1、2、3、4、5、6、7、8、9组合成3个3位数&#xff0c;要求每个数字仅使用一次&#xff0c;使每个3位数均为完全平方数。按从小到大的顺序输出这三个三位数。 输入 无 输出 按从小到大的顺序输出这三个三位数&a…...

ROS功能包目录下CMakeLists.txt

1. add_execuble CMake基础教程&#xff08;24&#xff09;add_executable生成目标可执行文件 CMake中add_executable的使用 CMake中的add_executable命令用于使用指定的源文件向项目(project)添加可执行文件&#xff0c;其格式如下&#xff1a; add_executable(<name>…...

Python爬虫追踪新闻事件发展进程及舆论反映

目录 实现方案 1. 确定目标新闻源&#xff1a; 2. 确定关键词&#xff1a; 3. 使用网络爬虫获取新闻内容&#xff1a; 4. 提取和分析新闻文章&#xff1a; 5. 追踪新闻事件的发展进程&#xff1a; 6. 监测舆论反映&#xff1a; 7. 数据可视化&#xff1a; 完整代码示例…...

Prometheus数据采集扩展:claw-prometheus项目详解与实战

1. 项目概述&#xff1a;一个为Prometheus量身定制的“数据抓取器”在云原生和微服务架构大行其道的今天&#xff0c;监控系统的地位不言而喻。Prometheus&#xff0c;作为这个领域的“事实标准”&#xff0c;以其强大的多维数据模型和灵活的查询语言&#xff08;PromQL&#x…...

基于MCP协议构建Python文档智能查询服务器,提升AI编程助手准确性

1. 项目概述&#xff1a;一个为Python开发者量身定制的文档智能助手如果你和我一样&#xff0c;每天大部分时间都在和Python代码打交道&#xff0c;那你肯定也经历过这样的场景&#xff1a;为了查一个函数的参数顺序&#xff0c;或者确认某个库的版本兼容性&#xff0c;不得不频…...

JSON Lint深度解析:如何用PHP实现专业级JSON验证与错误处理

JSON Lint深度解析&#xff1a;如何用PHP实现专业级JSON验证与错误处理 【免费下载链接】jsonlint JSON Lint for PHP 项目地址: https://gitcode.com/gh_mirrors/jso/jsonlint 在当今数据驱动的Web开发中&#xff0c;JSON已成为数据交换的标准格式。然而&#xff0c;当…...

用Adafruit MONSTER M4SK改造Boglin玩具:赋予经典怪物互动电子眼

1. 项目概述&#xff1a;当经典玩具遇上开源硬件如果你和我一样&#xff0c;对上世纪80年代那些造型古怪、充满想象力的玩具情有独钟&#xff0c;同时又是个喜欢动手折腾的创客&#xff0c;那么这个项目绝对能让你兴奋起来。今天我们要聊的&#xff0c;是如何让一个几乎被遗忘的…...

KafClaw:Apache Kafka增强型命令行客户端,提升数据操作与调试效率

1. 项目概述与核心价值最近在开源社区里&#xff0c;KafClaw 这个项目引起了不少关注。乍一看这个名字&#xff0c;你可能会联想到 Apache Kafka 和某种“爪子”&#xff08;Claw&#xff09;的结合&#xff0c;没错&#xff0c;这正是它的精髓所在。KafClaw 本质上是一个针对 …...

Armbian重置前的数据保卫战——备份与迁移的5层防护策略

备份就像买保险——平时觉得麻烦,出事时觉得买少了。 引言:那个让我彻夜未眠的晚上 凌晨三点,我的香橙派突然失联了。 SSH连不上,ping不通,插显示器一看——文件系统只读,内核panic。前一天刚折腾完Docker网络配置,手贱改了个内核参数,重启后直接翻车。 那一刻,我脑…...

METSO A413150输出模块

METSO A413150 是美卓&#xff08;Metso Automation&#xff09;BIU 8 分布式控制系统中的一款输出模块&#xff0c;主要用于向现场执行机构输出模拟量控制信号。中间15个特点METSO A413150 提供8通道模拟量输出&#xff0c;适用于多路控制信号输出。该模块分辨率为16位&#x…...

Smoothieware 分支固件编译与配置项深度解析

1. Smoothieware分支固件编译全流程实战 第一次接触Smoothieware_best-for-pnp这个分支时&#xff0c;我完全没想到一个开源3D打印机固件能有这么多隐藏玩法。这个由社区开发者维护的分支&#xff0c;在保留官方核心功能的同时&#xff0c;针对OpenPNP应用场景做了大量优化。最…...

AMD Ryzen终极调试指南:7步解锁SMUDebugTool硬件级控制

AMD Ryzen终极调试指南&#xff1a;7步解锁SMUDebugTool硬件级控制 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: https://g…...

如何在IDEA中打造你的私人阅读空间:3个实用技巧提升编程效率与阅读体验

如何在IDEA中打造你的私人阅读空间&#xff1a;3个实用技巧提升编程效率与阅读体验 【免费下载链接】thief-book-idea IDEA插件版上班摸鱼看书神器 项目地址: https://gitcode.com/gh_mirrors/th/thief-book-idea 在快节奏的编程工作中&#xff0c;如何有效利用碎片化时…...