Jetpack Compose 上手问答 - 新入门会遇到的一些问题和解释(1)

789 阅读3分钟

前言:同事抱着极大的热情试用了compose,然后给我甩了一堆问题

看看这些问题击中你了没有

其性能?

理论性能优于传统写法(1.0的性能测试看这里

(实际性能看起来稍差了一些,但应该可以通过androidx.profileInstaller和更新版本去优化,1.2.0-alpha05版本后似乎lazyColumn性能得到了大优化,有没有大佬基于最新alpha版测试下?)

无惧布局层级的嵌套(constraintLayout现在只是一种布局方式,不再有其他优势)

复杂动画性能远优于传统写法(除非你用自定义view)

初始化性能理应比xml快,但目前可能稍慢一些(未实测,只看了之前版本的其他人的测试结果)

全部或者部分代码改用compose写将大大优化包体积

为什么连给Text设置fontSize都是实验性API?

用 Int.sp / Float.sp

16.sp

哪里有讲compose原理的课程?

微信公众号可以搜到一些文章

但我还是想推荐这个公众号和其中的这篇文章(作者看到记得联系我结下广告费):

你需要了解的Compose背后的技术原理

compose里面怎么开线程

LaunchEffect(Unit){
    //主线程协程块,自己在这里面切子线程
    launch {
        //子线程协程块
    }
}

那——LaunchEffect中的launch块里能更新UI吗?

你且自由更新它!真有问题报错了再找解决方法!

怎么更新UI?

mutableStateOf / mutablexxxOf 包裹的对象更新时会触发invalidate使得界面刷新

var text by mutableStateOf("")

@Composable
fun Test() {
    Text (text, Modifier.clickable{
        text = "wow"
    })
    
// 如果text定义在@Composable函数内部,其定义就应当写成这样
var text by remember { mutableStateOf("") }

除此之外的其他值只能在界面刷新时被 【顺便】 刷新

remember?

被remember的块包裹的区域在Composable生命周期内只执行一次 但remember可以通过写成remember (value1 ,可选value2...){}的形式,对传入的value进行观察,当value改变时,其块包裹的区域会再次被执行

我没用过ViewModel

好说,获取它看这里——

  • @Composable
// 写法1
val viewModel = viewModel<MyViewModel>()
// 写法2
val viewModel : MyViewModel = viewModel()
  • koltin
// 这个context……看ViewModelProvider(ViewModelStore)的注释吧
val viewModel = ViewModelProvider(context).get(MyViewModel::java.class)

定义它看这里——

class MyViewModel : ViewModel() {
    // 如果这个值的改变应该触发界面刷新,请使它基于mutableStatexxxOf
    var contentOfText : String by mutableStateOf("")
}

多语言适配?

@Composable中可以直接通过LocalContext.current取到当前context,然后你懂的

——等等,你猜猜我在@Composable中打‘local’看到了什么?

image.png !!!你可以拿到这么多东西!

这一大堆东西里面,值得关注的还有LocalView LocalDensity,你懂的

多分辨率适配?

  • 通过context拿定义了不同dimen的xml dp值
  • 但我觉得我们也可以根据dimen的规则写一套自适应的Dp获取和计算方案 : )

使元素响应拖动?

var offsetOfText by remember { mutableStateOf( IntOffset.Zero ) }

Modifier
    .offset{offsetOfText}
    .pointerInput(Unit) {
                detectDragGestures { change, dragAmount -> 
                    offsetOfText += dragAmount.round()
                }
            }

Modifier是顺序敏感的?

那为什么上面一串代码我改成这样也可以拖动?

var offsetOfText by remember { mutableStateOf( IntOffset.Zero ) }

Modifier
    .pointerInput(Unit) {
                detectDragGestures { change, dragAmount -> 
                    offsetOfText += dragAmount.round()
                }
            }
    .offset{offsetOfText}

是可以,毕竟拖动事件的注册和进行offset又有什么关系呢?

但——会出现一个有意思的现象

描述一下就是:拖动监听区域将始终不会跟随offset值的改变而改变

也就是说:拖动监听区域将永远在初始位置,你每次需要从初始位置开始滑动才能触发拖曳响应

——没错,只有基于offset设置drag监听,才可以让监听跟随offset