DataBinding viewBinding(视图绑定与数据双向绑定)简单案例 (kotlin)

先上效果:

4个view的文字都是通过DataBinding填充的。交互事件:点击图片,切换图片

创建项目(android Studio 2023.3.1)

Build.gradle(:app) 引入依赖库(完整源码)

    buildFeatures {
        viewBinding true
        compose true
    }
    dataBinding {
        enabled = true
    }

plugins {alias(libs.plugins.android.application)alias(libs.plugins.jetbrains.kotlin.android)id 'kotlin-kapt'
}android {namespace 'com.example.lanidemokt'compileSdk 31defaultConfig {applicationId "com.example.lanidemokt"minSdk 24targetSdk 30versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}compileOptions {sourceCompatibility JavaVersion.VERSION_1_8targetCompatibility JavaVersion.VERSION_1_8}kotlinOptions {jvmTarget = '1.8'}lintOptions {abortOnError false}buildFeatures {viewBinding truecompose true}dataBinding {enabled = true}
}dependencies {implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2"implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2"implementation "androidx.compose.ui:ui:1.0.1"implementation 'androidx.appcompat:appcompat:1.4.1'implementation 'androidx.appcompat:appcompat-resources:1.4.1'implementation 'com.google.android.material:material:1.5.0'implementation 'androidx.compose.material:material:1.0.1'implementation 'com.github.bumptech.glide:compiler:4.11.0'implementation 'com.github.bumptech.glide:glide:4.11.0'
}

1. 基本使用意向绑定数据显示在界面 

MainActivity.kt (完整源码)

在MainActivity.kt里,Databinding和我们的XML文件绑定起来了,现在你点击Databinding会发现直接可以跳转到对应的XML文件里面去了,

package com.example.lanidemoktimport android.os.Bundle
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.databinding.BaseObservable
import androidx.databinding.DataBindingUtil
import com.catchpig.utils.LogUtils
import com.example.lanidemokt.adapter.MainActivityBindingAdapter
import com.example.lanidemokt.databinding.ActivityMainBinding
import com.example.lanidemokt.viewmodel.ButtonClickListener
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.util.Dateclass MainActivity : AppCompatActivity() {/** DataBinding 对应一个Binding对象,对象名是布局文件文称加上Binding后缀* binding,activity_main.xml的布局实例* xml上所有变量与点击事件,必须是binding的成员属性或者成员方法函数,否则操作界面无效** */var binding: ActivityMainBinding? = null // 操作布局实例private var login: Login? = null  //声明一个响应式对象,用于uivar clickListener: ButtonClickListener? = null // 布局点击对象封装override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState) //        setContentView(R.layout.activity_main)binding = DataBindingUtil.setContentView(this, R.layout.activity_main)ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)insets}initView()initData()corGlobalTest()}private fun initData() {LogUtils.init(this)}/* ** 在Controller层,将我们的data与model相关联* */data class Login(var name: String = "LLL", var msg: String) //意向绑定响应式data class Student(var name: String = "LLL", var score: Int) : BaseObservable() //双击绑定响应式private fun initView() {binding?.msg?.setText("我是谁")login = Login("LANI", "我是谁")//  binding?.login = Login("LANI", "我是谁")//  这一步必须要,否则点击没反应,否则界面不显示对应的名字与信息binding?.setLogin(Login("LANI", "我是谁"))binding?.setStudent(Student("LEE", 199))binding?.picture1?.setOnClickListener {println("图片点击")MainActivityBindingAdapter.loadStudentDetails(it as ImageView,"http://192.168.1.207:8080/download/88.jpg")}clickListener=ButtonClickListener()binding?.btnHandler = clickListener}/** 协程创建* */fun corGlobalTest() {GlobalScope.launch {println("|--开始global${Date()}")delay(1000)println("|--END global${Date()}")}println("|--END ${Date()}")}
}
 activity_main.xml

现在我们就来看看如何给我们的XML文件里面的View设置值。

在XML文件的layout标签下,创建data标签,在data标签中再创建variable标签,variable标签主要用到的就是name属性和type属性,类似于Java语言声明变量时,需要为该变量指定类型和名称。新建一个名为Login的数据类。

在XML文件中声明好variable属性后,接下来就可以在XML使用它了。

使用variable属性时需要使用到布局表达式: @{ }

可以在布局表达式@{ }中获取传入variable对象的

 activity_main.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"xmlns:tools="http://schemas.android.com/tools"><data><variablename="login"type="com.example.lanidemokt.MainActivity.Login" /><variablename="student"type="com.example.lanidemokt.MainActivity.Student" /></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><TextViewandroid:id="@+id/msg"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{login.name}"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"tools:text="名字" /><TextViewandroid:id="@+id/msg2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{login.msg}"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@id/msg"tools:text="消息" /><TextViewandroid:id="@+id/msg4"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{ ` `+ student.score}"app:layout_constraintBottom_toBottomOf="@id/login"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/msg2"tools:text="消息2" /></androidx.constraintlayout.widget.ConstraintLayout>
</layout>

2. 给控件View添加响应事件:

方式一:直接在Controller层通过原来的方式添加

binding?.login?.setOnClickListener {}

 方式二:

创建一个工具类,在类中定义响应的点击事件

第一步:创建点击的工具类 ButtonClickListener.kt

第二步:在XML文件中添加工具类 ,在XML文件中添加响应事件:

第三步:在XML文件中添加响应事件 android:onClick="@{btnHandler::click}"

第四步:在Controller里面进行关联 binding?.btnHandler = clickListener

 activity_main.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"xmlns:tools="http://schemas.android.com/tools"><data><!--需要使用到响应数据类引入data标签中再创建variable标签,variable标签主要用到的就是name属性和type属性 ,类似于Java语言声明变量时,需要为该变量指定类型和名称--><import type="android.view.View" /><!--        <import type="com.example.lanidemokt.MainActivity" />--><!--        <variablename="login"type="com.example.lanidemokt.MainActivity.Login" />--><variablename="btnHandler"type="com.example.lanidemokt.viewmodel.ButtonClickListener" /><variablename="login"type="com.example.lanidemokt.MainActivity.Login" /><variablename="student"type="com.example.lanidemokt.MainActivity.Student" /></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><TextViewandroid:id="@+id/msg"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{login.name}"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"tools:text="名字" /><TextViewandroid:id="@+id/msg2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{login.msg}"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@id/msg"tools:text="消息" /><TextViewandroid:id="@+id/msg4"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{ ` `+ student.score}"app:layout_constraintBottom_toBottomOf="@id/login"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/msg2"tools:text="消息2" /><Buttonandroid:id="@+id/login"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="杀生丸哥哥"android:onClick="@{btnHandler::msgTextClickListener}"android:layout_marginBottom="20dp"app:layout_constraintBottom_toBottomOf="@id/picture1"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/msg4"tools:text="消息2" /><ImageViewandroid:id="@+id/picture1"android:layout_width="300dp"android:layout_height="200dp"android:layout_marginBottom="20dp"android:layout_marginTop="20dp"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@id/login"app:layout_constraintBottom_toBottomOf="parent"app:url="@{`http://192.168.1.207:8080/download/kn.png`}" /></androidx.constraintlayout.widget.ConstraintLayout>
</layout>
 ButtonClickListener.kt 源码
package com.example.lanidemokt.viewmodelimport android.view.View
import android.widget.TextView
import com.example.lanidemokt.utils.LogSettingclass ButtonClickListener {/** 界面点击事件封装* */fun msgTextClickListener(view: View) {view.text = "杀生丸丸哥哥一直很帅"
//        view.setText( "杀生丸丸哥哥一直很帅") //Use of setter method instead of property access syntax}
}

3. XXXBindingAdapter方法实现响应

使用DataBinding库时,DataBinding会针对控件属性生成对应的XXXBindingAdapter类,如TextViewBindingAdapter类,其对TextView的每个可以使用DataBinding的属性都生成了对应的方法,而且每个方法都使用了@BindingAdapter注解,注解中的参数就是对应View的属性。

自定义BindingAdapter 编写一个处理图片的自定义BindingAdapter类。然后定义一个静态方法,主要用于添加 BindingAdapter 注解,注解值是 ImageView 控件自定义的属性名,如下所示。

MainActivityBindingAdapter.kt (源码)

图片资源是部署到本地的Nginx上的:

http://192.168.1.207:8080/download/kn.png

package com.example.lanidemokt.adapterimport android.util.Log
import android.widget.ImageView
import androidx.databinding.BindingAdapter
import com.bumptech.glide.Glide
import com.catchpig.utils.LogUtils
import com.example.lanidemokt.utils.LogSettingclass MainActivityBindingAdapter {companion object {val TAG: String = "MainActivityBindingAdapter"/** 通过默认adapter 设置自定app:xxx属性,并设置xx属性值,实现响应式修改更新** */@BindingAdapter("url")@JvmStaticfun loadStudentDetails(view: ImageView,url: String = "http://192.168.1.207:8080/download/kn.png") {Glide.with(view!!).load(url).into(view)}}
}

多个参数的话,修改@BindingAdapter有value


        @BindingAdapter(value = ["url", "placeholder", "error"])
        @JvmStatic 

4.双向响应绑定(输入框)

输入数字时,消息text同步更新

Build.gradle(:app) 引入依赖库(完整源码)

增加自动生成BR实体的依赖库, 

id 'kotlin-kapt'
kapt {generateStubs = true
}
kapt  "androidx.room:room-compiler:2.4.0"

 

plugins {alias(libs.plugins.android.application)alias(libs.plugins.jetbrains.kotlin.android)id 'kotlin-kapt'
}android {namespace 'com.example.lanidemokt'compileSdk 31defaultConfig {applicationId "com.example.lanidemokt"minSdk 24targetSdk 30versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}compileOptions {sourceCompatibility JavaVersion.VERSION_1_8targetCompatibility JavaVersion.VERSION_1_8}kotlinOptions {jvmTarget = '1.8'}lintOptions {abortOnError false}buildFeatures {viewBinding true
//        dataBinding  truecompose true}dataBinding {enabled = true}kapt {generateStubs = true}
}
dependencies {implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2"implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2"implementation "androidx.compose.ui:ui:1.0.1"implementation 'androidx.appcompat:appcompat:1.4.1'implementation 'androidx.appcompat:appcompat-resources:1.4.1'implementation 'com.google.android.material:material:1.5.0'implementation 'androidx.compose.material:material:1.0.1'implementation 'com.github.bumptech.glide:compiler:4.11.0'implementation 'com.github.bumptech.glide:glide:4.11.0'kapt  "androidx.room:room-compiler:2.4.0"
}

 

MainActivity.kt 源码

增加绑定viewmodel:    binding?.order = OrderViewModel() // 绑定双向响应实体

package com.example.lanidemoktimport android.os.Bundle
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.databinding.BaseObservable
import androidx.databinding.DataBindingUtil
import com.catchpig.utils.LogUtils
import com.example.lanidemokt.adapter.MainActivityBindingAdapter
import com.example.lanidemokt.databinding.ActivityMainBinding
import com.example.lanidemokt.viewmodel.ButtonClickListener
import com.example.lanidemokt.viewmodel.OrderViewModel
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.util.Dateclass MainActivity : AppCompatActivity() {/** DataBinding 对应一个Binding对象,对象名是布局文件文称加上Binding后缀* binding,activity_main.xml的布局实例* xml上所有变量与点击事件,必须是binding的成员属性或者成员方法函数,否则操作界面无效* 布局取响应式值 -表达式: `@{ }** */var binding: ActivityMainBinding? = null // 操作布局实例private var login: Login? = null  //声明一个响应式对象,用于uivar clickListener: ButtonClickListener? = null // 布局点击对象封装var vm: OrderViewModel = OrderViewModel()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState) //        setContentView(R.layout.activity_main)binding = DataBindingUtil.setContentView(this, R.layout.activity_main)ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)insets}initView()initData()corGlobalTest()}private fun initData() {LogUtils.init(this)}/* ** 在Controller层,将我们的data与model相关联* */data class Login(var name: String = "LLL", var msg: String) //意向绑定响应式data class Student(var name: String = "LLL", var score: Int) : BaseObservable() //双击绑定响应式private fun initView() {binding?.msg?.setText("我是谁")login = Login("LANI", "我是谁")//  binding?.login = Login("LANI", "我是谁")//  这一步必须要,否则点击没反应,否则界面不显示对应的名字与信息binding?.setLogin(Login("LANI", "我是谁"))binding?.setStudent(Student("LEE", 199))MainActivityBindingAdapter.loadStudentDetails(binding?.picture1 as ImageView,"http://192.168.1.207:8080/download/kn.png")binding?.picture1?.setOnClickListener {println("图片点击")LogUtils.d("图片点击")MainActivityBindingAdapter.loadStudentDetails(it as ImageView,"http://192.168.1.207:8080/download/88.jpg")}clickListener = ButtonClickListener()binding?.btnHandler = clickListener //给控件添加响应事件 :点击事件binding?.order = OrderViewModel() // 绑定双向响应实体}/** 协程创建* */fun corGlobalTest() {GlobalScope.launch {println("|--开始global${Date()}")delay(1000)println("|--END global${Date()}")}println("|--END ${Date()}")}
}
OrderViewModel.kt 源码

实现双向绑定 viewmodel,BaseObservable :普通的数据对象包装成一个可观察的数据对象

package com.example.lanidemokt.viewmodelimport androidx.databinding.BaseObservable
import androidx.databinding.Bindable
import com.catchpig.utils.LogUtils
import com.example.lanidemokt.BRclass OrderViewModel : BaseObservable() {/** 实现双向绑定 viewmodel,* BaseObservable :普通的数据对象包装成一个可观察的数据对象* 当使用name字段发生变更后,若想UI自动刷新,* 要求方法名必须以get开头并且标记Bindable注解* 注解才会自动在build目录BR类中生成entry* 数据模型继承 BaseObservable;* 要求获取数据方法名必须以 get 开头并且标记 @Bindable 注解;* 设置数据方法必须以 set 开头然后调用 notify() 函数既可以刷新视图。* BR 类是 BaseObservable 子类中由 @Bindable 注解修饰的函数生成;* BR 类生成位置在 //app\build\generated\source\kapt\debug\com\example\lanidemokt** */@get:Bindablevar orderCount: String? = "100"set(orderCount) {LogUtils.d("当前orderCount=${orderCount}")field = orderCountnotifyPropertyChanged(BR.orderCount)}}
activity_main.xml源码

引入viewmodel:

<variable name="order"  type="com.example.lanidemokt.viewmodel.OrderViewModel" />

<?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="android.view.View" /><variablename="order"type="com.example.lanidemokt.viewmodel.OrderViewModel" /><variablename="btnHandler"type="com.example.lanidemokt.viewmodel.ButtonClickListener" /><variablename="login"type="com.example.lanidemokt.MainActivity.Login" /><variablename="student"type="com.example.lanidemokt.MainActivity.Student" /></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><Buttonandroid:id="@+id/login"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="20dp"android:onClick="@{btnHandler::msgTextClickListener}"android:text="杀生丸哥哥"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/msg4"tools:text="杀生丸哥哥" /><TextViewandroid:id="@+id/msg5"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="20dp"android:text="@{ ` 当前订单数量:`+order.orderCount}"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/login"tools:text="消息2" /><!-- 双向响应数据,赋值语法  @={xx.xx}--><EditTextandroid:id="@+id/username"android:layout_width="100dp"android:layout_height="wrap_content"android:text="@={order.orderCount}"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@id/msg5" /><!--  XXXBindingAdapter方式设置app:url   --><ImageViewandroid:id="@+id/picture1"android:layout_width="300dp"android:layout_height="200dp"android:layout_marginTop="20dp"android:layout_marginBottom="20dp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@id/login"app:url="@{`http://192.168.1.207:8080/download/kn.png`}" /></androidx.constraintlayout.widget.ConstraintLayout>
</layout>

双向响应完结。

-- 设置网络图片在ImageView 打开网络权限

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><uses-permission android:name="android.permission.INTERNET"/><applicationandroid:allowBackup="true"android:dataExtractionRules="@xml/data_extraction_rules"android:fullBackupContent="@xml/backup_rules"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:networkSecurityConfig="@xml/network_security_config"android:theme="@style/Theme.LaniDemoKt"tools:targetApi="31"><activityandroid:name=".MainActivity"android:usesCleartextTraffic="true"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

app\src\main\res\xml\network_securit_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config><base-config cleartextTrafficPermitted="true" />
</network-security-config>

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

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

相关文章

java中的HashSet类

一、HashSet类 实现了Set接口&#xff0c;无法存储重复元素 特点&#xff1a;元素位置无序、无索引、底层是HashMap 1、构造方法 内部是HashMap的构造方法 2、add方法 (1)元素在底层存储使用到了三种数据结构&#xff1a;hash数组、链表、树 (2)添加流程&#xff08;根据…

告别登录烦恼,WPS免登录修改器体验!(如何实现不登录使用WPS)

文章目录 &#x1f4d6; 介绍 &#x1f4d6;&#x1f3e1; 演示环境 &#x1f3e1;&#x1f4d2; 解决方案 &#x1f4d2;&#x1f388; 获取方式 &#x1f388;⚓️ 相关链接 ⚓️ &#x1f4d6; 介绍 &#x1f4d6; 想象一下&#xff0c;如果你能够绕过繁琐的登录流程&#x…

C# WinForm —— 22 Forms.Timer 组件介绍与使用

1. 简介 Timer 计时器 组件不会出现在窗体中&#xff0c;每隔 定义的间隔时间&#xff0c;就会触发事件&#xff0c;主要应用于Windows应用程序&#xff0c;独占一个线程&#xff0c;可以修改 UI 元素 属性 属性解释(Name)控件ID&#xff0c;在代码里引用的时候会用到,一般…

运营美区TikTok小店常见问题汇总,你中了几个?

大家好&#xff0c;我是IPdodo的小编&#xff0c;专注于分享出海网络解决方案&#xff0c;致力于为TikTok运营人提供解决视频0播放、直播间卡顿、不进人甚至封号等问题的跨境网络专线。目前已经帮助数千位用户成功开启跨境业务。 今天&#xff0c;将针对美区TikTok小店的常见问…

Swift使用JSONDecoder处理json数据,实现json序列化和反序列化

Json数据处理是开发中不可获取的一项技能&#xff0c;如果你不会处理json数据&#xff0c;那你离失业就不远了&#xff0c;所以学完了swift基础教程&#xff0c;还是先老老实实学习一下json处理吧&#xff0c;有了这项技能&#xff0c;你才可以继续下一个网络请求阶段的开发&am…

Git总结超全版

最近想系统的回顾一下Git的使用&#xff0c;如果只想快速的集成git到idea&#xff0c;可以参考另一篇我的博客中的git部分 目录 版本管理工具简介Git安装与配置Git远程仓库配置 Git常用命令为常用命令配置别名(可选)Git忽略文件.gitignore一些概念*本地仓库操作删除仓库内容 *远…

滴滴三面 | Go后端研发

狠狠的被鞭打了快两个小时… 注意我写的题解不一定是对的&#xff0c;如果你认为有其他答案欢迎评论区留言 bg&#xff1a;23届 211本 社招 1. 自我介绍 2. 讲一个项目的点&#xff0c;因为用到了中间件平台的数据同步&#xff0c;于是开始鞭打数据同步。。 3. 如果同步的时候…

Sketch v100 for Mac 安装教程【支持M芯片】

Sketch v100 for Mac 安装教程【支持M芯片】 原文地址&#xff1a;https://blog.csdn.net/weixin_48311847/article/details/139104315

CasaOS系统玩客云安装内网穿透工具实现无公网IP远程访问

文章目录 前言1. CasaOS系统介绍2. 内网穿透安装3. 创建远程连接公网地址4. 创建固定公网地址远程访问 前言 2月底&#xff0c;玩客云APP正式停止运营&#xff0c;不再提供上传、云添加功能。3月初&#xff0c;有用户进行了测试&#xff0c;局域网内的各种服务还能继续使用&am…

【学习笔记】后端(Ⅰ)—— NodeJS(Ⅰ)

NodeJS 1、概述 1.1、NodeJS是什么 1.2、NodeJS的主要作用 1.3、NodeJS的优点 1.4、NodeJS 与 浏览器 的 JavaScript 对比 1.4.1 ECMAScript 介绍 1.4.2 JavaScript 介绍 1.4.3 TypeScript 介绍2、基础篇 2.1、Buff…

LangChain带你轻松玩转ChatGPT等大模型开发

大家好&#xff0c;我是herosunly。985院校硕士毕业&#xff0c;现担任算法研究员一职&#xff0c;热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名&#xff0c;CCF比赛第二名&#xff0c;科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的…

Python中cv2 (OpenCV, opencv-python)库的安装、使用方法demo最新详细教程

&#x1f42f; Python中cv2 (OpenCV, opencv-python)库的安装、使用方法demo最新详细教程 &#x1f4f8; 文章目录 &#x1f42f; Python中cv2 (OpenCV, opencv-python)库的安装、使用方法demo最新详细教程 &#x1f4f8;摘要引言正文&#x1f4d8; OpenCV库概述&#x1f680; …

【Git教程】(十九)合并小型项目 — 概述及使用要求,执行过程及其实现,替代解决方案 ~

Git教程 合并小型项目 1️⃣ 概述2️⃣ 使用要求3️⃣ 执行过程及其实现 在项目的初始阶段&#xff0c;往往需要针对重要的设计决策和技术实现原型实验。当原型评估结束后&#xff0c;需要将那些成功的原型合并起来称为整个项目的初始版本。 在这样的情景中&#xff0c;各个原…

php代码审计参考

代码审计思路&#xff1a; 从个人角度出发&#xff0c;如果环境允许的话&#xff0c;可以先选择做一个”程序员“再来做代码审计。因为从开发者的位置去思考问题&#xff0c;可以快速定位问题。学习面向对象编程以及面向过程编程&#xff0c;编写一些 项目提升对代码的理解能力…

Android Compose 六:常用组件 Button

Button 1 简单使用 Button(onClick { /*TODO*/ }) {Text(text "我是一只button里的text")}效果 颜色为什么是这个样子&#xff1f; 前面Text里我们讲过 主题色会影响组件的颜色 这里我使用的颜色如下 primary Color(0xFFFF0000),onPrimary Color(0xFF00FF00),p…

什么是合法IP地址?

IP地址&#xff0c;即互联网协议地址&#xff0c;是网络设备在互联网上进行通信的唯一标识符。IP地址有两种主要版本&#xff1a;IPv4和IPv6。为了保证网络通信的正常进行&#xff0c;IP地址需要是合法的。本文将详细阐述什么是合法IP地址&#xff0c;以及其重要性和验证方法。…

如何给实拍添加旋转模糊效果?视频模糊特效PR模板剪辑素材

PR特效模板&#xff0c;高级旋转模糊效果视频模板剪辑素材。 特征&#xff1a; After Effects 2019及以上兼容项目。 Premiere Pro 2021及以上兼容项目。 可用分辨率&#xff08;4K–HD–方形–移动&#xff09;。 不需要插件。 包括教程。 免费下载&#xff1a;https://prmu…

宝藏级丨图解项目管理全流程(上篇)

《项目管理知识体系指南》的定义&#xff1a;项目是为创造独特的产品、服务或成果而进行的临时性工作。项目管理就是将各种知识、技能、工具与技术应用于项目活动&#xff0c;以满足项目的要求。项目管理的全流程包括以下几个阶段&#xff1a; 项目启动阶段。这是开始一个新项…

GAN实例基于神经网络

目录 1.前言 2.实验 1.前言 需要了解GAN的原理查看对抗生成网络&#xff08;GAN&#xff09;&#xff0c;DCGAN原理。 采用手写数字识别数据集 2.实验 import argparse import os import numpy as np import mathimport torchvision.transforms as transforms from torchvi…

RedisTemplate使用最详解(三)--- opsForHash()

1、put(H var1, HK var2, HV var3) 新增hashMap值 var1 为Redis的keyvar2 为key对应的map值的keyvar3 为key对应的map值的值var2相同替换var3 redisTemplate.opsForHash().put("hashValue","map1","value1"); redisTemplate.opsForHash().put(&q…