【Android】Jetpack入门知识总结(LifeCycle,ViewModel,LiveData,DataBinding等)

文章目录

  • LifeCycle
    • 使用Lifecycle解耦页面与组件
      • 自定义控件实现LifecycleObserver接口
      • 注册生命周期监听器
    • 使用LifecycleService解耦Service与组件
    • 使用ProcessLifecycleOwner监听应用程序生命周期
  • ViewModel
    • 用法
    • 在 Fragment 中使用 ViewModel
  • LiveData
  • DataBinding
    • 导入依赖
    • 基本用法
      • 在布局文件中生成
      • 使用DataBinding的布局文件
      • 要绑定的数据类
      • 在Activity使用
    • 事件绑定
      • 定义事件处理类
      • 在Activity中设置绑定
      • 布局文件
    • 使用类方法
  • BindingAdapter
    • 示例
  • 双向绑定
    • BaseObservable
      • 示例
    • ObservableField

LifeCycle

使用Lifecycle解耦页面与组件

自定义控件实现LifecycleObserver接口

这里实现一个自定义的Chronometer,并实现能够响应生命周期事件的功能

public class MyChronometer extends Chronometer implements LifecycleObserver {private long elapsedtime;public MyChronometer(Context context, AttributeSet attrs) {super(context, attrs);}// 添加注解与生命周期事件关联@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)private void startMeter() {setBase(SystemClock.elapsedRealtime() - elapsedtime);start();}@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)private void stopMeter() {elapsedtime = SystemClock.elapsedRealtime() - getBase();stop();}
}

注册生命周期监听器

在代码中使用自定义组件并为其注册生命周期监听器

public class MainActivity extends AppCompatActivity {private MyChronometer chronometer;private long elapsedtime;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);chronometer = findViewById(R.id.chronometer);// 注册生命周期监听器getLifecycle().addObserver(chronometer);}
} 

activityfragment都是直接实现了LifecycleOwner接口,所以直接调用getLifecycle方法得到LifeCycle对象。addObserver 注册了一个生命周期观察者,当 MainActivity 的生命周期发生变化时,chronometer 会自动响应这些事件。

使用LifecycleService解耦Service与组件

1. 添加依赖

生命周期 | Jetpack | Android Developers (google.cn)

    implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"

实现了 LifecycleObserver 接口的类,用于监听 Service 的生命周期事件。

public class MyLocationObserver implements LifecycleObserver {private Context mContext;private LocationManager locationManager;private MyLocationlistener myLocationlistener;public MyLocationObserver(Context context) {this.mContext = context;}@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)public void startGetLocation() {Log.d("TagA", "start位置");if (ActivityCompat.checkSelfPermission(mContext, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {return;}locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);myLocationlistener = new MyLocationlistener();locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 3000, 1, myLocationlistener);}@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)public void stopGetLocation() {Log.d("TagA", "stop位置");locationManager.removeUpdates(myLocationlistener);}static class MyLocationlistener implements LocationListener {@Overridepublic void onLocationChanged(@NonNull Location location) {Log.d("TagA", "位置变了");}}
}

扩展自 LifecycleService 的服务

public class MyLocationService extends LifecycleService {public MyLocationService() {Log.d("TagA", "MyLocationService空参构造");MyLocationObserver myLocationObserver = new MyLocationObserver(this);getLifecycle().addObserver(myLocationObserver);}
}

启动服务

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Log.d("TagA", "启动");Intent intent = new Intent(this, MyLocationService.class);startService(intent);} 
}

使用ProcessLifecycleOwner监听应用程序生命周期

ProcessLifecycleOwner 是 Android Jetpack 中的一个类,用于监听整个应用进程的生命周期事件。与 Activity 和 Fragment 的生命周期不同,ProcessLifecycleOwner 关注的是整个应用的前后台状态切换。它实现了 LifecycleOwner 接口,因此你可以像使用 Activity 或 Fragment 的生命周期一样,监听应用的生命周期事件。

ProcessLifecycleOwner 允许你监听以下两个主要状态:

  1. 前台:当应用至少有一个 Activity 可见时,进入前台。
  2. 后台:当所有 Activity 都不可见时,应用进入后台。
public class MyApp extends Application implements LifecycleObserver {@Overridepublic void onCreate() {super.onCreate();// 注册观察者来监听应用的生命周期ProcessLifecycleOwner.get().getLifecycle().addObserver(this);}@OnLifecycleEvent(Lifecycle.Event.ON_START)public void onEnterForeground() {Log.d("AppLifecycle", "应用进入前台");// 这里可以添加当应用进入前台时需要执行的操作}@OnLifecycleEvent(Lifecycle.Event.ON_STOP)public void onEnterBackground() {Log.d("AppLifecycle", "应用进入后台");// 这里可以添加当应用进入后台时需要执行的操作}
}
  1. 继承 Application 类
    创建一个自定义的 Application 类,并在其中注册生命周期观察者。

  2. 添加生命周期观察者
    使用 ProcessLifecycleOwner.get().getLifecycle().addObserver() 来添加生命周期观察者。这样可以监听整个应用的生命周期。

  3. 处理生命周期事件
    通过 @OnLifecycleEvent(Lifecycle.Event.ON_START)@OnLifecycleEvent(Lifecycle.Event.ON_STOP) 监听应用进入前台和后台的事件。在进入前台或后台时,可以执行相应的逻辑,比如暂停或恢复任务、更新UI、数据同步等。

优点

  1. 应用级生命周期管理:不再需要逐个监听每个 Activity 或 Fragment 的生命周期事件,ProcessLifecycleOwner 提供了一种应用级别的生命周期事件处理方式。

  2. 前后台切换检测:可以用来检测应用是否进入后台或回到前台,非常适合在应用进入后台时暂停某些服务,或者在进入前台时恢复。

注意:ProcessLifecycleOwner 只监听应用的前台和后台状态,不会捕捉到具体的 Activity 或 Fragment 的生命周期事件。如果需要监听具体的页面状态,仍然需要使用各自的 LifecycleOwner

ViewModel

ViewModel 是 Android Jetpack 提供的架构组件之一,主要用于存储和管理与 UI 相关的数据,以确保在配置更改(如屏幕旋转)时数据能够持久化并且不会丢失。ViewModel 可以帮助我们更好地分离 UI 控制逻辑与数据处理逻辑,增强代码的可维护性。

  1. 生命周期感知ViewModel 是生命周期感知的,它的生命周期比 ActivityFragment 更长,因此即使 UI 控件销毁重建,数据依然可以保存。
  2. 持久化数据:它可以避免在配置更改(如屏幕旋转)时重新加载数据。
  3. UI 与数据逻辑分离:ViewModel 主要处理数据逻辑,使 UI 控制代码和业务逻辑分离,保持代码结构清晰。

用法

  1. 创建 ViewModel
  2. ActivityFragment 中创建 ViewModel 实例
  3. 使用 ViewModel 提供的数据更新 UI
import androidx.lifecycle.ViewModel;public class MyViewModel extends ViewModel {private int counter = 0;// 增加计数public void increaseCounter() {counter++;}// 获取当前计数public int getCounter() {return counter;}
}
  1. 在 Activity 中使用 ViewModel
public class MainActivity extends AppCompatActivity {private TextView textView;private MyViewModel myViewModel;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);textView = (TextView) findViewById(R.id.textView);// 通过 ViewModelProvider 获取 MyViewModel 的实例myViewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(MyViewModel.class);textView.setText(String.valueOf(myViewModel.getCounter()));}public void plus(View view) {myViewModel.increaseCounter();textView.setText(String.valueOf(myViewModel.getCounter()));}
}

在 Fragment 中使用 ViewModel

如果是在 Fragment 中使用 ViewModel,方式与 Activity 类似,只需确保使用的是 FragmentViewModelProvider,代码如下:

myViewModel = new ViewModelProvider(getActivity()).get(MyViewModel.class);

LiveData

ViewModel 通常与 LiveData 结合使用,这样可以让 UI 自动监听数据变化并更新,而不需要手动刷新界面。

示例:

实现两个fragment中的seekbar同步变化

public class MyViewModel3 extends ViewModel {private MutableLiveData<Integer> progerss;public MutableLiveData<Integer> getProgerss() {if (progerss == null) {progerss = new MutableLiveData<Integer>();}return progerss;}
}

fragment处理

public class Fragment1 extends Fragment {private MyViewModel3 myViewModel3;public Fragment1() {}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {View v = inflater.inflate(R.layout.fragment_1, container, false);SeekBar seekBar = v.findViewById(R.id.seekBar);myViewModel3 = new ViewModelProvider(getActivity(), new ViewModelProvider.AndroidViewModelFactory()).get(MyViewModel3.class);myViewModel3.getProgerss().observe(getActivity(), new Observer<Integer>() {@Overridepublic void onChanged(Integer integer) {seekBar.setProgress(integer);}});seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {myViewModel3.getProgerss().setValue(progress);}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {}});return v;}
}

两个fragment中都需要进行修改

实现效果:

image-20241014183933983

DataBinding

导入依赖

android {...buildFeatures {dataBinding true}
}

基本用法

在布局文件中生成

image-20241014221456001

使用DataBinding的布局文件

<?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><variablename="user"type="com.example.livedatapractice.User" /></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><TextViewandroid:id="@+id/tv_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{user.name}"android:textSize="50dp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"tools:text="name" /><TextViewandroid:id="@+id/tv_age"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="67dp"android:text="@{String.valueOf(user.age)}"android:textSize="50dp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintHorizontal_bias="0.498"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/tv_name"app:layout_constraintVertical_bias="0.0"tools:text="age" /></androidx.constraintlayout.widget.ConstraintLayout>
</layout>

要绑定的数据类

package com.example.livedatapractice;public class User {private String name;private int age;public User(String name, int age) {this.name = name;this.age = age;}
}

在Activity使用

public class MainActivity extends AppCompatActivity {private ActivityMainBinding activityMainBinding;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);User user = new User("lixaing", 20);activityMainBinding.setUser(user);}
}

事件绑定

定义事件处理类

public class EventHandleListener {private Context context;public EventHandleListener(Context context) {this.context = context;}public void buttonOnClick(View view) {Toast.makeText(context, "点", Toast.LENGTH_SHORT).show();}
}

在Activity中设置绑定

public class MainActivity extends AppCompatActivity {private ActivityMainBinding activityMainBinding;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);User user = new User("lixaing", 20);activityMainBinding.setUser(user);// setactivityMainBinding.setEventHandle(new EventHandleListener(this));}
}

布局文件

<?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><variablename="user"type="com.example.livedatapractice.User" /><variablename="eventHandle"type="com.example.livedatapractice.EventHandleListener" /></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><TextViewandroid:id="@+id/tv_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{user.name}".../><TextViewandroid:id="@+id/tv_age"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{String.valueOf(user.age)}".../><Buttonandroid:id="@+id/button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Button"android:onClick="@{eventHandle.buttonOnClick}".../></androidx.constraintlayout.widget.ConstraintLayout>
</layout>

使用类方法

定义工具类

package com.example.databindingpractice2;public class StringUtils {public static String toUpperCase(String str) {return str.toUpperCase();}
}

在布局文件中使用

<data><import type="com.example.databindingpractice2.StringUtils" /><variablename="user"type="com.example.databindingpractice2.ObservableUser" />
</data>
		   <TextViewandroid:id="@+id/textView1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{StringUtils.toUpperCase(user.lastName)}" />

image-20241015204321757

BindingAdapter

有很多属性并非遵循了 javaBean 约定,例如 ImageView 可以通过android:src=“@{userViewModel.head}” 来绑定图片源,但是 ImageView 并没有提供 setSrc() 方法,而设置图片的方法是 setImageDrawable()、setImageURI() 等这些方法;但我们却也可以通过绑定,是因为google为我们提供了许多扩展标记行为的注解,帮助我们完成特殊需求下的匹配绑定,例如 @BindingAdapte可以扩展绑定行为,当然还有其他更丰富的的注解可以组合完成任何双向绑定的需求和复杂的中间过程。

示例

  1. 创建一个 BindingAdapter,将 URL 绑定到 ImageView
public class BindingAdapter {@androidx.databinding.BindingAdapter("app:src")public static void loadImage(ImageView view, String url) {Glide.with(view.getContext()).load(url).error(R.drawable.ic_launcher_background).into(view);}
}
  1. ImageView 中使用 BindingAdapter
<?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><variablename="user"type="com.example.livedatapractice.User" /><variablename="eventHandle"type="com.example.livedatapractice.EventHandleListener" /><variablename="imageUrl"type="String" /></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity">...<ImageViewandroid:id="@+id/imageView"android:layout_width="wrap_content"android:layout_height="wrap_content"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintHorizontal_bias="0.498"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintVertical_bias="0.097"app:src="@{imageUrl}"tools:srcCompat="@tools:sample/avatars" /></androidx.constraintlayout.widget.ConstraintLayout>
</layout>
  1. 在Activity中使用
activityMainBinding.setImageUrl(url);

当 ImageView 控件的 url 属性值发生变化时,dataBinding 就会将 ImageView 实例以及新的 url 值传递给 loadImage() 方法,从而可以在此动态改变 ImageView 的相关属性

双向绑定

BaseObservable

示例

继承BaseObservable类,

get方法使用@Bindable注解,

set方法添加notifyPropertyChanged(BR.firstName)通知绑定的视图(View)数据已经发生了变化,需要更新视图显示的内容

// 被观察者    viewModel
public class ObservableUser extends BaseObservable {private String firstName;private String lastName;public ObservableUser(String firstName, String lastName) {this.firstName = firstName;this.lastName = lastName;}@Bindablepublic String getFirstName() {return firstName;}@Bindablepublic String getLastName() {return lastName;}public void setFirstName(String firstName) {this.firstName = firstName;notifyPropertyChanged(BR.firstName);}public void setLastName(String lastName) {this.lastName = lastName;notifyPropertyChanged(BR.lastName);}
}

布局文件中采用@=符号,这里允许EditTextuser.firstName之间进行双向数据同步。

<?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><variablename="user"type="com.example.databindingpractice2.ObservableUser" /></data><LinearLayoutandroid:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity"><TextViewandroid:id="@+id/textView1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{user.lastName}"android:textSize="30dp" /><TextViewandroid:id="@+id/textView2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{user.firstName}"android:textSize="30dp" /><EditTextandroid:id="@+id/et"android:layout_width="186dp"android:layout_height="54dp"android:text="@={user.lastName}"android:textSize="30dp" /><EditTextandroid:id="@+id/et2"android:layout_width="186dp"android:layout_height="54dp"android:text="@={user.firstName}"android:textSize="30dp" /></LinearLayout>
</layout>

在主活动中将user对象与视图绑定

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);ObservableUser user = new ObservableUser("Yuyu","Feng");binding.setUser(user);}
}

ObservableField

与直接继承 Observable 类相比,ObservableField 更适合简单场景下的单一数据绑定,不需要复杂的通知操作,可以理解为官方对 BaseObservable 中字段的注解和刷新等操作的封装。Android 为常见的基本数据类型(如 intboolean 等)提供了对应的 ObservableX 类型,方便开发者使用。

ObservableBoolean
ObservableByte
ObservableChar
ObservableShort
ObservableInt
ObservableLong
ObservableFloat
ObservableDouble

BaseObservable的示例修改

public class ObservableUser {private ObservableField<String> firstName;private ObservableField<String>  lastName;public ObservableUser(String firstName, String lastName) {this.firstName = new ObservableField<>(firstName);this.lastName = new ObservableField<>(lastName);}public ObservableField<String> getFirstName() {return firstName;}public void setFirstName(ObservableField<String> firstName) {this.firstName = firstName;}public ObservableField<String> getLastName() {return lastName;}public void setLastName(ObservableField<String> lastName) {this.lastName = lastName;}
}


感谢您的阅读
如有错误烦请指正


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

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

相关文章

Pandas | 通过PUBG数据集进行数据分析并理解函数使用

PUBG数据分析 PUBG数据集train 数据分析iloc和loc 过滤参数人数少的比赛duplicated().count() 和 transform(count)countplot绘图函数 补充&#xff1a;查看判断pd的某一列是否没有重复值方法 1: 使用 duplicated() 方法方法 2: 使用 nunique() 方法方法 3: 使用 value_counts(…

4418 , TF 卡烧写, 无法启动,TF卡启动报错

问题: 在使用TF卡烧写的过程中,出现 TF卡无法启动的情况,报错如下: 解决:  我一直以为是 烧写的过程不对,或者是 烧写的uboot 镜像不对,或者是核心板有问题。 但是后来发现,我如果使用 另一台电脑 烧写HMI 的UBOOT的时候,我使用的是同一个 核心…

边缘计算网关助力煤矿安全远程监控系统

煤矿开采环境复杂&#xff0c;危险程度高&#xff0c;每一次事故都带给行业血淋淋的教训&#xff0c;安全问题也是政府与行业亟待解决的难题。伴随着技术的发展&#xff0c;煤矿智能化成为行业探索的新方向&#xff0c;降低安全风险也是智能化的重要目标之一。防微杜渐是安全生…

Markdown编辑器测试文章

Markdown编辑器测试文章 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一…

AI与测试行业调研

业务方向及应用场景 方向 技术 应用 大语言模型 私有化大模型&#xff1a; llama2 privateGPT 业务分析 测试数据生成 机器学习、深度学习应用 视觉自动化&#xff1a; FastbotApplitools 视觉自动化 缺陷预测与挖掘 知识图谱 neo4j 测试用例生成 精准测试 大语言模…

WEB前端使用标签制作网页

需要使用HTML的一些基本标签制作网页 基本代码如下: <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><body><form action"#" method"post" enctype"text/…

AI大模型应用开发:手把手教你部署并使用清华智谱GLM大模型

部署一个自己的大模型&#xff0c;没事的时候玩两下&#xff0c;这可能是很多技术同学想做但又迟迟没下手的事情&#xff0c;没下手的原因很可能是成本太高&#xff0c;近万元的RTX3090显卡&#xff0c;想想都肉疼&#xff0c;又或者官方的部署说明过于简单&#xff0c;安装的时…

nginx中的HTTP 负载均衡

HTTP 负载均衡&#xff1a;如何实现多台服务器的高效分发 为了让流量均匀分配到两台或多台 HTTP 服务器上&#xff0c;我们可以通过 NGINX 的 upstream 代码块实现负载均衡。 方法 在 NGINX 的 HTTP 模块内使用 upstream 代码块对 HTTP 服务器实施负载均衡&#xff1a; upstr…

Maven与Gradle的区别

Maven与Gradle是两种流行的构建工具&#xff0c;广泛用于Java项目的管理和构建。以下是它们的对比&#xff0c;包括官网、Windows 11配置环境、在IDEA中的相同点和不同点&#xff0c;以及它们各自的优缺点。 官网 Maven官网: https://maven.apache.orgGradle官网: https://gr…

[Linux网络编程]02-Socket编程

一.套接字(Socket) 在通信过程中&#xff0c;套接字一定是成对出现的(通信双方各持一个) 一个文件描述符指向一个套接字(该套接字内部由内核借助两个缓冲区实现读写),即一个套接字只有一个文件描述符&#xff0c;但有两个缓存区&#xff0c;与管道正好相反。 Linux套接字实现…

解决k8s集群中安装ks3.4.1开启日志失败问题

问题 安装kubesphere v3.4.1时&#xff0c;开启了日志功能&#xff0c;部署时有三个pod报错了 Failed to pull image “busybox:latest”: rpc error: code Unknown desc failed to pull and unpack image “docker.io/library/busybox:latest”: failed to copy: httpRead…

uniapp使用html2canvas时,页面内的image元素模糊

不废话很简单只需要将image改成img就行 改之前 改之后 原因可能是因为uniapp里面的image标签做了某种处理

QT教程-二十一,Qt动画类

目录 1. QPropertyAnimation 主要功能 示例 2. QVariantAnimation 主要功能 3. QAbstractAnimation 主要功能 4. QAnimationGroup 主要功能 5. QSequentialAnimationGroup 示例 6. QParallelAnimationGroup 示例 7. QEasingCurve 示例 8. 例子,实现一边移动一边…

1.计算机网络_基本知识

基本知识 计算机网络的类别&#xff1a; 1、按作用范围来分类 2、按网络的使用者来分类 什么是计算机网络&#xff1a; 计算机网络由若干个节点和链接这些节点的链路组成&#xff0c;节点可以是计算机、集线器、交换机、路由器等。互联网络是多个网络通过路由器连接在了一起…

具备技术二:正则表达式

一、C正则库 regex 用于报文的解析。 使用接口&#xff1a;bool regex_match(const string &src, smatch &matches, regex &e); src&#xff1a;要解释的字符串。 smatch&#xff1a;一个类似于数组的结构&#xff0c;用于存储一个个解释之后的字符串。 matche…

可视化大屏的C位放啥(02):3D建筑,数据的集大成展示。

3D 建筑以其立体、逼真的形态&#xff0c;瞬间抓住人们的眼球。它不仅仅是一个静态的模型&#xff0c;更是一个承载着丰富数据的载体。通过精细的建模&#xff0c;可以展示建筑的外观、结构、内部布局等多方面信息。 从数据展示的角度来看&#xff0c;3D 建筑可以与各种数据进…

【zookeeper】集群配置

zookeeper 数据结构 zookeeper数据模型结构&#xff0c;就和Linux的文件系统类型&#xff0c;看起来是一颗树&#xff0c;每个节点称为一个znode.每一个Znode默认的存储1MB的数据&#xff0c;每个Znode都有唯一标识&#xff0c;可以通过命令显示节点的信息每当节点有数据变化…

相同的树算法

给你两棵二叉树的根节点 p 和 q &#xff0c;编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同&#xff0c;并且节点具有相同的值&#xff0c;则认为它们是相同的。 示例 1&#xff1a; 输入&#xff1a;p [1,2,3], q [1,2,3] 输出&#xff1a;true示例 2&…

最新开发项目H5商城小程序源码系统 带源代码安装包以及搭建部署教程

系统概述 在当今数字化迅猛发展的时代&#xff0c;电子商务已成为企业拓展市场、提升品牌影响力的重要手段。H5商城小程序作为一种跨平台、轻量级的应用形式&#xff0c;凭借其无需下载安装、即用即走的特性&#xff0c;迅速赢得了广大用户的青睐。为了满足企业对高质量H5商城…

【工具变量】A股上市企业大数据应用(2001-2023年)-参考柏淑嫄实践

数据简介&#xff1a;企业数字化转型的浪潮孕育出大数据&#xff0c;大数据技术是在数据处理和应用中释放大数据多元价值的必要手段。大数据作为企业发展的战略资源和生产要素对企业转型发展具有重要意义。对上市企业大数据应用程度进行测算不仅有助于了解大数据相关技术在企业…