Jetpack Compose -> 声明式UI Modifier

前言

本章主要介绍下 Compose 的声明式 UI 以及初级写法;

什么是声明式UI

传统UI

传统 UI 方式来声明UI

<androidx.appcompat.widget.LinearLayoutCompat    
    android:layout_width="match_parent"    
    android:layout_height="match_parent"    
    android:orientation="vertical">    
    <androidx.appcompat.widget.AppCompatImageView        
        android:layout_width="match_parent"        
        android:scaleType="centerCrop"        
        android:layout_height="300dp" />
</androidx.appcompat.widget.LinearLayoutCompat>

是通过 xml 来进行显示的,显示文字的方式是使用 TextView,它内部显示文字的方式有两种,一种是在 xml 中直接设置,通过下面这种方式设置

android:text="@string/app_name"

这种方式是通过初始值在 xml 中进行预设置的;

还有一种是在代码中直接调用 setText 进行设置

TextView textView = findViewById(R.id.text);
textView.setText("xxxx");

代码中是通过 setText 后续对值进行手动更新的;

这种需要手动对界面更新的方式 就不是声明式,属于传统式

声明式UI

指的是:在写界面的时候,只需要对界面进行一次性的声明,而不用在各种条件对界面元素进行跟条件有关的更新;

声明式 UI 自动更新界面,不需要手动更新,而传统式需要手动更新界面;

例如我们写一个 Compose 的 Text

Text(    
    text = "Hello $name!",    
    modifier = modifier
)

我们只需要把 name 作为参数传给这个 Text ,这个文字控件就会显示 name 的值;而声明式 UI 它不仅会用 name 来初始化显示 name 的值,当 name 的值发生变化的时候,Text 所显示的内容也会跟着发生改变,比如 name 的初始值是 Mars,界面第一时间显示的就是 Mars,过了一会这个 name 的值变成了 老A 了,那么界面就会跟着变成 老A,而不需要再次调用 setText 进行更新;这就是声明式 UI;并不是说界面是用声明式写出来的,而是说只需要声明就够了,不需要任何的手动更新;

传统式再次调用 setText 才能更新,这个调用不能省略,否则不会发生更新;

Compose 怎么写?

一种是直接创建一个 Compose 项目,一种是项目中增加配置,让它支持 Compose;

我的 Android Stuido 版本,可以直接创建 Compose 项目,并且这个版本的 AS 已经默认创建的就是 Compose 项目了;

点击 Next 创建完成;

完成之后,我们在 MainActivity 中可以看到一个大概的构建逻辑:

区别与传统的方式,我们通过一个 setContent 函数开启了我们的 Compose 之旅;

文字 Text 的声明

setContent {    
    Text("老A")
}

运行我们的程序,然后就可以在界面上看到 老A

Text 函数还有很多其他的用法,大家根据 API 直接去探索使用即可

图片 Image 的声明

传统 ImageView 显示图片的方式有两种,一种是位图,也就是 Bitmap;一种是矢量图,也就是 VectorDrawable;

但是在 Compose 中位图提供了一个新的 API,ImageBitmap;矢量图也提供了一个新的 API,ImageVector;

到这里的时候,可能很多人就会有疑问了,为什么要区别开来?

因为 Compose 的初衷是独立于 Android 平台,这个 [独立于平台] 说的就是不依赖于最新的 Android 系统才能使用;

例如我们熟悉的 RecyclerView,ViewPager2,AppCompat,协调者布局,ViewModel 等等一系列 Jetpack 组件,任何一个库出了新版本就能直接发布,开发者就可以直接使用,不需要等升级到最新的 Android 系统版本之后才能使用;

Compose 不仅独立与最新版本的 Android ,还独立于 Android 平台;Compose 提供的所有 API 全都不带有 Android 的痕迹;

虽然 Compose 不带有 Android 痕迹了,但是它底层还是使用的 Android 的 drawText()、drawTextRun()(可以看下这个链接,针对这两个 api 的介绍)、Canvas 来进行的绘制;

更精确的说:是上层暴露给开发者的 API 是独立于 Android 平台的;

声明一个图片 使用 Image,如果想使用 drawable 文件夹下的图片,使用 painterResource 来传递一个资源 id;

Image(
    painterResource(    
        id = R.drawable.ic_launcher_foreground),    
        contentDescription = resources.getString(R.string.app_name)
)

painterResource 这个函数内部会创建一个 ImageBitmap 或者 ImageVector 对象,取决于传递进去的时候位图还是矢量图,不过这就跟外部调用的没有关系了;painter 跟 Android 中的 drawable 比较类似,我们也可以不使用 painterResource 直接传递一个 ImageBitmap、ImageVector 也是可以的;

运行效果如上;

网络图片的加载,就需要依赖第三方库了,这里推荐一个图片库 Coil (Android 官方推荐 Coroutine Image Loader)这个库是面向 kotlin 和协程的,同时它还不是面向 View 系统的,

使用的话,直接引入依赖即可

implementation("io.coil-kt:coil-compose:2.5.0")

然后还是使用 Image 函数

Image(    
    rememberAsyncImagePainter("https://img2.baidu.com/it/u=1866466367,1635278877&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=734"),    
    contentDescription = resources.getString(R.string.app_name),    
    modifier = Modifier.size(150.dp)
)

只不过 painterResource 替换成了 rememberAsyncImagePainter,就可以传递一个网络图片url,并进行加载;

设置图片尺寸,使用 Modifier 关键字;

别忘了添加网络权限

<uses-permission android:name="android.permission.INTERNET"/>

运行效果如下:

早期的 Coil 并没有支持 Jetpack Compose,如果你使用的 Coil 版本比较低,可以使用另外一个库 Accompanist 

Image 的底层也是最终调用的 Android 的原生 API drawBitmap,如果是纯色,就是 Canvas 的 drawColor 等 API;

图标 Icon 的声明

在 Compose 中,图标的声明使用 Icon 函数;

Column {
    Icon(    
        imageVector = Icons.Filled.Favorite, contentDescription = ""
    )
}

运行效果如下:

Icon 的用法基本上和 Image 上一样;

按钮 Button 的声明

在Compose当中,Button 和 Text 之间并没有什么关系。它们是两个独立的控件,并且通常它们还需要配合在一起使用才行;

先来看下不配合 Text 的效果

Button(onClick = {}) {    }

运行效果如下:

按钮是没有文案的,需要给 Button 设置一个文案

Button(onClick = {}) { 
    Text(text = "我是老A")
}

运行效果如下:

点击事件的话,就直接在 onClick = { }  中处理即可

Button(onClick = {    
    Toast.makeText(LocalContext.current as Context, "", Toast.LENGTH_LONG).show()
}) {    
    Text(text = "我是老A")
}

输入框 TextFiled 的声明

在 Compose 中,使用 TextFiled 代替了 EditText

var text by remember { mutableStateOf("") }
TextField(
    value = text, 
    onValueChange = {       
        text = it                                
    }, 
    label = {Text(text = "用户名")})

运行效果如下:

可以看到,实现了 EditeText 的效果,还是 Material 风格的;

TextField 函数还有很多其他的用法,大家根据 API 直接去探索使用即可;

使用 Layout 的 Compose 平替

Android 中常用的布局有 FrameLayout、 LinearLayout、RelativeLayout、ConstraintLayout、ScrollView、RecyclerView、ViewPager 等等

Compose 中的平替控件

FrameLayout ->  Box()

Box {
    Text(
       text = "老A"
       color = Color(0XFF886600) 
    )
    Image(
        rememberAsyncImagePainter("https://img2.baidu.com/it/u=1866466367,1635278877&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=734"),        contentDescription = resources.getString(R.string.app_name),        modifier = Modifier.size(150.dp)
    )
}

运行效果如下:

可以看到,和上面截图排列一样,也就是说,不使用布局控件,默认就是 FrameLayout排列;

LinearLayout -> Column()、Row() 表示纵向和横向;

Column {
    Text(
       text = "老A"
       color = Color(0XFF886600) 
    )
    Image(
        rememberAsyncImagePainter("https://img2.baidu.com/it/u=1866466367,1635278877&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=734"),        contentDescription = resources.getString(R.string.app_name),        modifier = Modifier.size(150.dp)
    )
}

运行效果如下:

Row {
    Text(
       text = "老A"
       color = Color.Blue
    )
    Image(
        rememberAsyncImagePainter("https://img2.baidu.com/it/u=1866466367,1635278877&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=734"),        contentDescription = resources.getString(R.string.app_name),        modifier = Modifier.size(150.dp)
    )
}

运行效果如下:

RelativeLayout -> Box()

RelativeLayout 也是使用 Box 平替,但是通过 Modifier 来修改相对位置;

Box(modifier = Modifier.border(2.dp, Color.Black).size(200.dp)){    
    Text(        
        text= "老A",        
        color = Color.Blue    
    )    
    Image(        
        rememberAsyncImagePainter("https://img2.baidu.com/it/u=1866466367,1635278877&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=734"),        
        contentDescription = resources.getString(R.string.app_name),        
        modifier = Modifier.size(150.dp).align(Alignment.CenterEnd)    
    )
}

运行效果如下:

ConstraintLayout ->  ConstraintLayout for Compose

因为约束布局非常好用,所以官方为我们迁移到了 Compose 平台,我们可以直接使用这个控件;这里并不是套壳支持,而是把它们的逻辑移植到了 Compose 里面;

implementation("androidx.constraintlayout:constraintlayout-compose:+")
ConstraintLayout(modifier = Modifier    
    .border(2.dp, Color.Black)    
    .size(400.dp)    
    .padding(10.dp)) {    
    val (portraitImageRef, usernameTextRef, desTextRef) =  remember { createRefs() }    
    Image(        
        rememberAsyncImagePainter("https://img2.baidu.com/it/u=1866466367,1635278877&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=734"),        
        contentDescription = "",        
        modifier = Modifier.size(150.dp).constrainAs(portraitImageRef){            
            top.linkTo(parent.top)            
            bottom.linkTo(parent.bottom)            
            start.linkTo(parent.start)        
        })    
    Text(        
        text = "我是老A",        
        fontSize = 16.sp,        
        maxLines = 1,        
        textAlign = TextAlign.Left,        
        modifier = Modifier.constrainAs(usernameTextRef) {            
            top.linkTo(portraitImageRef.top)            
            start.linkTo(portraitImageRef.end, 10.dp)        
        })    
    Text(        
        text = "这是我的个人描述",        
        fontSize = 12.sp,        
        maxLines = 1,        
        color = Color.Red,        
        fontWeight = FontWeight.Light,        
        modifier = Modifier.constrainAs(desTextRef) {                
            top.linkTo(usernameTextRef.bottom, 5.dp)            
            start.linkTo(portraitImageRef.end, 10.dp)        
        })
}

运行效果如下:

使用 RecyclerView(竖向) 的 Compose 平替 -> LazyColumn

val names = listOf("Jordan", "Kobe", "James", "Wade", "Paul")
LazyColumn { // 没有 adapter,没有 ViewHolder    
    items(names.size) {        
        Text(text = names[it])    
    }
}

运行效果如下:

items 是遍历,item 是设置单个列表项,而且可以使用 item 来添加header、footer,也可以设置不同的 itemType,也就是不同的 ViewHolder;

val names = listOf("Jordan", "Kobe", "James", "Wade", "Paul")
LazyColumn {    
    item {        
        Text(text = "header")    
    }    
    items(names.size) {        
        Text(text = names[it])    
    }    
    item {        
        Text(text = "footer")  
    }
}

运行效果如下:

设置不同的 itemType,

val names = listOf("Jordan", "Kobe", "James", "Wade", "Paul", "Jordan", "Kobe", "James", "Wade", "Paul", "Jordan", "Kobe", "James", "Wade", "Paul")
LazyColumn {    
    item {        
        Text(text = "header")    
    }    
    items(names.size) {        
        Text(text = names[it])    
    }    
    item {        
        Image(            
            rememberAsyncImagePainter("https://img2.baidu.com/it/u=1866466367,1635278877&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=734"),            
            contentDescription = resources.getString(R.string.app_name),            
            modifier = Modifier.size(150.dp)        
        )    
    }    
    items(names.size) {        
        Text(text = names[it])    
    }    
    item {        
        Image(            
            rememberAsyncImagePainter("https://img2.baidu.com/it/u=1866466367,1635278877&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=734"),            
            contentDescription = resources.getString(R.string.app_name),            
            modifier = Modifier.size(150.dp)        
        )    
    }
}

运行效果如下:

可以看到,直接就可以滑动了,也就是实现了 Rechyclerview 的效果;

使用 RecyclerView(横向) 的 Compose 平替 -> LazyRow

val names = listOf("Jordan", "Kobe", "James", "Wade", "Paul", "Jordan", "Kobe", "James", "Wade", "Paul", "Jordan", "Kobe", "James", "Wade", "Paul")
LazyRow {    
    item {        
        Text(text = "header")    
    }    
    items(names.size) {        
        Text(text = names[it])    
    }    
    item {        
        Image(            
            rememberAsyncImagePainter("https://img2.baidu.com/it/u=1866466367,1635278877&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=734"),            
            contentDescription = resources.getString(R.string.app_name),            
            modifier = Modifier.size(150.dp)        
        )    
    }    
    items(names.size) {        
        Text(text = names[it])    
    }    
    item {        
        Image(            
            rememberAsyncImagePainter("https://img2.baidu.com/it/u=1866466367,1635278877&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=734"),            
            contentDescription = resources.getString(R.string.app_name),            
            modifier = Modifier.size(150.dp)        
        )    
    }
}

运行效果如下,横向滑动的列表:

使用 ScrollView(竖向) 的 Compose 平替 -> Modifier.verticalScroll

Android 中还有一个滑动组件:ScrollView,它的内部不是动态的,它内部的内容都是预先编排好的,而不是让它自己算的,它内部的布局也是在第一时间就加载好的,而不是滑动到什么地方才加载,如果 ScrollView 加载一个很长很长的布局,有可能会内存溢出的;

而在 Compose 中的平替是没有 ScrollView 的概念的,你只需要给你需要滑动的组件加上 Modifier.verticalScroll() 函数就可以实现竖向滑动;

Column(Modifier.requiredSize(200.dp)    
        .background(Color.Blue)    
        .verticalScroll(rememberScrollState())) {    
        repeat(20) {        
            Text(            
                text= "老A",            
                color = Color.Red        
            )    
        }
}

运行效果如下:

使用 ScrollView(横向) 的 Compose 平替 -> Modifier.horizontalScroll

Row(Modifier.requiredSize(200.dp)    
        .background(Color.Blue)    
        .horizontalScroll(rememberScrollState())) {            repeat(20) {        
            Text(            
                text= "老A",            
                color = Color.Red        
            )    
        }
}

运行效果如下:

使用 ViewPager(竖向) 的 Compose 平替 -> VerticalPager

VerticalPager(10) { page ->     
    Text(        
        text = "Page: $page",        
        modifier = Modifier.fillMaxWidth()    
    )
}

运行效果如下:

使用 ViewPager(横向) 的 Compose 平替 -> HorizontalPager

HorizontalPager(10) { page ->     
    Text(        
        text = "Page: $page",        
        modifier = Modifier.fillMaxWidth()    
    )
}

这里就不运行显示了,大家可以自己运行看下效果

Modifier

padding & margin

现在我们知道怎么去写布局了,其中线性布局是我们开法中用的最多的布局了,但是我们一般并不只是在那放一个线性布局就OK了,而是我们需要做很多很多的细节设置,比如我们需要去设置一些边距,margin、padding 等等,而在 Compose 中需要使用另外一种方式来设置边距,它就是 Modifier;

Modifier 是 Compose 中的一个很重要的角色,UI 的很多设置都是通过 Modifier 来完成的,通过官方文档,我们可以知道,Modifier 有如下四个作用:

借助修饰符(Modifier),您可以修饰或扩充可组合项。您可以使用修饰符(Modifier)来执行以下操作:

  • 更改可组合项的大小、布局、行为和外观;
  • 添加信息,如无障碍标签;
  • 处理用户输入;
  • 添加高级互动,如使元素可点击、可滚动、可拖动或可缩放;

比如,我们想给一个 Row 设置一个 10dp 的 padding,我们可以这么实现

Row(Modifier.padding(8.dp)) {
    
}

但是 Compose 中的 Modifier 是没有 margin 的概念的,我们在 Andriod 中使用 padding 和 margin 来设置内边距和外边距,通常是因为背景色的原因,margin 是外边距,它是不包含在背景之内的,而 padding 它是内边距;

我们在 Compose 中设置背景色的时候,也是通过 Modifier 来执行的,Modifier.background(),但是 Modifier 对调用顺序是有先后要求的,我们可以看下下面的这个例子,以及我们如果和通过 padding 来实现 margin 的效果:

Row(    
    Modifier        
        .background(Color.Red)        
        .padding(10.dp)) {    
    Image(        
        rememberAsyncImagePainter("https://img2.baidu.com/it/u=1866466367,1635278877&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=734"),        
        contentDescription = resources.getString(R.string.app_name),        
        modifier = Modifier.size(150.dp)    
    )        
    
    Text(
        text = "我是老A", 
        Modifier.background(Color.Green).padding(10.dp)
    )    

    Text(
        text = "老A是我", 
        Modifier.padding(10.dp).background(Color.Green)
    )
}

运行效果:

可以看到 我是老A 是把背景色包含进来了,而 老A是我 是不包含的,也是 Modifier  的一个特点,设置有先后

这样,我们就只需要 padding 这一个函数就可以了;

background

我们看到,background 其实是有两个参数的,一个设置背景色,一个是 Shape,也就是形状,也就是说,我们可以给 background 设置一个形状,我们来看下效果

Row(    
    Modifier        
        .background(Color.Red, RoundedCornerShape(10.dp)) // 给背景设置一个圆角        
        .padding(10.dp)) {    
    Image(        
        rememberAsyncImagePainter("https://img2.baidu.com/it/u=1866466367,1635278877&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=734"),        
        contentDescription = resources.getString(R.string.app_name),        
        modifier = Modifier.size(150.dp)    
    )        
    
    Text(
        text = "我是老A", 
        Modifier.background(Color.Green).padding(10.dp)
    )    

    Text(
        text = "老A是我", 
        Modifier.padding(10.dp).background(Color.Green)
    )
}

运行效果如下:

我们的 CardView,可以通过 Modifier 来实现;

clip(shape: Shape)

Modifier 还提供了一个切割函数 clip,可以切各种东西,例如可以切图片,我们看下面这个例子

Row(    
    Modifier        
        .background(Color.Red, RoundedCornerShape(10.dp)) // 给背景设置一个圆角        
        .padding(10.dp)) {    
    Image(        
        rememberAsyncImagePainter("https://img2.baidu.com/it/u=1866466367,1635278877&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=734"),        
        contentDescription = resources.getString(R.string.app_name), 
        // 将图片切成圆的       
        modifier = Modifier.clip(CircleShape).size(150.dp)    
    )        
    
    Text(
        text = "我是老A", 
        Modifier.background(Color.Green).padding(10.dp)
    )    

    Text(
        text = "老A是我", 
        Modifier.padding(10.dp).background(Color.Green)
    )
}

运行效果如下:

因为图片的左右是透明的,所以看不出来效果;已经把图片切割成圆的了;

layout_width & layout_height 的 Compose 平替 size

layout_width 可以用 width 来替换,layout_height 可以用 height 来替换,如果宽高一样的话,可以直接使用 size

Row(    
    Modifier        
        .background(Color.Red, RoundedCornerShape(10.dp))        
        .width(400.dp) // 设置宽度       
        .height(800.dp) // 设置高度       
        .padding(10.dp)) {    
    Image(        
        rememberAsyncImagePainter("https://img2.baidu.com/it/u=1866466367,1635278877&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=734"),        
        contentDescription = resources.getString(R.string.app_name),        
        modifier = Modifier.clip(CircleShape).size(150.dp)    
    )        
    Text(text = "我是老A", Modifier.background(Color.Green).padding(10.dp))    
    Text(text = "老A是我", Modifier.padding(10.dp).background(Color.Green))
}

在 Android 中,我们需要强制给每个控件声明 width 和 height,但是在 Compose 中,这个并不是强制的了,因为每个组件都有一个默认规则,默认规则就是,如果你不写,那么它就相当于是传统 View 的 wrap_content 的了;

如果想使用类似 match_parent 的,则使用 Modifier.fillMaxWidth/ fillMaxHeight/ fillMaxSize 函数;

给 Text 设置颜色和大小

如果我们想给 Text 设置颜色和大小,可能第一时间我们就想到了使用 Modifier,但是,可能没有你想的那么简单,Modifier 并没有提供相关API,我们可以往上看 Text 的基础使用,发现其实 Text 的 API 提供了相关设置;

我们在声明 Text 的时候,直接使用 color 和 fontSize 来设置颜色和大小,而不用通过 Modifier,到这里的时候,可能大家就比较迷糊了,为啥还不统一呢,是不是 Jetpack Compose 的作者脑子没想好呢?然而并不是,因为 Compose 对于 Android 团队来说,是一次重要的革命,Android 团队其实在 Compose 上下了很大的功夫的;判断是 Modifier 还是函数参数,其实很简单:

通用的设置方式,使用 Modifier;专项的设置,使用函数参数

给控件设置点击监听

Android 中其实任何控件都可以设置监听的,这其实可以看做通用的设置方式,也就是说可以通过 Modifier 来给任意的控件设置一个监听

Row(    
    Modifier        
        .background(Color.Red, RoundedCornerShape(10.dp))        
        .width(400.dp)        
        .height(800.dp)        
        .padding(10.dp) 
        // 给 Row 设置一个监听       
        .clickable {            
            Toast.makeText(context, "我是 Row,我被点击了", Toast.LENGTH_LONG).show()        
        }) {    
            Image(        
                rememberAsyncImagePainter("https://img2.baidu.com/it/u=1866466367,1635278877&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=734"),        
                contentDescription = resources.getString(R.string.app_name),        
                modifier = Modifier.clip(CircleShape).size(150.dp)    
            )        
            Text(text = "我是老A", Modifier.background(Color.Green).padding(10.dp))    
            Text(text = "老A是我", Modifier.padding(10.dp).background(Color.Green))
}

运行效果如下:

可以看到,点击事件被执行了;

好了,Compose 的初探,就先到这里吧~~

下一节预告

状态订阅和自动更新;

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

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

相关文章

大数据调度框架Oozie,这个学习网站让你事半功倍!

Oozie是一个基于工作流引擎的开源框架&#xff0c;由Cloudera公司贡献给Apache。它主要用于管理和调度Apache Hadoop作业&#xff0c;支持的任务类型包括Hadoop MapReduce、Pig Jobs等。 Oozie的核心概念包括workflow jobs和coordinator jobs。Workflow jobs是由多个动作&#…

快递平台长期最低价格收费,需要寄快递享折扣优惠的请看这里 !

除了我们平时去菜鸟驿站寄快递或者在快递公司的官网上下单等方式外&#xff0c;我们还可以在我们平日使用的微信小程序中选择快递平台享受快递物流折扣。不用像其他主流快递公司想用优惠券一样下载官方APP。您还可以享受无忧特派送监管服务。今天给大家介绍一下我最常用的一款&…

鸿蒙开发已解决-Failed to connect to gitee.com port 443: Time out 连接超时提示

文章目录 项目场景:问题描述原因分析:解决方案:解决方案1解决方案2:解决方案3:此Bug解决方案总结解决方案总结**心得体会:解决连接超时问题的三种方案**项目场景: 导入Sample时遇到导入失败的情况,并提示“Failed to connect to gitee.com port 443: Time out”连接超…

用通俗易懂的方式讲解:大模型微调方法总结

大家好&#xff0c;今天给大家分享大模型微调方法&#xff1a;LoRA,Adapter,Prefix-tuning&#xff0c;P-tuning&#xff0c;Prompt-tuning。 文末有大模型一系列文章及技术交流方式&#xff0c;传统美德不要忘了&#xff0c;喜欢本文记得收藏、关注、点赞。 文章目录 1、LoRA…

“所有伙食开销统计:轻松查看,智能管理你的餐饮支出“

你是否经常为伙食开销感到困扰&#xff0c;不知道如何有效控制和管理&#xff1f;现在&#xff0c;有了我们的伙食开销统计工具&#xff0c;这些问题将得到轻松解决&#xff01; 首先第一步&#xff0c;我们要进入晨曦记账本并在上方功能栏里选择“查看方式”。并在弹出来的列表…

SpringBoot之优化高并发场景下的HttpClient并提升QPS

HttpClient优化思路 使用连接池&#xff08;简单粗暴&#xff09; 长连接优化&#xff08;特殊业务场景&#xff09; httpclient和httpget复用 合理的配置参数&#xff08;最大并发请求数&#xff0c;各种超时时间&#xff0c;重试次数&#xff09; 异步请求优化&#xff0…

gitlab导入/还原代码仓库(离线导入本地代码仓库及历史提交记录)

gitlab安装 在线 导入&#xff08;还原&#xff09;代码仓库 已有的代码代码可能托管于 GitHub、Bitbucket Cloud 、Bitbucket Server 、FogBugz 、Gitea 等平台&#xff0c;只要你有合适的权限&#xff0c;都可以使用 GitLab的在线导入功能直接从这些平台导入&#xff0c;如…

山西电力市场日前价格预测【2024-01-13】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2024-01-13&#xff09;山西电力市场全天平均日前电价为231.81元/MWh。其中&#xff0c;最高日前电价为345.71元/MWh&#xff0c;预计出现在00:15。最低日前电价为0.00元/MWh&#xff0c;预计出…

声明式管理方法(yaml文件)

声明式管理方法&#xff08;yaml文件&#xff09; 声明式管理方法&#xff08;yaml文件&#xff09;&#xff1a; 1、适合对资源的修改操作 2、声明式管理依赖于yaml文件&#xff0c;所有的内容都在yaml文件当中声明 3、编辑好的yaml文件&#xff0c;还是要依靠陈述式的命令…

数据结构链表完整实现(负完整代码)

文章目录 前言引入1、链表定义及结构链表的分类3、单向不带头链表实现实现完整代码 4、带头双向循环链表实现实现完整代码 前言 引入 在上一篇文章中&#xff0c;我们认识了顺序表&#xff0c;但是在许多情况中&#xff0c;顺序表在处理一些事件时还存在许多问题&#xff0c;比…

计算机缺失msvcr100.dll如何修复?分享五种实测靠谱的方法

在计算机系统的日常运行与维护过程中&#xff0c;我们可能会遇到一种特定的故障场景&#xff0c;即系统中关键性动态链接库文件msvcr100.dll的丢失。msvcr100.dll是Microsoft Visual C Redistributable Package的一部分&#xff0c;对于许多基于Windows的应用程序来说&#xff…

增广路算法 DFS求解 最大网络流问题

最大网络流问题 最大网络流问题是这样的&#xff0c;有一个有向图&#xff0c;假定有一个源点&#xff0c;有一个汇点&#xff0c;源点有流量出来&#xff0c;汇点有流量进入&#xff0c;有向图上的边的权重为该条边可通过的最大流量(方向为边的方向)&#xff0c;问从源点到汇…

Servlet-Request

一、预览 在上一篇Servlet体系结构中&#xff0c;我们初步了解了怎么快速本篇将介绍Servlet中请求Request的相关内容&#xff0c;包括Request的体系结构&#xff0c;Request常用API。 二、Request体系结构 我们注意到我们定义的Servlet类若实现Servlet接口时&#xff0c;请求…

leetcode14. 最长公共前缀

题目 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 “”。 解题方法&#xff1a; 1.首先找到数组中长度最短的数据&#xff0c;与数组第一个数进行交换&#xff08;公共前缀的长度肯定不会大于列表中长度最短的字符串&#x…

MYSQL的操作

1.库的操作 1.1创建数据库 语法&#xff1a; CREATE DATABASE [IF NOT EXISTS] db_name [create_specification [, create_specification] ...] create_specification: [DEFAULT] CHARACTER SET charset_name [DEFAULT] COLLATE collation_name 说明&#xff1a; #…

windows11通过虚拟机安装Ubuntu20.04

VMware 分为 VMware Workstation Pro 和 VMware Workstation Player, Pro体验期后收费&#xff0c;Player则免费。player 早期不能创建虚拟机&#xff0c;只能Pro创建好后给Player运行&#xff0c;而现在player早已加入创建虚拟机功能&#xff0c;所以使用体验上两者相差不大&a…

计算机体系结构----存储系统

本文严禁转载&#xff0c;仅供学习使用。参考资料来自中国科学院大学计算机体系结构课程PPT以及《Digital Design and Computer Architecture》、《超标量处理器设计》、同济大学张晨曦教授资料。如有侵权&#xff0c;联系本人修改。 1.1 引言 1.1.1虚拟和物理内存 程序员看到…

学习Qt笔记

前言&#xff1a; 学习笔记的内容来自B站up主阿西拜编程 《Qt6 C开发指南 》2023&#xff08;上册&#xff0c;完整版&#xff09;_哔哩哔哩_bilibili《Qt6 C开发指南 》2023&#xff08;上册&#xff0c;完整版&#xff09;共计84条视频&#xff0c;包括&#xff1a;00书籍介…

Java初学习

Java代码示例&#xff1a; public class helloworld {public static void main(String[] args){System.out.println("hello world");} } Java程序的名字需要和文件名字一致&#xff0c;就是那个helloworld Java程序需要对类有深度的认识&#xff1a; 对象是类的…

让java程序就像脚本一样去写工具

背景&#xff1a; 接触了各种语言之后发现&#xff0c;java还是比go&#xff0c;.netcore之类的简单&#xff0c;成熟&#xff0c;我最终选择了jenkinsshelljava去部署我们的代码&#xff0c;此时很多人可能去使用js或者python之类的去写部署逻辑&#xff0c;毕竟java每次打包…