JetPack之ViewModel+LiveData

目录

  • 一、概述
  • 二、LiveData 使用
    • 2.1 创建 LiveData 对象
    • 2.2 观察 LiveData 对象
    • 2.3 更新 LiveData 对象
  • 三、编写 LiveData Demo
    • 3.1 不使用 LiveData
    • 3.2 使用 MutableLiveData
    • 3.3 使用 MediatorLiveData
      • 3.3.1 监听 2 个数据源的变化
      • 3.3.2 编写模拟 2 个数据源更新的代码
  • 四、ViewModel 使用
    • 4.1 创建 ViewModel 类
    • 4.2 在 Activity 中使用
  • 五、ViewModel+LiveData
    • 5.1 在 ViewModel 中增加 LiveData
    • 5.2 在 ViewModel 中添加操作数据的逻辑
    • 5.3 修改 MainActivity 中和 liveData 有关的代码
    • 5.4 修改 MyViewModel
    • 5.5 修改后
      • 5.5.1 修改后MainActivity
      • 5.5.2 修改后MyViewModel
  • 六、总结


一、概述

之前单独介绍过ViewModel和LiveData,但是没有将两者结合使用。
JetPack之ViewModel
JetPack之LiveData
ViewModel 对象为特定的界面组件(如 Fragment 或 Activity)提供数据,并包含数据处理业务逻辑,会配合 LiveData 一起使用。
LiveData 是一种可观察的数据存储器类, LiveData 使用观察者模式,每当数据发生变化时, LiveData 会通知 Observer 对象,可以在这些 Observer 对象中更新 UI。
接下来,先介绍如果使用 LiveData,并编写一个 LiveData Demo,接着再结合ViewModel 对 LiveData Demo 的代码进行重构


二、LiveData 使用

LiveData< T>是一个抽象类,它有 2 个子类分别是: MutableLiveData和MediatorLiveData< T>,在编写代码时,是创建的子类。先来看MutableLiveData< T>使用方法,在后面的示例中再介绍如何使用 MediatorLiveData< T>

2.1 创建 LiveData 对象

如果要观察的对象类为 String,就通过如下代码创建一个 MutableLiveData 对象

MutableLiveData< String> liveData = new MutableLiveData<>();

2.2 观察 LiveData 对象

通过 observe 方法来监听 LiveData 的数据变化,每当 LiveData 发生变化时,都会回调
onChanged 方法,并返回值的内容 String s

liveData.observe(this, new Observer< String>() {
@Override
public void onChanged(String s) {
Log.i(TAG, "onChanged: " + s)
   	}
});

2.3 更新 LiveData 对象

通过 LiveData 的 setValue 方法,给 LiveData 赋值,每次赋完值后,都会回调 onChanged 方法

liveData.setValue("add for test");

当给 LiveData 赋值为"add for test"时, onChanged 会输出日志:

I/LiveDataDemo: onChanged: add for test

三、编写 LiveData Demo

创建一个 Demo,主界面只有一个 TextView, TextView 用作展示一个数字,这个数字会从 59 开始显示,然后每隔 1 秒数字会减 1,直到数字变为 0。

3.1 不使用 LiveData

代码说明:
1、在 MainActivity 增加一个 countDown 的方法,通过 CountDownTimer 创建一个倒计时器
2、 new CountDownTimer(1 * 60 * 1000, 1 * 1000)中 2 个参数的含义:第一个参数表示这个 Timer 的总时长为 60 秒;第 2 个参数表示每隔 1 秒中会更新一次,并回调 onTick方法
3、每次调用 onTick 方法,会调用 textView.setText(String.valueOf(l / 1000));设置一次TextView 的内容
对应代码如下:

public class MainActivity extends AppCompatActivity {

    private TextView textView;

    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.textView);
        countDown();
    }

    private void countDown() {
        new CountDownTimer(1 * 60 * 1000, 1 * 1000) {
            @Override
            public void onTick(long l) {
                textView.setText(String.valueOf(l / 1000));
            }

            @Override
            public void onFinish() {
            }
        }.start();
    }
}

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

效果:
在这里插入图片描述
弊端:
业务逻辑(倒计时的功能)和 UI 逻辑(TextView 更新)没有分开,耦合到一起了

3.2 使用 MutableLiveData

为了方便演示,直接在 MainActivity 中操作 LiveData,实际项目中不要这样编写代码,应该把LiveData 放到 ViewModel 中
Google 推荐的使用 LiveData 的方法:
在这里插入图片描述

代码说明:
1、在 MainActivity 中增加一个 long 类型的 MutableLiveData
2、每次回调 onTick 方法时,调用 liveData.setValue(l);,把最新的值设置给 LiveData
3、调用 LivewData 的 observe 方法,设置一个监听器,每当 LiveData 的值变化时,会回调 onChanged 方法,在 onChanged 中设置 TextView 的内容
对应代码如下:

public class MainActivity extends AppCompatActivity {

    private final MutableLiveData<Long> liveData = new MutableLiveData<>();
    private TextView textView;

    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.textView);
        countDown();
        // TODO:为了方便演示,直接在 MainActivity 中操作 LiveData,实际项目中不要这样编写代码,应该把 LiveData 放到 ViewModel 中
        liveData.observe(this, new Observer<Long>() {
            @Override
            public void onChanged(Long aLong) {
                textView.setText(String.valueOf(aLong / 1000));
            }
        });
        countDown();
    }


    public void countDown() {
        new CountDownTimer(1 * 60 * 1000, 1 * 1000) {
            @Override
            public void onTick(long l) {
                // TODO:为了方便演示,直接在 MainActivity 中操作 LiveData,实际项目中不要这样编写代码,应该把 LiveData 放到 ViewModel 中
                liveData.setValue(l);
            }

            @Override
            public void onFinish() {
            }
        }.start();
    }

}

效果与上面一样。

3.3 使用 MediatorLiveData

MediatorLiveData 可以合并多个 LiveData 源,只要任何原始的 LiveData 源对象发生更改,就会触发 MediatorLiveData 对象的观察者。
例如,如果界面中有可以从本地数据库或网络更新的 LiveData 对象,则可以向MediatorLiveData 对象添加以下源:

与存储在数据库中的数据关联的LiveData 对象。
与从网络访问的数据关联的LiveData 对象。

Activity 只需观察 MediatorLiveData 对象即可从这两个源接收更新。接下来,实现这个例子。

3.3.1 监听 2 个数据源的变化

代码说明如下:
1、创建 1 个 MediatorLiveData< String>对象
2、创建 2 个MutableLiveData: liveData1 表示网络数据源, liveData2 表示本地数据源
3、调用 MediatorLiveData 的 addSource 方法,分别将 liveData1 和 liveData2 加到 MediatorLiveData 要监听的数据源中
4、设置 MediatorLiveData 的监听,当 2 个数据源发生变化时,会回调onChanged 方法,并将变化的内容展示到 TextView 上

3.3.2 编写模拟 2 个数据源更新的代码

编写一个 mergeTes 的方法,里面创建了 2 个 Timer,用作模拟网络数据更新和本地数据更新的情况,每隔 3 秒会往网络数据 liveData1 设置值、每隔 10 秒会往本地数据liveData2 设置值。
完整代码如下

public class MainActivity extends AppCompatActivity {

    private TextView textView;
    private MutableLiveData< String> liveData1 = new MutableLiveData<>();
    private MutableLiveData< String> liveData2 = new MutableLiveData<>();
    final MediatorLiveData< String> liveDataMerger = new MediatorLiveData<>();
    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.textView);

        liveDataMerger.addSource(liveData1, new Observer< String>() {
            @Override
            public void onChanged(String s) {
                liveDataMerger.setValue(s);
            }
        });
        liveDataMerger.addSource(liveData2, new Observer< String>() {
            @Override
            public void onChanged(String s) {
                liveDataMerger.setValue(s);
            }});
        liveDataMerger.observe(this, new Observer< String>() {
            @Override
            public void onChanged(String s) {
                textView.setText(s);
            }
        });
        mergeTest();
    }



    public void mergeTest() {
        new CountDownTimer(1 * 60 * 1000, 3 * 1000) {
            @Override
            public void onTick(long l) {
                liveData1.setValue("网络有数据更新了" + l/1000);
            }
            @Override
            public void onFinish() {
            }
        }.start();
        new CountDownTimer(1 * 60 * 1000, 10 * 1000) {
            @Override
            public void onTick(long l) {
                liveData2.setValue("本地数据库更新了" + l/1000);
            }
            @Override
            public void onFinish() {
            }
        }.start();
    }
}

运行效果

在这里插入图片描述

四、ViewModel 使用

4.1 创建 ViewModel 类

创建一个 MyViewModel 类,继承自 ViewModel

import androidx.lifecycle.ViewModel;
public class MyViewMode extends ViewModel {

}

4.2 在 Activity 中使用

    public class MainActivity extends AppCompatActivity {
        private MyViewModel viewModel;
        @Overrideprotected
        void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            viewModel = new ViewModelProvider(this).get(MyViewModel.class);
        }
    }

五、ViewModel+LiveData

5.1 在 ViewModel 中增加 LiveData

在 MyViewModel 中增加 3 个 MutableLiveData,分别对应在 MainActivity 中使用到的。
并编写这 3 个 LiveData 的 get 方法

public class MyViewModel extends ViewModel {

    private MutableLiveData<Long> liveData = new MutableLiveData<>();
    private MutableLiveData<String> liveData1 = new MutableLiveData<>();
    private MutableLiveData<String> liveData2 = new MutableLiveData<>();

    public MutableLiveData<Long> getLiveData() {
        return liveData;
    }

    public MutableLiveData<String> getLiveData1() {
        return liveData1;
    }

    public MutableLiveData<String> getLiveData2() {
        return liveData2;
    }

}

5.2 在 ViewModel 中添加操作数据的逻辑

countDown、 mergeTest 这 2 个方法在操作数据,从 MainActivity 中把这 2 个方法copy 到 MyViewModel 中

    public void countDown() {
        new CountDownTimer(1 * 60 * 1000, 1 * 1000) {
            @Override
            public void onTick(long l) {

                liveData.postValue(l);
            }

            @Override
            public void onFinish() {
            }
        }.start();
    }

    public void mergeTest() {
        new CountDownTimer(1 * 60 * 1000, 3 * 1000) {
            @Override
            public void onTick(long l) {
                liveData1.postValue("网络有数据更新了" + l / 1000);
            }

            @Override
            public void onFinish() {
            }
        }.start();
        new CountDownTimer(1 * 60 * 1000, 10 * 1000) {
            @Override
            public void onTick(long l) {
                liveData2.postValue("本地数据库更新了" + l / 1000);
            }

            @Override
            public void onFinish() {
            }
        }.start();
    }

5.3 修改 MainActivity 中和 liveData 有关的代码

1、删除 countDown,改用 viewModel.countDown();

    MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class);
    viewModel.countDown();

2、用 viewModel.getLiveData().observe 替换 liveData.observe

    viewModel.getLiveData().observe(this, new Observer<Long>() {
        @Override
        public void onChanged(Long aLong) {
            textView.setText(String.valueOf(aLong / 1000));
        }
    });

5.4 修改 MyViewModel

增加 liveDataMerger 字段,并编写 getLiveDataMerger()方法,这个方法里面的内容,是从 MainActivity 中 copy 过来的

public class MyViewModel extends ViewModel {

    private MediatorLiveData<String> liveDataMerger;

    private MutableLiveData<Long> liveData = new MutableLiveData<>();
    private MutableLiveData<String> liveData1 = new MutableLiveData<>();
    private MutableLiveData<String> liveData2 = new MutableLiveData<>();

    public MediatorLiveData<String> getLiveDataMerger() {
        if (liveDataMerger == null) {
            liveDataMerger = new MediatorLiveData<>();
        }
        liveDataMerger.addSource(liveData1, new Observer<String>() {
            @Override
            public void onChanged(String s) {

                liveDataMerger.setValue(s);
            }
        });
        liveDataMerger.addSource(liveData2, new Observer<String>() {
            @Override
            public void onChanged(String s) {

                liveDataMerger.setValue(s);
            }
        });
        return liveDataMerger;
    }
.........

5.5 修改后

5.5.1 修改后MainActivity

public class MainActivity extends AppCompatActivity {

    private TextView textView;
    private MyViewModel viewModel;

    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.textView);
        viewModel = new ViewModelProvider(this).get(MyViewModel.class);

        viewModel.getLiveDataMerger().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                textView.setText(s);
            }
        });
        viewModel.mergeTest();
//        viewModel.getLiveData().observe(this, new Observer<Long>() {
//            @Override
//            public void onChanged(Long aLong) {
//                textView.setText(String.valueOf(aLong / 1000));
//            }
//        });
//        viewModel.countDown();
    }
}

5.5.2 修改后MyViewModel

public class MyViewModel extends ViewModel {
    private MutableLiveData<Long> liveData = new MutableLiveData<>();
    private MutableLiveData<String> liveData1 = new MutableLiveData<>();
    private MutableLiveData<String> liveData2 = new MutableLiveData<>();
    private MediatorLiveData<String> liveDataMerger;

    public MediatorLiveData<String> getLiveDataMerger() {
        if (liveDataMerger == null) {
            liveDataMerger = new MediatorLiveData<>();
        }
        liveDataMerger.addSource(liveData1, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                liveDataMerger.setValue(s);
            }
        });
        liveDataMerger.addSource(liveData2, new Observer<String>() {
            @Override
            public void onChanged(String s) {

                liveDataMerger.setValue(s);
            }
        });
        return liveDataMerger;
    }

    public MutableLiveData<Long> getLiveData() {
        return liveData;
    }

    public MutableLiveData<String> getLiveData1() {
        return liveData1;
    }

    public MutableLiveData<String> getLiveData2() {
        return liveData2;
    }

    public void countDown() {
        new CountDownTimer(1 * 60 * 1000, 1 * 1000) {
            @Override
            public void onTick(long l) {

                liveData.postValue(l);
            }

            @Override
            public void onFinish() {
            }
        }.start();
    }

    public void mergeTest() {
        new CountDownTimer(1 * 60 * 1000, 3 * 1000) {
            @Override
            public void onTick(long l) {
                liveData1.postValue("网络有数据更新了" + l / 1000);
            }

            @Override
            public void onFinish() {
            }
        }.start();
        new CountDownTimer(1 * 60 * 1000, 10 * 1000) {
            @Override
            public void onTick(long l) {
                liveData2.postValue("本地数据库更新了" + l / 1000);
            }

            @Override
            public void onFinish() {
            }
        }.start();
    }
}

六、总结

ViewModel 和 LiveData 结合使用的一些好处:

  • 生命周期感知:ViewModel 和 LiveData 都是生命周期感知的组件,它们可以在界面控制器(如 Activity 或 Fragment)的生命周期变化时自动调整其行为。这意味着可以在 ViewModel 中存储和管理数据,而 LiveData 可以通知观察者(如界面控制器)数据的变化。
  • 数据持久性:ViewModel 和 LiveData 结合使用可以确保数据在配置更改(如屏幕旋转)时得以保留。ViewModel 会在界面控制器销毁和重新创建时保持数据不变,而 LiveData 可以通知观察者更新数据。
  • 避免内存泄漏:ViewModel 和 LiveData 的结合使用有助于避免内存泄漏问题。ViewModel 不持有对界面控制器的引用,而 LiveData 会自动处理观察者的生命周期,从而避免因观察者未及时取消注册而导致的内存泄漏。
  • 数据更新通知:LiveData 可以实现数据的观察和更新,当数据发生变化时,LiveData 会通知所有观察者进行相应的更新操作。这样可以确保界面与数据保持同步,提升用户体验。
  • 简化异步操作:LiveData 可以结合 ViewModel 使用,帮助简化异步操作和数据加载过程。可以在 ViewModel 中处理异步操作,然后通过 LiveData 将结果传递给观察者,从而实现响应式编程。
  • 解耦数据和界面:ViewModel 和 LiveData 的结合使用有助于将数据逻辑与用户界面分离,使代码更易于维护和测试。ViewModel 中的数据可以供多个界面控制器共享,避免重复加载数据。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

奇门辅助软件v2024.5

废话不说&#xff0c;先上链接 链接&#xff1a;https://pan.baidu.com/s/1_i11lMx4P_vrTs-6lpWoHA?pwd8v1m 提取码&#xff1a;8v1m 功能介绍 【宫内信息】是点击宫内某属性时显示的宫内基本信息。 【古籍宝鉴】是《御定奇门宝鉴》里的对应时局内容&#xff0c;但差补法置…

YashanDB与帆软信创商业智能软件完成兼容互认证

近日&#xff0c;深圳计算科学研究院崖山数据库系统YashanDB与帆软信创商业智能软件&#xff08;V6.0&#xff09;顺利完成兼容性互认证&#xff0c;经严格测试&#xff0c;双方产品能够相互兼容&#xff0c;稳定运行。 崖山数据库系统YashanDB是深圳计算科学研究院自主研发设计…

XSS Challenges 靶场通关解析

前言 XSS Challenges&#xff08;跨站脚本攻击挑战&#xff09;是一种用于学习和测试跨站脚本&#xff08;XSS&#xff09;漏洞的实验性平台。这些挑战旨在帮助安全研究人员和开发人员了解XSS漏洞的工作原理、检测方法和防御技巧。 通常&#xff0c;XSS Challenges平台提供一…

vite创建vue项目启动时域名为127.0.0.1修改为localhost不生效——问题解决

今天偶然间想起来年前整的一套vue3的框架&#xff0c;索性跑了一下&#xff0c;结果发现运行后地址为127.0.0.1而非localhost&#xff0c;所以想把域名改一下 找到vite.config.js文件中的export default defineConfig&#xff0c;在server中写入host:localhost 然后通过npm ru…

3d设计网站有哪些(2)?渲染100邀请码1a12

上次介绍了了几个设计网站&#xff0c;这次我们接着介绍。 1、Archive 3D Archive 3D是一个简单庞大的模型下载网站&#xff0c;可以下载的类型有家具、设备、飞行装备、门窗、厨房等。 2、3D Warehouse 3D Warehouse是预制3D模型网站&#xff0c;能与SketchUp无缝协作&…

软件杯 深度学习的水果识别 opencv python

文章目录 0 前言2 开发简介3 识别原理3.1 传统图像识别原理3.2 深度学习水果识别 4 数据集5 部分关键代码5.1 处理训练集的数据结构5.2 模型网络结构5.3 训练模型 6 识别效果7 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习…

EFDC模型安装及建模方法;在排污口论证、水质模拟、地表水环评、地表水水源地划分、水环境容量计算等领域中的应用

目录 专题一 EFDC软件安装 专题二 EFDC模型讲解 专题三 一维河流模拟实操 专题四 建模前处理 专题五 EFDC网格剖分介绍 专题六 EFDC二维湖库水动力模拟/非保守染色剂模拟 专题七 EFDC水质模型参数及原理介绍 专题八 EFDC一、二、三维湖库水质模拟 专题九 基于EFDC的地…

Aigtek射频功率放大器的主要功能是什么

射频功率放大器是一种专门用于放大射频信号功率的电子器件&#xff0c;它在无线通信、雷达系统、卫星通信等射频应用中起着至关重要的作用。下面将详细介绍射频功率放大器的主要功能。 信号放大&#xff1a;射频功率放大器的主要功能之一就是将传入的射频信号放大到所需的功率水…

使用 FFmpeg 从音视频中提取音频

有时候我们需要从视频文件中提取音频&#xff0c;并保存为一个单独的音频文件&#xff0c;我们可以借助 FFmpeg 来完成这个工作。 一、提取音频&#xff0c;保存为 mp3 文件: 要使用 FFmpeg 从音视频文件中提取音频&#xff0c;并将 ACC 编码的音频转换为 MP3 格式&#xff0…

利用PS中Lab颜色模式进行简单调色?

【原图】 详细步骤如下&#xff1a; Step 1 : 打开PS&#xff0c;打开素材&#xff0c;点菜单栏&#xff0c;【图像】-【模式】-【Lab颜色】&#xff0c;效果如下图 Step2&#xff1a;ctrl(或command)m打开曲线工具&#xff0c;选择a通道&#xff0c;效果如下图。 Step3: 把标…

埃及外宾亲临育菁 参观考察桌面CNC机床

随着我公司的规模不断壮大以及国际化建设工作的不断推进&#xff0c;广东育菁装备在国外的知名度也越来越高&#xff0c;4月25日&#xff0c;公司迎来了埃及外宾到访考察桌面型数控加工中心&#xff0c;桌面级数控车床等&#xff0c;育菁总经理杨先生等相关负责人对远到而来的埃…

git/gerrit使用遇到的问题

Push时出现的多个问题及其解决 branch【...】not found 这个错误通常出现在 Git 命令中指定的分支名称中包含特殊字符或者语法错误时。需要确保指定的分支名称是正确的&#xff0c;并且没有任何不支持的字符。 例如&#xff0c;如果分支名称是 feature/branch&#xff0c;应该…

写爬虫代码抓取Asterank中小行星数据

2024年5月4日 问题来源 解决方案 回顾2023年7月14日自己写的爬虫代码 import requests import re import pandas as pd texts[] def getData(page):#每页评论的网址urlhttps://item.jd.com/51963318622.html#comment#添加headers&#xff0c;伪装成浏览器headers{User-Agent:…

电脑切换窗口快捷键,让你轻松驾驭多个任务

在使用电脑时&#xff0c;经常需要切换不同的窗口&#xff0c;以便快速地访问不同的应用程序或任务。为了提高效率&#xff0c;掌握一些电脑切换窗口快捷键是非常重要的。本文将介绍三种在电脑上切换窗口的方法&#xff0c;帮助您更加高效地进行多任务处理。 方法1&#xff1a;…

FIFO Generate IP核使用——异步复位

FIFO Generator IP核提供了一个复位输入&#xff0c;当该输入被激活时&#xff0c;它会复位所有的计数器和输出寄存器。对于块RAM或分布式RAM实现&#xff0c;复位FIFO并不是必需的&#xff0c;可以在FIFO中禁用复位引脚。共有两种复位类型选项&#xff1a;异步复位和同步复位。…

Linux——mysql运维篇

回顾基本语句&#xff1a; 数据定义语言 ( DDL ) 。这类语言用于定义和修改数据库的结构&#xff0c;包括创建、删除和修改数据库、表、视图和索引等对象。主要的语句关键字包括 CREATE 、 DROP 、 ALTER 、 RENAME 、 TRUNCATE 等。 create database 数据库 &…

FreeRTOS为什么要区分任务函数和中断函数?

在我们之前的学习中&#xff0c;队列&#xff0c;信号量&#xff0c;互斥量&#xff0c;事件组&#xff0c;任务通知&#xff0c;它们都有两套函数&#xff0c;在任务中使用或在中断中使用。 1.为什么要用两套函数&#xff1f; 情景1&#xff1a; 我们在写队列的时候等待100…

图神经网络实战(9)——GraphSAGE详解与实现

图神经网络实战&#xff08;9&#xff09;——GraphSAGE详解与实现 0. 前言1. GraphSAGE 原理1.1 邻居采样1.2 聚合 2. 构建 GraphSAGE 模型执行节点分类2.1 数据集分析2.2 构建 GraphSAGE 模型 3. PinSAGE小结系列链接 0. 前言 GraphSAGE 是专为处理大规模图而设计的图神经网…

一般实现分布式锁都有哪些方式?使用 Redis 如何设计分布式锁?使用 zk 来设计分布式锁可以吗?这两种分布式锁的实现方式哪种效率比较高?

目录 1.Redis 分布式锁 &#xff08;1&#xff09;Redis 最普通的分布式锁 &#xff08;2&#xff09;RedLock 算法 2.zk 分布式锁 3.redis 分布式锁和zk分布式锁的对比 1.Redis 分布式锁 官方叫做 RedLock 算法&#xff0c;是 Redis 官方支持的分布式锁算法。 这个分布式…

C++ | Leetcode C++题解之第70题爬楼梯

题目&#xff1a; 题解&#xff1a; class Solution { public:int climbStairs(int n) {double sqrt5 sqrt(5);double fibn pow((1 sqrt5) / 2, n 1) - pow((1 - sqrt5) / 2, n 1);return (int)round(fibn / sqrt5);} };
最新文章