UI自动刷新大法:DataBinding数据绑定

之前我们讲了DataBinding在Activity、Fragment、RecyclerView中的基础使用,而那些常规使用方法里,每当绑定的变量发生数据变化时,都需要ViewDataBinding重新设值才会刷新对应UI。而DataBinding通过内部实现的观察者模式来进行自动刷新UI,这块内容是DataBinding的重要部分。在观察者模式的角度下,DataBinding库,允许我们使用对象、字段,或者集合来进行观察,当其中的一个可观察者数据对象绑定到了视图当中,并且数据对象的属性发生更改变化的时候,视图将会自动更新。而根据绑定的方式不同,又可分为 单向绑定双向绑定

单向绑定,实现数据变化自动驱动UI刷新,方式有三种:BaseObservable,ObservableField、ObservableCollection。在此之前,先让我们来了解下事件绑定。

前言 事件绑定

为了更好的了解单向绑定和后续的双向绑定,我们先来看下DataBinding中事件绑定的方式。严格来说,事件绑定也是一种变量绑定,只不过设置的绑定不再是单纯的变量,还是回调接口,事件绑定可设置的回调事件有以下:

android:onClick
android:onLongClick
android:onTextChanged
android:afterTextChanged
...

对应使用步骤也较为简单:

第一步 声明内部类

在要使用的activity类里新建一个内部类来声明对应的回调方法,这里我们接着用上篇文章中的工程来继续修改。我们在MainActivity中新建一个内部类,里面声明onClick()和afterTextChanged()事件:

public class MainActivity extends AppCompatActivity {
    UserInfo userInfo;
    DemoBinding viewDataBinding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        userInfo = new UserInfo("亚历山大", 66);
        viewDataBinding.setUserInfoExample(userInfo);
        viewDataBinding.setUserEventListener(new EventListener());
    }
    public class EventListener{
        public void changedUserName(){
            userInfo.setName("鸭梨山大二世");
            viewDataBinding.setUserInfoExample(userInfo);
        }
        public void changedUserInfo(){
            userInfo.setName("鸭力山大三世");
            userInfo.setAge(81);
            viewDataBinding.setUserInfoExample(userInfo);
        }
    }
}

第二步 修改布局标签内容

同时还要在相应布局文件中的< data>标签里声明此内部类路径,在对应设置此点击事件回调的控件里通过内嵌表达式 @{} 来设置引用。

<?xml version="1.0" encoding="utf-8"?>
<layout 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">

    <data>
        <import type="com.example.dbjavatest.MainActivity.EventListener"/>
        <import type="com.example.dbjavatest.bean.UserInfo"/>

        <variable
            name="UserInfoExample"
            type="UserInfo" />

        <variable
            name="UserEventListener"
            type="EventListener" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/tv_user_first"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{()->UserEventListener.changedUserName()}"
            android:text="@{UserInfoExample.name,default=defaultValue}"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"/>

        <TextView
            android:id="@+id/tv_user_second"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(UserInfoExample.age),default=defaultValue}"
            app:layout_constraintTop_toBottomOf="@+id/tv_user_first"
            app:layout_constraintStart_toStartOf="parent"/>

        <Button
            android:id="@+id/btn_change"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toBottomOf="@+id/tv_user_second"
            app:layout_constraintStart_toStartOf="parent"
            android:text="改变属性"
            android:onClick="@{()->UserEventListener.changedUserInfo()}"/>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

在这布局文件中,android:onClick="@{()->UserEventListener.changedUserName()}"属性含义即为点击事件响应方法为指定的UserEventListener中的changedUserName(),运行后,可查看效果如下:

DataBinding点击事件.gif

单向数据绑定之Base Observable

众所周知,一个单纯的ViewModel类被更新后,并不会让UI自动更新。Observable存在的目的就是为了数据变更后UI会自动刷新。

在此方面,Observable提供了两个方法:

· notifyChange()
· notifyPropertyChanged()

方法一notifyChange()会刷新所有的UI。

方法二notifyPropertyChanged()只会刷新属于它的UI,需要绑定属性(通过注解 @Bindable来绑定)。

使用方式也较为简单:

第一步 修改实体bean类

使实体bean类继承自BaseObservable:

public class UserInfo extends BaseObservable {
    public UserInfo(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(BR.name);
    }

    public void setNameAndAge(String name,int age){
        this.name = name;
        this.age = age;
        notifyChange();
    }

    @Bindable
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Bindable
    public String name; //public属性成员可直接在成员变量上方加上@Bindable

    private int age; //private属性成员需要在其get方法上添加@Bindable
}

第二步、修改对应Activity

为了凸显出区别,我们继续沿用上面点击事件中例子的布局,不做修改,但是Activity中代码要修改:

public class MainActivity extends AppCompatActivity {
    UserInfo userInfo;
    ActivityMainBinding viewDataBinding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        userInfo = new UserInfo("亚历山大", 66);
        viewDataBinding.setUserInfoExample(userInfo);
        viewDataBinding.setUserEventListener(new EventListener());
    }
    public class EventListener{
        public void changedUserName(){
            userInfo.setName("鸭梨山大二世");
            userInfo.setAge(999);//无效
        }
        public void changedUserInfo(){
            userInfo.setNameAndAge("鸭力山大X世",new Random().nextInt(100));
        }
    }
}

可以看到,相比于普通的点击事件代码中明显少了viewDataBinding.setUserInfoExample…等操作,可能一两个点击事件看不出明显差别,但事件一多,你会发现Activity的代码会省略很多,非常利于代码解耦和整洁性。这也不影响相应效果,运行效果如下:

DataBinding中的Observable点击事件.gif

可见,在点击用户名时,userInfo.setAge(999)执行无效的,因为在原实体bean类中,只设置了改变name属性(notifyPropertyChanged(BR.name)):

image.gif
所以在点击name属性的时候,只有名字在变化,而点击事件里setNameAndAge()中因为声明了notifyChange();改变所有元素,因此可看到点击按钮时,全局属性跟着改变了(name属性一致固定写死,所以你可能觉得名字没变化)。

二、单项数据绑定之ObservableField

有的时候相应工程里,实体Bean类需要继承其他类,这样就无法使用Observable了。这时有另外一个方案,即ObservableField。PS:ObservableField不需要进行notify操作。

在ObservableField中,官方提供了对基本数据类型的封装,如ObservableInt、ObservableLong、ObservableFloat、ObservableDouble ObservableShort、ObservableBoolean、ObservableByte、ObservableChar以及 ObservableParcelable 。当然也可通过泛型来申明其他类型,可以说这是官方对Observable中字段的注解和刷新等操作等封装。

其使用方式与Observable还是有点区别的:

第一步 修改实体bean类

public class UserInfo{

    public final ObservableField<String> name;

    public final ObservableField<Integer> age;

    public ObservableField<String> getName() {
        return name;
    }

    public ObservableField<Integer> getAge() {
        return age;
    }

    public UserInfo(String name,
                    Integer age){
        this.name=new ObservableField<>(name);
        this.age= new ObservableField<Integer>(age);
    }
}

可见Bean文件在这里取消了继承,对变量进行了public final修饰,重写对应的get()(final修饰的变量无法写set())。其set()属性的方式则有些许不一样。

第二步 修改对应逻辑

在对应需要进行set逻辑的地方,可以通过ObservableField提供的get、set方法,去拿到值和设置值来达到更新UI效果。如下:

public class MainActivity extends AppCompatActivity {
    UserInfo userInfo;
    ActivityMainBinding viewDataBinding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        userInfo = new UserInfo("亚历山大", 66);
        viewDataBinding.setUserInfoExample(userInfo);
        viewDataBinding.setUserEventListener(new EventListener());
    }
    public class EventListener{
        public void changedUserName(){
            userInfo.getName().set("鸭梨山大二世");
        }
        public void changedUserInfo(){
            userInfo.getName().set("鸭梨山大一世");
            userInfo.getAge().set(new Random().nextInt(101));
        }
    }
}

对应的效果为:

DataBinding-Field点击事件.gif

三、单项数据绑定之ObservableCollection

ObservableCollection中最常用的是ObservableList 和 ObservableMap,即dataBinding 提供的包装类用于替代原生的 List 和 Map。其使用方式与前两者差别也不大。

第一步 修改Collection布局

这里我们不再使用实体bean类,而是dataBinding 包装的ObservableMap和ObservableList元素,因此需要修改< data>标签。如下:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <import type="androidx.databinding.ObservableMap"/>
        <import type="androidx.databinding.ObservableList"/>
        <!--注意这里,只能用 "&lt;"和 "&gt;"-->
        <variable
            name="list"
            type="ObservableList&lt;String&gt;"/>
        <variable
            name="map"
            type="ObservableMap&lt;String,Integer&gt;"/>
        <variable
            name="sing"
            type="String"/>
        <variable
            name="num"
            type="int"/>
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/tv_user_first"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{list[num],default=syt}"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"/>

        <TextView
            android:id="@+id/tv_user_second"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(map[sing]),default=sys}"
            app:layout_constraintTop_toBottomOf="@+id/tv_user_first"
            app:layout_constraintStart_toStartOf="parent"/>

        <Button
            android:id="@+id/btn_change"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toBottomOf="@+id/tv_user_second"
            app:layout_constraintStart_toStartOf="parent"
            android:text="改变属性"
            android:onClick="onButtonClick"/>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

这里的ObservableMap和ObservableList归属的databinding在androidX包里,如果你的工程还没有适配安卓X,最好请尽快适配。最后一个Button里的android:onClick="onButtonClick"可能会让你感到疑惑,但其实这也是dataBinding里的控件的点击事件写法之一。

第二步 修改Activity中对应逻辑

其Activity中代码就如下:

public class MainActivity extends AppCompatActivity{
    ActivityMainBinding viewDataBinding;
    private ObservableMap<String, Integer> map;
    ObservableArrayList<String> obList;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        map = new ObservableArrayMap<>();
        map.put("test_num",1 );
        map.put("test_biger_num", 100);
        viewDataBinding.setMap(map);
        obList = new ObservableArrayList<>();
        obList.add("ObservableArrayList");
        obList.add("observablelist");
        obList.add("observablelist more");
        viewDataBinding.setList(obList);
        viewDataBinding.setNum(0);
        viewDataBinding.setSing("test_biger_num");
    }

    public void onButtonClick(View v) {
        map.put("test_biger_num",new Random().nextInt(99));
    }

}

对应效果如下:

DataBinding_ObservableCollection点击事件.gif

当然,设置点击事件还有一种方法引用,直接用 :: 即可,
如: android:onClick=“@{listener::onClick}” 就是方法引用绑定!

四、双向数据绑定

双向绑定含义就是 在数据更新时使得View也能更新,而View更新的时候也同时更改数据

此法不适合所有的应用场景,但也有相应的应用场景,比如用户注册登录场景,在输入账号和密码同时,UI刷新同时数据也更新,这里就适合双向绑定。可以说,双向绑定时安卓MVVM架构的基础。
这次简单实例我们用ObservableField方式,先写一个bean实体类:

public class DataBean {
    public final ObservableField<String> dataInfo;

    public DataBean(ObservableField<String> dataInfo) {
        this.dataInfo = dataInfo;
    }

    public ObservableField<String> getDataInfo() {
        return dataInfo;
    }
}

对应也要修改布局文件和引入,如下:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <import type="com.example.dbjavatest.bean.DataBean"/>
        <variable
            name="dataInfoBean"
            type="DataBean" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/tv_data"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="26sp"
            android:textColor="@color/purple_200"
            android:text="@{dataInfoBean.dataInfo}"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_marginLeft="50dp"/>

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入数据"
            android:text="@={dataInfoBean.dataInfo}"
            app:layout_constraintTop_toBottomOf="@+id/tv_data"
            android:textSize="25sp"
            android:layout_marginTop="30dp"
            android:paddingLeft="20dp"/>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

这里要注意,在EditText中更新数据时会同步到上面的TextView,绑定方式跟单向绑定方式相比,要在内嵌表达式中多用一个“=”,即android:text=“@={dataInfoBean.dataInfo}”。

对应Activity中代码如下:

public class MainActivity extends AppCompatActivity{
    ActivityMainBinding viewDataBinding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        DataBean dataBean = new DataBean(new ObservableField<String>(""));
        viewDataBinding.setDataInfoBean(dataBean);
    }
}

效果也能猜到:

DataBinding双向绑定.gif

五、List Set Map等数据结构

除了ObservableCollection,DataBinding也支持原生Java数据结构(数组、List、Set和Map)在布局文件中使用,且在布局文件中都可以通过list[index]的形式来获取元素。

官方为了和< variable>标签元素区分开,在声明具有多个泛型的数据类型时,需要使用"& lt;"和 " >"用以区分。如下:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <import type="java.util.List" />
        <import type="java.util.Set" />
        <import type="java.util.Map" />
        <variable
            name="array"
            type="String[]" />
        <variable
            name="list"
            type="List&lt;String&gt;" />
        <variable
            name="map"
            type="Map&lt;String, String&gt;" />
        <variable
            name="set"
            type="Set&lt;String&gt;" />
        <variable
            name="num"
            type="int" />
        <variable
            name="sing"
            type="String" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <TextView
        ···
        android:text="@{array[1]}" />
        <TextView
        ···
        android:text="@{list[num]}" />
        <TextView
        ···
        android:text="@{map[sing]}" />
        <TextView
        ···
        android:text='@{map["test"]}' />
    </LinearLayout>
</layout>

六、使用相应类方法

在DataBinding中,使用相应类方法,可现在< data>标签中导入该类不需要写<vari…>标签,然后在布局中像对待一般方法来调用就行。

例如,先写个没啥用的静态类:

public class UIUtils {

    public static String showTheDemo(String str) {
        return str.toString();
    }

}

在< data>中引入该类:

<import type="com.example.dbjavatest.UIUtils" />

然后在对应控件里调用:

<TextView
    android:id="@+id/tv_data"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="26sp"
    android:textColor="@color/purple_200"
    android:text="@{UIUtils.showTheDemo(dataInfoBean.dataInfo)}"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    android:layout_marginLeft="50dp"/>

PS : DataBinding中布局里的控件通过嵌入表达式不仅可以引用对应方法,也可以使用三元运算符等运算符。

七、include和viewStub

DataBinding也支持include的布局文件,一样通过dataBinding来进行数据绑定,一样需要使用< layout>标签和声明需要使用的变量,然后在主布局中将对应的变量传递给include布局,使两个布局共享的数据变量相同。

例如:view_insert.xml中

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <import type="com.example.dbjavatest.bean.DataBean"/>
        <variable
            name="dataInfoBean"
            type="DataBean" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入数据"
            android:text="@={dataInfoBean.dataInfo}"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            android:textSize="25sp"
            android:layout_marginTop="30dp"
            android:paddingLeft="20dp"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

对应主布局则直接include,同时通过bind:变量名来将同一变量传过去。你可能发现这里会报错,在布局头文件声明xmlns:bind=“http://schemas.android.com/apk/res-auto” 即可。对应布局文件为:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:bind="http://schemas.android.com/apk/res-auto">

    <data>
        <import type="com.example.dbjavatest.bean.DataBean"/>
        <variable
            name="dataInfoBean"
            type="DataBean" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/tv_data"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="26sp"
            android:textColor="@color/purple_200"
            android:text="@{dataInfoBean.dataInfo}"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_marginLeft="50dp"/>

        <include
            layout="@layout/view_insert"
            app:layout_constraintTop_toBottomOf="@+id/tv_data"
            bind:dataInfoBean = "@{dataInfoBean}"
            />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

ViewStub绑定变量和将变量传递给ViewStub的方式与此一致。例如:

<ViewStub
    android:id="@+id/view_stub"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout="@layout/view_insert"
    bind:dataInfoBean="@{dataInfoBean}" />

当然,ViewStub 文件一样要使用 layout 等标签进行布局。相应的在Activity中也是通过ViewBinding获取对象实例:

View viewStub = viewDataBinding.viewStub.getViewStub().inflate();

通过此实例,可以控制viewStub的可见性。如果在xml中,没用使用bind:dataInfoBean=“@{dataInfoBean}”,但又想对ViewStub进行数据绑定。则可以在ViewStub 设置 setOnInflateListener回调函数时进行数据绑定,如下:

viewDataBinding.viewStub.setOnInflateListener(new ViewStub.OnInflateListener() {
    @Override
    public void onInflate(ViewStub stub, View inflated) {
        ViewDataBinding viewStubBinding = DataBindingUtil.bind(inflated);
        viewStubBinding.setDataInfoBean(dataBean);
    }
});

对DataBinding的数据绑定就介绍到这里了,如果后续发现有遗漏的要点,会即使补充。另外,如果看这篇文字有点吃力,说明你对DataBinding的基础操作还不熟悉,请翻阅我的上一片文章。

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

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

相关文章

浅谈人工智能之深度学习~

目录 前言&#xff1a;深度学习的进展 一&#xff1a;深度学习的基本原理和算法 二&#xff1a;深度学习的应用实例 三&#xff1a;深度学习的挑战和未来发展方向 四&#xff1a;深度学习与机器学习的关系 五&#xff1a;深度学习与人类的智能交互 悟已往之不谏&#xff0…

Gemini VS GPT-4,当前两大顶级AI模型实测

随着谷歌在AI军备竞赛中急起直追&#xff0c;“有史以来最强大模型”Gemini Advanced终于上线&#xff0c;AI爱好者们总算等来了一款号称能够匹敌GPT-4的大语言模型。 月费19.99美元&#xff08;包含Google One订阅&#xff09;的Gemini Advanced实际表现如何&#xff1f;究竟…

MongoDB系列之WiredTiger引擎

概述 关系型数据库MySQL有InnoDB存储引擎&#xff0c;存储引擎很大程度上决定着数据库的性能。 在MongoDB早期版本中&#xff0c;默认使用MMapV1存储引擎&#xff0c;其索引就是一个B-树&#xff08;也称B树&#xff09;。 从MongoDB 3.0开始引入WiredTiger&#xff08;以下…

arduino D1 中esp8266 没有ide的库

http://arduino.esp8266.com/stable/package_esp8266com_index.json https://arduino.esp8266.com/stable/package_esp8266com_index.json 这个是官网的包地址 拿到后复制到arduino ide中 然后在开发板管理器&#xff0c;搜索esp&#xff0c;搜出来后安装 去开发板选择 然后测…

导数的几何意义【高数笔记】

1. 高数中的导数几何意义&#xff0c;与中学中斜率的联系 2. 导函数与导数的区别和联系又是什么 3. 导数的几何意义的题型是什么 4. 这些题型又有哪些区别 5. 点在曲线外和点在曲线上&#xff0c;需要注意什么 6. 法线和切线有什么关系 7. 法线是什么

MySQL数据库-索引概念及其数据结构、覆盖索引与回表查询关联、超大分页解决思路

索引是帮助mysql高效获取数据的数据结构,主要用来提高检索的效率,降低数据库的IO成本(输入输出成本&#xff08;Input-Output Cost&#xff09;),同时通过索引对数据进行排序也能降低数据排序的成本,降低了CPU的消耗。 Mysql的默认存储引擎InnoDB&#xff0c;InnoDB采用的B树的…

STM32 7-8

目录 ADC AD单通道 AD多通道 DMA DMA转运数据 DMAAD多通道 ADC AD单通道 AD.c #include "stm32f10x.h" // Device header/*** brief 初始化AD所需要的所有设备* param 无* retval 无*/ void AD_Init(void) {RCC_APB2PeriphClockCmd(RCC_AP…

sheng的学习笔记-网络爬虫scrapy框架

基础知识&#xff1a; scrapy介绍 何为框架&#xff0c;就相当于一个封装了很多功能的结构体&#xff0c;它帮我们把主要的结构给搭建好了&#xff0c;我们只需往骨架里添加内容就行。scrapy框架是一个为了爬取网站数据&#xff0c;提取数据的框架&#xff0c;我们熟知爬虫总…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之AlphabetIndexer组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之AlphabetIndexer组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、AlphabetIndexer组件 可以与容器组件联动用于按逻辑结构快速定位容器显…

C#使用重载方法实现不同类型数据的计算

目录 一、涉及到的相关知识 1.重载的方法 2.Convert.ToInt32(String)方法 3.判断字符串是否带有小数点 二、实例 1.示例 2.生成成果 一、涉及到的相关知识 1.重载的方法 重载方法就是方法名称相同&#xff0c;但是每个方法中参数的数据类型、个数或顺序不同的方法。如果…

【电路】三个晶体管的声控开关电路

这种声控开关&#xff0c;可能是非常有用的&#xff0c;例如敲门声或拍手声可以激活一盏灯&#xff0c;灯光几秒钟后会自动关闭。另一种使用在防盗保护&#xff0c;如果有人想打开门或打破东西&#xff0c;灯就会亮起来&#xff0c;这表明有人在家。 该电路可以工作于任何5–1…

disql备份还原

disql备份还原 前言 本文档根据官方文档&#xff0c;进行整理。 一、概述 在 disql 工具中使用 BACKUP 语句你可以备份整个数据库。通常情况下&#xff0c;在数据库实例配置归档后输入以下语句即可备份数据库&#xff1a; BACKUP DATABASE BACKUPSET db_bak_01;语句执行完…

使用Cargo创建、编译与运行Rust项目

在 Rust 开发中&#xff0c;Cargo 是一个非常重要的工具&#xff0c;它负责项目的构建、管理和依赖管理。以下是如何使用 Cargo 创建、编译和运行 Rust 项目的详细步骤。 1. 创建新项目 首先确保你已经在计算机上安装了 Rust 和 Cargo。然后&#xff0c;在命令行中输入以下命…

【动态规划】1301. 最大得分的路径数目

作者推荐 【动态规划】【前缀和】【C算法】LCP 57. 打地鼠 本文涉及知识点 动态规划汇总 LeetCoce1301. 最大得分的路径数目 给你一个正方形字符数组 board &#xff0c;你从数组最右下方的字符 ‘S’ 出发。 你的目标是到达数组最左上角的字符 ‘E’ &#xff0c;数组剩余…

【Tauri】(1):使用Tauri1.5版本,进行桌面应用开发,在windows,linux进行桌面GUI应用程序开发,可以打包成功,使用 vite 最方便

1&#xff0c;视频地址&#xff1a; https://www.bilibili.com/video/BV1Pz421d7s4/ 【Tauri】&#xff08;1&#xff09;&#xff1a;使用Tauri1.5版本&#xff0c;进行桌面应用开发&#xff0c;在windows&#xff0c;linux进行桌面GUI应用程序开发&#xff0c;可以打包成功&…

springboot177健身房管理系统

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的 适用于计算机类毕业设计&#xff0c;课程设计参考与学习用途。仅供学习参考&#xff0c; 不得用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。 看运行截图看 第五章 第四章 获取资料方式 **项…

Java图形化界面编程——弹球游戏 笔记

Java也可用于开发一些动画。所谓动画&#xff0c;就是间隔一定的时间(通常小于0 . 1秒 )重新绘制新的图像&#xff0c;两次绘制的图像之间差异较小&#xff0c;肉眼看起来就成了所谓的动画 。 ​ 为了实现间隔一定的时间就重新调用组件的 repaint()方法&#xff0c;可以借助于…

正则可视化工具:学习和编写正则表达式的利器

引言 正则表达式是一种强大的文本匹配和处理工具&#xff0c;但对于初学者和非专业开发者来说&#xff0c;编写和理解正则表达式可能是一项具有挑战性的任务。为了帮助人们更好地学习和编写正则表达式&#xff0c;正则可视化工具应运而生。本文将探讨正则可视化工具的优点&…

自动化AD域枚举和漏洞检测脚本

linWinPwn 是一个 bash 脚本&#xff0c;可自动执行许多 Active Directory 枚举和漏洞检查。该脚本基于很多现有工具实现其功能&#xff0c;其中包括&#xff1a;impacket、bloodhound、netexec、enum4linux-ng、ldapdomaindump、lsassy、smbmap、kerbrute、adidnsdump、certip…

力扣49. 字母异位词分组

Problem: 49. 字母异位词分组 文章目录 题目描述思路复杂度Code 题目描述 思路 1.我们利用一个无序映射以排序后的字符作为键、字符数组作为值&#xff1b; 2.每次我们从原始数组中取出一个字符串并对其进行排序&#xff0c;并将其添加到对应键所存的数组中&#xff1b; 3.创建…