LiveData和ViewModel源码学习

文章目录

        • LiveData
          • ObserverWrapper 数据观察者
          • LifecycleEventObserver 生命周期观察者
        • ViewModel
          • ViewModelStore
          • ViewModelProvider
          • ViewModelStoreOwner
          • ComponentActivity
          • NonConfigurationInstances
          • Activity attach 恢复
          • NonConfigurationInstances
          • ActivityThread performDestroyActivity 保存
          • ActivityClientRecord

LiveData
ObserverWrapper 数据观察者
LifecycleEventObserver 生命周期观察者
  1. 活跃状态接受并更新数据 刷新页面数据
  2. 非活跃状态暂停接收数据 防止崩溃,
  3. 销毁状态的时候移除观察者 防止内存泄漏
  4. 数据可以监听
  5. 数据倒灌,就是先发送数据,通过生命周期响应来触发change
  6. 数据粘性,先发送数据,后订阅的也能收到数据
  7. 为什么能感知生命周期和数据观察者 因为把传入的观察者通过LifecicleBoundObserver包了一层
    LifecicleBoundObserver继承了LifecicleEventObserver和ObserverWrapper,然后添加到lifecicle和livedata中
package androidx.lifecycle;import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.arch.core.executor.ArchTaskExecutor;
import androidx.arch.core.internal.SafeIterableMap;
import androidx.lifecycle.Lifecycle.State;
import java.util.Iterator;
import java.util.Map;public abstract class LiveData<T> {final Object mDataLock = new Object();static final int START_VERSION = -1;static final Object NOT_SET = new Object();private SafeIterableMap<Observer<? super T>, LiveData<T>.ObserverWrapper> mObservers = new SafeIterableMap();int mActiveCount = 0;private volatile Object mData;volatile Object mPendingData;private int mVersion;private boolean mDispatchingValue;private boolean mDispatchInvalidated;private final Runnable mPostValueRunnable;public LiveData(T value) {this.mPendingData = NOT_SET;this.mPostValueRunnable = new NamelessClass_1();this.mData = value;this.mVersion = 0;}public LiveData() {this.mPendingData = NOT_SET;class NamelessClass_1 implements Runnable {NamelessClass_1() {}public void run() {Object newValue;synchronized(LiveData.this.mDataLock) {newValue = LiveData.this.mPendingData;LiveData.this.mPendingData = LiveData.NOT_SET;}LiveData.this.setValue(newValue);}}this.mPostValueRunnable = new NamelessClass_1();this.mData = NOT_SET;this.mVersion = -1;}private void considerNotify(LiveData<T>.ObserverWrapper observer) {if (observer.mActive) {if (!observer.shouldBeActive()) {observer.activeStateChanged(false);} else if (observer.mLastVersion < this.mVersion) {observer.mLastVersion = this.mVersion;observer.mObserver.onChanged(this.mData);}}}void dispatchingValue(@Nullable LiveData<T>.ObserverWrapper initiator) {if (this.mDispatchingValue) {this.mDispatchInvalidated = true;} else {this.mDispatchingValue = true;do {this.mDispatchInvalidated = false;if (initiator != null) {this.considerNotify(initiator);initiator = null;} else {Iterator<Map.Entry<Observer<? super T>, LiveData<T>.ObserverWrapper>> iterator = this.mObservers.iteratorWithAdditions();while(iterator.hasNext()) {this.considerNotify((ObserverWrapper)((Map.Entry)iterator.next()).getValue());if (this.mDispatchInvalidated) {break;}}}} while(this.mDispatchInvalidated);this.mDispatchingValue = false;}}@MainThreadpublic void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {assertMainThread("observe");if (owner.getLifecycle().getCurrentState() != State.DESTROYED) {LiveData<T>.LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);LiveData<T>.ObserverWrapper existing = (ObserverWrapper)this.mObservers.putIfAbsent(observer, wrapper);if (existing != null && !existing.isAttachedTo(owner)) {throw new IllegalArgumentException("Cannot add the same observer with different lifecycles");} else if (existing == null) {owner.getLifecycle().addObserver(wrapper);}}}@MainThreadpublic void observeForever(@NonNull Observer<? super T> observer) {assertMainThread("observeForever");LiveData<T>.AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);LiveData<T>.ObserverWrapper existing = (ObserverWrapper)this.mObservers.putIfAbsent(observer, wrapper);if (existing instanceof LifecycleBoundObserver) {throw new IllegalArgumentException("Cannot add the same observer with different lifecycles");} else if (existing == null) {wrapper.activeStateChanged(true);}}@MainThreadpublic void removeObserver(@NonNull Observer<? super T> observer) {assertMainThread("removeObserver");LiveData<T>.ObserverWrapper removed = (ObserverWrapper)this.mObservers.remove(observer);if (removed != null) {removed.detachObserver();removed.activeStateChanged(false);}}@MainThreadpublic void removeObservers(@NonNull LifecycleOwner owner) {assertMainThread("removeObservers");Iterator var2 = this.mObservers.iterator();while(var2.hasNext()) {Map.Entry<Observer<? super T>, LiveData<T>.ObserverWrapper> entry = (Map.Entry)var2.next();if (((ObserverWrapper)entry.getValue()).isAttachedTo(owner)) {this.removeObserver((Observer)entry.getKey());}}}protected void postValue(T value) {boolean postTask;synchronized(this.mDataLock) {postTask = this.mPendingData == NOT_SET;this.mPendingData = value;}if (postTask) {ArchTaskExecutor.getInstance().postToMainThread(this.mPostValueRunnable);}}@MainThreadprotected void setValue(T value) {assertMainThread("setValue");++this.mVersion;this.mData = value;this.dispatchingValue((ObserverWrapper)null);}@Nullablepublic T getValue() {Object data = this.mData;return data != NOT_SET ? data : null;}int getVersion() {return this.mVersion;}protected void onActive() {}protected void onInactive() {}public boolean hasObservers() {return this.mObservers.size() > 0;}public boolean hasActiveObservers() {return this.mActiveCount > 0;}static void assertMainThread(String methodName) {if (!ArchTaskExecutor.getInstance().isMainThread()) {throw new IllegalStateException("Cannot invoke " + methodName + " on a background thread");}}private class AlwaysActiveObserver extends LiveData<T>.ObserverWrapper {AlwaysActiveObserver(Observer<? super T> observer) {super(observer);}boolean shouldBeActive() {return true;}}private abstract class ObserverWrapper {final Observer<? super T> mObserver;boolean mActive;int mLastVersion = -1;ObserverWrapper(Observer<? super T> observer) {this.mObserver = observer;}abstract boolean shouldBeActive();boolean isAttachedTo(LifecycleOwner owner) {return false;}void detachObserver() {}void activeStateChanged(boolean newActive) {if (newActive != this.mActive) {this.mActive = newActive;boolean wasInactive = LiveData.this.mActiveCount == 0;LiveData var10000 = LiveData.this;var10000.mActiveCount += this.mActive ? 1 : -1;if (wasInactive && this.mActive) {LiveData.this.onActive();}if (LiveData.this.mActiveCount == 0 && !this.mActive) {LiveData.this.onInactive();}if (this.mActive) {LiveData.this.dispatchingValue(this);}}}}class LifecycleBoundObserver extends LiveData<T>.ObserverWrapper implements LifecycleEventObserver {@NonNullfinal LifecycleOwner mOwner;LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {super(observer);this.mOwner = owner;}boolean shouldBeActive() {return this.mOwner.getLifecycle().getCurrentState().isAtLeast(State.STARTED);}public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {if (this.mOwner.getLifecycle().getCurrentState() == State.DESTROYED) {LiveData.this.removeObserver(this.mObserver);} else {this.activeStateChanged(this.shouldBeActive());}}boolean isAttachedTo(LifecycleOwner owner) {return this.mOwner == owner;}void detachObserver() {this.mOwner.getLifecycle().removeObserver(this);}}
}
ViewModel

1.为什么ViewModel生命周期比activity长
attach(Acitivity)->mLastNonConfigurationInstances(ActivityClientRecord)-> 恢复
performDestoryActivity(ActivityThread)-> retainNonConfigurationInstances(Activity)- onRetainConfigurationInstances(ComponentActivity)->mLastNonConfigurationInstances 保存

ViewModelStore
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package androidx.lifecycle;import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;public class ViewModelStore {private final HashMap<String, ViewModel> mMap = new HashMap();public ViewModelStore() {}final void put(String key, ViewModel viewModel) {ViewModel oldViewModel = (ViewModel)this.mMap.put(key, viewModel);if (oldViewModel != null) {oldViewModel.onCleared();}}final ViewModel get(String key) {return (ViewModel)this.mMap.get(key);}Set<String> keys() {return new HashSet(this.mMap.keySet());}public final void clear() {Iterator var1 = this.mMap.values().iterator();while(var1.hasNext()) {ViewModel vm = (ViewModel)var1.next();vm.clear();}this.mMap.clear();}
}
ViewModelProvider
package androidx.lifecycle;import android.app.Application;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import java.lang.reflect.InvocationTargetException;public class ViewModelProvider {private static final String DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey";private final Factory mFactory;private final ViewModelStore mViewModelStore;public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {this((ViewModelStore)owner.getViewModelStore(), (Factory)(owner instanceof HasDefaultViewModelProviderFactory ? ((HasDefaultViewModelProviderFactory)owner).getDefaultViewModelProviderFactory() : ViewModelProvider.NewInstanceFactory.getInstance()));}public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {this(owner.getViewModelStore(), factory);}public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {this.mFactory = factory;this.mViewModelStore = store;}@NonNull@MainThreadpublic <T extends ViewModel> T get(@NonNull Class<T> modelClass) {String canonicalName = modelClass.getCanonicalName();if (canonicalName == null) {throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");} else {return this.get("androidx.lifecycle.ViewModelProvider.DefaultKey:" + canonicalName, modelClass);}}@NonNull@MainThreadpublic <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {ViewModel viewModel = this.mViewModelStore.get(key);if (modelClass.isInstance(viewModel)) {if (this.mFactory instanceof OnRequeryFactory) {((OnRequeryFactory)this.mFactory).onRequery(viewModel);}return viewModel;} else {if (viewModel != null) {}if (this.mFactory instanceof KeyedFactory) {viewModel = ((KeyedFactory)((KeyedFactory)this.mFactory)).create(key, modelClass);} else {viewModel = this.mFactory.create(modelClass);}this.mViewModelStore.put(key, viewModel);return viewModel;}}public static class AndroidViewModelFactory extends NewInstanceFactory {private static AndroidViewModelFactory sInstance;private Application mApplication;@NonNullpublic static AndroidViewModelFactory getInstance(@NonNull Application application) {if (sInstance == null) {sInstance = new AndroidViewModelFactory(application);}return sInstance;}public AndroidViewModelFactory(@NonNull Application application) {this.mApplication = application;}@NonNullpublic <T extends ViewModel> T create(@NonNull Class<T> modelClass) {if (AndroidViewModel.class.isAssignableFrom(modelClass)) {try {return (ViewModel)modelClass.getConstructor(Application.class).newInstance(this.mApplication);} catch (NoSuchMethodException var3) {throw new RuntimeException("Cannot create an instance of " + modelClass, var3);} catch (IllegalAccessException var4) {throw new RuntimeException("Cannot create an instance of " + modelClass, var4);} catch (InstantiationException var5) {throw new RuntimeException("Cannot create an instance of " + modelClass, var5);} catch (InvocationTargetException var6) {throw new RuntimeException("Cannot create an instance of " + modelClass, var6);}} else {return super.create(modelClass);}}}public static class NewInstanceFactory implements Factory {private static NewInstanceFactory sInstance;public NewInstanceFactory() {}@NonNullstatic NewInstanceFactory getInstance() {if (sInstance == null) {sInstance = new NewInstanceFactory();}return sInstance;}@NonNullpublic <T extends ViewModel> T create(@NonNull Class<T> modelClass) {try {return (ViewModel)modelClass.newInstance();} catch (InstantiationException var3) {throw new RuntimeException("Cannot create an instance of " + modelClass, var3);} catch (IllegalAccessException var4) {throw new RuntimeException("Cannot create an instance of " + modelClass, var4);}}}abstract static class KeyedFactory extends OnRequeryFactory implements Factory {KeyedFactory() {}@NonNullpublic abstract <T extends ViewModel> T create(@NonNull String var1, @NonNull Class<T> var2);@NonNullpublic <T extends ViewModel> T create(@NonNull Class<T> modelClass) {throw new UnsupportedOperationException("create(String, Class<?>) must be called on implementaions of KeyedFactory");}}static class OnRequeryFactory {OnRequeryFactory() {}void onRequery(@NonNull ViewModel viewModel) {}}public interface Factory {@NonNull<T extends ViewModel> T create(@NonNull Class<T> var1);}
}
ViewModelStoreOwner
public interface ViewModelStoreOwner {@NonNullViewModelStore getViewModelStore();
}
ComponentActivity
NonConfigurationInstances
  @Nullablepublic final Object onRetainNonConfigurationInstance() {Object custom = this.onRetainCustomNonConfigurationInstance();ViewModelStore viewModelStore = this.mViewModelStore;NonConfigurationInstances nci;if (viewModelStore == null) {nci = (NonConfigurationInstances)this.getLastNonConfigurationInstance();if (nci != null) {viewModelStore = nci.viewModelStore;}}if (viewModelStore == null && custom == null) {return null;} else {nci = new NonConfigurationInstances();nci.custom = custom;nci.viewModelStore = viewModelStore;return nci;}}@NonNullpublic ViewModelStore getViewModelStore() {if (this.getApplication() == null) {throw new IllegalStateException("Your activity is not yet attached to the Application instance. You can't request ViewModel before onCreate call.");} else {if (this.mViewModelStore == null) {NonConfigurationInstances nc = (NonConfigurationInstances)this.getLastNonConfigurationInstance();if (nc != null) {this.mViewModelStore = nc.viewModelStore;}if (this.mViewModelStore == null) {this.mViewModelStore = new ViewModelStore();}}return this.mViewModelStore;}}@NonNullpublic ViewModelProvider.Factory getDefaultViewModelProviderFactory() {if (this.getApplication() == null) {throw new IllegalStateException("");} else {if (this.mDefaultFactory == null) {this.mDefaultFactory = new SavedStateViewModelFactory(this.getApplication(), this, this.getIntent() != null ? this.getIntent().getExtras() : null);}return this.mDefaultFactory;}}static final class NonConfigurationInstances {Object custom;ViewModelStore viewModelStore;NonConfigurationInstances() {}}
Activity attach 恢复
NonConfigurationInstances
	@UnsupportedAppUsagefinal void attach(Context context, ActivityThread aThread,Instrumentation instr, IBinder token, int ident,Application application, Intent intent, ActivityInfo info,CharSequence title, Activity parent, String id,NonConfigurationInstances lastNonConfigurationInstances,Configuration config, String referrer, IVoiceInteractor voiceInteractor,Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {mLastNonConfigurationInstances = lastNonConfigurationInstances;}NonConfigurationInstances retainNonConfigurationInstances() {Object activity = onRetainNonConfigurationInstance();NonConfigurationInstances nci = new NonConfigurationInstances();nci.activity = activity;nci.children = children;nci.fragments = fragments;nci.loaders = loaders;if (mVoiceInteractor != null) {mVoiceInteractor.retainInstance();nci.voiceInteractor = mVoiceInteractor;}return nci;}static final class NonConfigurationInstances {Object activity;HashMap<String, Object> children;FragmentManagerNonConfig fragments;ArrayMap<String, LoaderManager> loaders;VoiceInteractor voiceInteractor;}
ActivityThread performDestroyActivity 保存
   @UnsupportedAppUsagefinal ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,int configChanges, boolean getNonConfigInstance, String reason) {ActivityClientRecord r = mActivities.get(token);Class<? extends Activity> activityClass = null;if (localLOGV) Slog.v(TAG, "Performing finish of " + r);if (r != null) {activityClass = r.activity.getClass();r.activity.mConfigChangeFlags |= configChanges;if (finishing) {r.activity.mFinished = true;}performPauseActivityIfNeeded(r, "destroy");if (getNonConfigInstance) {try {r.lastNonConfigurationInstances= r.activity.retainNonConfigurationInstances();} catch (Exception e) {if (!mInstrumentation.onException(r.activity, e)) {throw new RuntimeException("Unable to retain activity "+ r.intent.getComponent().toShortString()+ ": " + e.toString(), e);}}}return r;}
ActivityClientRecord
	public static final class ActivityClientRecord {@UnsupportedAppUsagepublic IBinder token;Activity.NonConfigurationInstances lastNonConfigurationInstances;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/809086.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在Java中实现记录1000万用户连续7天登录的功能,可以使用Redis的Bitmap来跟踪每个用户的登录状态

在Java中实现记录1000万用户连续7天登录的功能&#xff0c;可以使用Redis的Bitmap来跟踪每个用户的登录状态。以下是一个简化的Java示例&#xff0c;使用了Jedis库作为Redis的Java客户端。 首先&#xff0c;确保你已经在项目中添加了Jedis的依赖。如果你使用Maven&#xff0c;…

【高端电流检测IC储能产品应用方案】耐压28V侧轨的电流检测芯片FP130A 应用于电脑电源,开关电源以及多口快充充电器,户外移动电源,适配器,电池充电器等

电流检测技术常用于高压短路保护、电机控制、DC/DC换流器、系统功耗管理、二次电池的电流管理、蓄电池管理等电流侦测等场景。对于大多数应用而言&#xff0c;都是间接测量电阻两端的跨压差来获取待测电流。 如下面的高端电流检测芯片FP130A&#xff0c;丝印是FC915。电路原理图…

MySQL数据库的详解(1)

DDL&#xff08;数据库操作&#xff09; 查询 查询所有数据库&#xff1a;show databases;当前数据库&#xff1a;select database(); 创建 创建数据库&#xff1a;create database [ if not exists] 数据库名 ; 使用 使用数据库&#xff1a;use 数据库名 ; 删除 删除数…

利用Python实现可视化交互界面:Dash

Dash是一个低代码数据框架&#xff0c;用Python实现可视化交互界面&#xff0c;不用写Javascript&#xff0c;开源&#xff0c;支持回调、HTML组件等功能。 安装 pip install dash使用 # Import packages from dash import Dash, html, dash_table, dcc, callback, Output, …

网络安全JavaSE第六天

7. 数组 7.3.5 数组排序 7.3.5.1 冒泡排序 冒泡排序的思路&#xff1a;相邻两个元素进行比较&#xff0c;如果前面元素比后面元素大就交换位置&#xff0c;每一趟执行完后&#xff0c; 就会得到最大的数。 排序过程分析&#xff1a; package com.openlab; /** * 冒泡排序 */…

Gin 相对 标准库 net/http的优势

这些优势主要体现在以下几个方面&#xff1a; 简洁的路由分组和中间件支持 Gin允许开发者使用简洁的API来定义路由&#xff0c;支持路由分组和中间件&#xff0c;这使得构建具有复杂路由规则的大型应用变得更加简单和高效。 参数化路由 Gin支持参数化路由&#xff0c;可以很容…

pyside6自定义部件库和软件框架的建设记录

一、自定义部件库 原则上尽量做到前后端分离&#xff0c;接口方便&#xff0c;复制简单。 1、单选框部件 # encoding: utf-8 ################################################### # 自定义的单选框 #################################################### 对外…

wsl2 arch linux访问ch340串口和usb设备

wsl2 arch linux访问ch340串口和usb设备 安装usb转网络软件usbipd共享usb到网络wsl2安装usbip挂载USB设备卸载USB设备 安装usb转网络软件usbipd 在powershell执行下面命令安装 winget install --interactive --exact dorssel.usbipd-win共享usb到网络 #查看USB设备 usbipd l…

基于模型预测算法的含储能微网双层能量管理模型

基于模型预测算法的含储能微网双层能量管理模型 文章目录 基于模型预测算法的含储能微网双层能量管理模型一、项目介绍二、源程序下载 一、项目介绍 代码主要做的是一个微网双层优化调度模型&#xff0c;微网聚合单元包括风电、光伏、储能以及超级电容器&#xff0c;在微网的运…

Go语言mac环境搭建详解

Go语言mac环境搭建详解见视频&#xff0c;视频下方也有讲解具体的操作步骤。 Golang Mac电脑环境搭建、开发工具Vscode配置 Go语言mac环境搭建步骤如下&#xff1a; 1、下载安装Golang Go官网下载地址&#xff1a;https://golang.org/dl/ Go官方镜像站&#xff08;推荐&…

Windows下如何确定DLL动态库是32位还是64位

文章目录 Windows下如何确定DLL动态库是32位还是64位使用dumpbin工具可能出现的问题结果输出内容 Windows下如何确定DLL动态库是32位还是64位 使用dumpbin工具 dumpbin.exe通常位于Visual Studio的安装目录下的VC\bin或VC\Tools\MSVC\<version>\bin\Hostx64\x64 比如&am…

海山数据库(He3DB)Redis技术实践:继承开源Redis精髓,强化升级企业级服务

数字化转型中的企业数据的处理速度和效率直接关系到企业的竞争力&#xff0c;Redis作为业界广泛使用的开源键值对存储系统&#xff0c;以其卓越的性能和丰富的数据结构&#xff0c;成为了众多开发者和企业的首选。然而&#xff0c;近期Redis开源社区对Redis协议进行了变更&…

电力综合自动化系统对电力储能技术的影响有哪些?

电力综合自动化系统对电力储能技术的影响主要体现在以下几个方面&#xff1a; 提高能源利用效率&#xff1a;电力综合自动化系统通过优化调度和能量管理&#xff0c;可以实现储能设备的有效利用&#xff0c;提高能源利用效率。在电力系统中&#xff0c;储能设备可以有效地平抑风…

第十一篇JavaScript JSON与AJAX

JSON 在JavaScript中&#xff0c;JSON&#xff08;JavaScript Object Notation&#xff09;是一种常用的数据格式&#xff0c;用于存储和交换数据。它基于JavaScript的对象字面量语法&#xff0c;但具有更宽松的语法规则。 json 是一种轻量级的数据交换格式。 JSON使用键值对…

贪心算法:排列算式

题目描述 给出n数字&#xff0c;对于这些数字是否存在一种计算顺序&#xff0c;使得计算过程中数字不会超过3也不会小于0&#xff1f; 输入描述: 首行给出一个正整数t,(1≤t≤1000)代表测试数据组数每组测试数据第一行一个正整数n,(1≤n≤500)第二行包含n个以空格分隔的数字…

Flutter - flutter_gen 资源管理

引言&#xff1a; 在开发 Flutter 应用时&#xff0c;我们经常需要使用各种静态资源&#xff0c;如图片、字体和音频等。如何有效地管理和加载这些资源呢&#xff1f;本篇博客将以图片为例带你解密 Flutter 项目中是如何管理资源地。 assets 加载资源 具体文件名引入 在工程…

STC89C52学习笔记(九)

STC89C52学习笔记&#xff08;九&#xff09; 综述&#xff1a;本文主要介绍了蜂鸣器、蜂鸣器如何使用以及如何利用蜂鸣器播放不同频率声音。 一、蜂鸣器 1.定义和作用 电信号→声音信号&#xff0c;常用来产生按键音和报警音。 2.分类 有源&#xff1a;自带振荡器&#…

机器学习 -- 端到端的机器学习项目

场景 我们将一个端到端的项目&#xff08;一个从开始到结束包含了所有必要步骤和组件的完整项目&#xff09;案例&#xff0c;步骤大概有&#xff1a; 1.观察大局。 2.获得数据。 3.从数据探索和可视化中获得洞见。 4.机器学习算法的数据准备。 5.选择和训练模型。 6.微调模型…

git lfs 大文件管理

简介 git-lfs 是 Git Large File Storage 的缩写&#xff0c;是 Git 的一个扩展&#xff0c;用于处理大文件的版本控制。 它允许你有效地管理和存储大型二进制文件&#xff0c;而不会使 Git 仓库变得过大和不稳定。以下是一些与 git-lfs 相关的常见命令和解释&#xff1a; 常…

Django的路由分组和路由转发器

02 查询文章信息 文章列表模板 复制zdpdjango_basic&#xff0c;然后在templates中新建一个articles.html文件&#xff0c;用来展示文章列表&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><tit…