首页系统综合问题作为Android开发者你还不会Compose吗

作为Android开发者你还不会Compose吗

时间2023-01-07 07:32:02发布分享专员分类系统综合问题浏览180

今天小编给各位分享compose的知识,文中也会对其通过作为Android开发者你还不会Compose吗和Android真的推荐用MVI模式?MVI和MVVM有什么区别?等多篇文章进行知识讲解,如果文章内容对您有帮助,别忘了关注本站,现在进入正文!

内容导航:

  • 作为Android开发者你还不会Compose吗
  • Android真的推荐用MVI模式?MVI和MVVM有什么区别?
  • Google官方梳理,Android 多返回栈技术详解
  • Android-Compose下常用方法&虚拟键盘监听
  • 一、作为Android开发者你还不会Compose吗

    没有伞的孩子必须努力奔跑!你不勇敢,没人替你坚强。只有经历过地狱般的折磨,才有征服天堂的力量。只有流过血的手指才能弹出世间的绝唱。

    简介

    Compose 是用于构建原生 Android 界面的新工具包。是Android全新的UI框架,它使用更少的代码、强大的工具和直观的 Kotlin API,可以帮助简化并加快 Android 界面开发。

    为什么要学习Compose

    更少的代码编写更少的代码会影响到所有开发阶段:作为代码撰写者,需要测试和调试的代码会更少,出现 bug 的可能性也更小,您就可以专注于解决手头的问题;作为审核人员或维护人员,您需要阅读、理解、审核和维护的代码就更少。与使用 Android View 系统(按钮、列表或动画)相比,Compose 可让您使用更少的代码实现更多的功能。无论您需要构建什么内容,现在需要编写的代码都更少了。直观Compose 使用声明性 API,这意味着只需描述界面,Compose 会负责完成其余工作。这类 API 十分直观 - 易于探索和使用。利用 Compose,您可以构建不与特定 activity 或 fragment 相关联的小型无状态组件。这让您可以轻松重用和测试这些组件。在 Compose 中,状态是显式的,并且会传递给相应的可组合项。这样一来,状态便具有单一可信来源,因而是封装和分离的。然后,应用状态变化时,界面会自动更新。加速开发Compose 与所有的现有代码兼容:可以从 View 调用 Compose 代码,也可以从 Compose 调用 View。大多数常用库(如 Navigation、ViewModel 和 Kotlin 协程)都适用于 Compose。借助全面的 Android Studio 支持以及实时预览等功能,可以更快地迭代和交付代码:Android Studio 中的预览功能极大地节省了我们的时间。构建多个预览的能力也帮我们节省了时间。

    基本要求

    Android Stdio版本4.3及以上。Kotlin语法 (重点是高阶函数部分)。

    创建Jetpack Compose 工程步骤

    如果您位于 Welcome to Android Studio 窗口中,请点击 Start a new Android Studio project。如果您已打开 Android Studio 项目,请从菜单栏中依次选择 File > New > New Project。在 Select a Project Template 窗口中,选择 Empty Compose Activity,然后点击 Next。在Configure your project窗口中,执行以下操作:按照常规方法设置 Name、Package name 和 Save location。请注意,在 Language 下拉菜单中,Kotlin 是唯一可用的选项,因为 Jetpack Compose 仅适用于使用 Kotlin 编写的类。在 Minimum API level dropdown 菜单中,选择 API 级别 21 或更高级别。点击 Finish。

    现有项目添加支持Compose

    配置kotlin开发环境:kotlin版本1.4.30及以上。
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.20" 
    Gradle配置:
    buildFeatures {compose true  //支持compose}composeOptions {kotlinCompilerExtensionVersion compose_version  //设置kotlin编译器版本} 
    添加Compose依赖:
    implementation "androidx.compose.ui:ui:$compose_version"implementation "androidx.compose.material:material:$compose_version"implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"

    第一个Compose程序

    class MainActivity : ComponentActivity() {    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContent {            //主题            ComposeProjectTheme {                // 一个带有背景颜色的容器可理解为R.layout.xxx                Surface(                    modifier = Modifier.fillMaxSize(),                    color = MaterialTheme.colors.background                ) {                    //可组合函数                    Greeting("Android")                }            }        }    }}//可组合函数@Composablefun Greeting(name: String) {    Text(text = "Hello $name!")}@Preview(showBackground = true, showSystemUi = true, device = Devices.AUTOMOTIVE_1024p)@Composablefun DefaultPreview() {    ComposeProjectTheme {        Greeting("Android")    }}

    页面预览

    @Preview(showBackground = true, showSystemUi = true, device = Devices.AUTOMOTIVE_1024p)@Composablefun DefaultPreview() {    ComposeProjectTheme {        Greeting("Android")    }}

    @Preview注解用来构建预览页面。参数包括,背景,是否显示系统UI,模拟设备等等。

    编程思想

    声明式编程

    长期以来,Android视图层次结构一直可以表示为界面控件树,由于应用程序的状态会因用户交互等因素而发生变化,因此界面层次结构需要更新以显示当前的数据,最常见的更新方式就是通过findViewById 等函数遍历view树,找到对应的view,然后调用view的相应的方法进行更新。而Compose是根据数据变化而自动更新UI层次结构。

    可组合函数

    @Composablefun Greeting(isLogin:Boolean = false) {   val content = if (isLogin)  "登录成功" else "请登录"    Text(text = "Hello $content!")}

    可组函数不仅可以写展示页面也可以写逻辑代码

    @Composable注释修饰,作用是提示Compose编译器,此函数可将数据转化为页面。可接收参数,也可以包含逻辑处理。没有返回值,只是用来构建屏幕的状态。在构建页面的时候不能影响其他地方。可以通过定义一组接收数据并发出页面的可组合函数来构建界面。

    重组

    在Android View中,如果想要修改某个控件,需要调用控件的方法,而在Compose中,可以使用新的数据再次调用可组合函数进行修改,这就导致函数进行重组,重组就是系统根据需要使用新数据重新绘制的函数来重组组合,Compos可以智能的仅重组已更改的控件。

    @Composablefun Greeting(isLogin:Boolean = false) {   val content = if (isLogin)  "登录成功" else "请登录"    Text(text = "Hello $content!")}

    当Compose根据新数据进行重组时,它仅调用可能已更改的函数或者lambda,跳过其余函数或lambda,通过跳过所有未更改的参数的函数或lambda,Compose就可以重组了。

    可组合函数如果被频繁进行调用,如动画,为了避免动画执行过程中的卡顿,尽量使用后台协程中执行,并将值结果作为参数传递给可组合函数。

    Compose跟原生的View到底是什么关系?是跟Flutter一样完全基于Skia引擎渲染,还是说和原生View一样?

    override fun onResume() {    super.onResume()    //测量布局    window.decorView.postDelayed({        ( window.decorView as? ViewGroup)?.let {          printViewCount(it,1)        }    },300)}fun printViewCount(view: View,index:Int){    Log.e(TAG, "布局 第: $index 层 --$view")   if (view is ViewGroup){       view.children.forEach {           printViewCount(it,index+1)       }   }}

    我们通过日志打印,在页面展示出来后,第三秒还是遍历当前页面的整个布局层次,来看一下布局层次是否和我们代码添加的一致.

    通过日志分析可以看出来,布局的最后一层是AndroidComposeView,没有我们代码添加的布局,那么我们添加的布局在哪?

    我们先看布局结构层次

    public fun ComponentActivity.setContent(    parent: CompositionContext? = null,    content: @Composable () -> Unit) {    val existingComposeView = window.decorView        .findViewById<ViewGroup>(android.R.id.content)        .getChildAt(0) as? ComposeView    if (existingComposeView != null) with(existingComposeView) {        setParentCompositionContext(parent)        setContent(content)    } else ComposeView(this).apply {        // Set content and parent **before** setContentView        // to have ComposeView create the composition on attach        setParentCompositionContext(parent)        setContent(content)        // Set the view tree owners before setting the content view so that the inflation process        // and attach listeners will see them already present        setOwners()        setContentView(this, DefaultActivityContentLayoutParams)    }}

    性能提升

    APK体积减小代码行数减少Compose 没有xml文件,kotlin代码相应减少构建速度加快Android原生在解析xml时,需要遍历xml中布局的每一个层级,拿的控件进行渲染。

    喜欢Compose的同学,请关注或收藏一下本篇文章,后续跟随小编一起学习Compose。有精通Compose的同学欢迎评论区留言!

    一、Android真的推荐用MVI模式?MVI和MVVM有什么区别?

    android自己卷自己,自己造一个MVI架构模式吗?

    MVI架构模式是国内android开发者最近一两年造出来的吗?

    看了很多MVI的资料,发现都提到cycle.js框架。android的mvi架构就是启发于cycle.js框架。

    我们再看看Cycle.js框架是什么时候开始的,又是什么时候开始使用MVI模式的。

    Cycle.js框架 第一个预发版本

    再结合官方文档来看,Cycle.js框架就是为了MVI架构模式而生的。

    虽然不知道,Cycle.js框架是不是首个MVI模式框架。

    但是从很多资料可以推测,MVI架构模式就是Cycle.js框架推广开来的。

    而且早在2014年就已经在前端开发中用得飞起了。

    想想2014年,咱们在干嘛?android在用什么架构模式。

    正所谓,天下武功出少林啊。

    我们android的很多技术,在前端早就用“烂了”。

    我们知道MVP和MVVM的爹都是MVC。MVI的爹也是MVC。


    MVC的Controller是命令是编程组件,不能直接实现响应式编程思想。


    响应式编程范式(Reactive programming):

    安卓官方的compose框架、微信小程序、Flutter、React、鸿蒙UI的开发框架,都是使用响应式开发框架。

    这里就不拓展开来讲了,上面提到的任何一个开发框架,你只要会一个基本就能理解响应式编程范式。

    如果一个都不会也没关系,现在不理解响应式编程也没关系,等你学会MVI就理解了,这种只有实际使用过才能深刻理解。


    学不会也没关系,不要焦虑(尤其那些工作不久的小伙伴,学不会属于正常现象~)

    MVI,咱第一遍学不会,就等2年,再学一遍~

    2年后也没学会,那就再等2年~ 一定要有耐心~

    如果还是学不会,那也没关系,因为MVI早晚也会过时~ 等过时了就不用学了~

    哈哈哈~ 别笑,正经Android可不会开玩笑的。

    就像rxjava,当年有多少人死活学不会,android开发现在谁还学Rxjava?哈哈哈~

    用一张图来总结这次升级的核心思想:


    新版架构指南在旧版的基础上,做了如下调整和建议:

    1. 将LiveData组件改成了StateFlow

    对协程的使用更友好。并且更能体现面向数据流开发的思想。

    实际上,依然使用LiveData也没毛病。


    2. ViewModel传递给View的数据限制为View的UIState

    ViewModel从Model层获取数据后,转换为UIState数据,通过StateFlow流向View层。

    UIState的数据面向界面组件而定义的,是能直接控制View组件如何显示的数据。

    所以我们也可以称UIState为界面的状态或者View的状态。

    如下:


    3. 单数据流还是多数据流的选择

    官方指南并没有强制我们使用单流。

    同一个界面应该使用单个StateFlow还是多个StateFlow,需要我们自己判断。

    我们应该根据UIStates数据们之间关联程度来决定多流还是单流。

    单流优缺点都十分明显:

    优点: 数据集中管控,会提高代码的可读性和修改的便利性。

    缺点: 当数据非常多且复杂时,会影响效率。因为我们没有diff功能,View层不能只更新有变化的数据,只会根据UIState刷新当前界面。

    我们再看下官方新版架构图:

    当然不仅仅MVVM可以改造成响应式开发范式,MVP也是可以的。

    不信你看 这篇blog

    1. 理解MVC架构模式的思想【MVC是其他架构模式之爹,他的思想是MVP、MVVM、MVI的基础,学会它是关键步骤~】。

    3. 学习kotlin的StateFlow组件,的使用:Sequence->Flow->StateFlow。

    4. 学习ViewModel组件的使用(虽然不用ViewModel也能实现MVI架构,但是ViewModel还是值得学习)。

    5. 理解DRY(Don't Repeat Yourself)原则。

    6. 理解MVVM(因为官方的MVI模式是基于MVVM的基础改造的~)。

    7. 学习官方架构指南。

    8. 实战。

    在这里就分享一份由大佬亲自收录整理的 学习PDF+架构视频+面试文档+源码笔记 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料

    这些都是我现在闲暇时还会反复翻阅的精品资料。里面对近几年的大厂面试高频知识点都有详细的讲解。相信可以有效地帮助大家掌握知识、理解原理,帮助大家在未来取得一份不错的答卷。

    当然,你也可以拿去查漏补缺,提升自身的竞争力。

    真心希望可以帮助到大家,Android路漫漫,共勉!

    如果你有需要的话,只需 私信我【进阶】即可获取

    二、Google官方梳理,Android 多返回栈技术详解


    用户通过系统返回按钮导航回去的一组页面,在开发中被称为返回栈 (back stack)。多返回栈即一堆 "返回栈",对多返回栈的支持是在 Navigation 2.4.0-alpha01 和 Fragment 1.4.0-alpha01 中开始的。本文将为你展开多返回栈的技术详解。

    系统返回按钮的乐趣

    无论你在使用 Android 全新的 手势导航 还是传统的导航栏,用户的 "返回" 操作是 Android 用户体验中关键的一环,把握好返回功能的设计可以使应用更加贴近整个生态系统。

    在最简单的应用场景中,系统返回按钮仅仅 finish 你的 Activity。在过去你可能需要覆写 Activity 的 onBackPressed() 方法来自定义返回操作,而在 2021 年你无需再这样操作。我们已经在 OnBackPressedDispatcher 中提供了 针对自定义返回导航的 API 。实际上这与 FragmentManager 和 NavController 中 已经 添加的 API 相同。

    这意味着当你使用 Fragments 或 Navigation 时,它们会通过 来确保你调用了它们返回栈的 API,系统的返回按钮会将你推入返回栈的页面逐层返回。

    多返回栈不会改变这个基本逻辑。系统的返回按钮仍然是一个单向指令 —— "返回"。这对多返回栈 API 的实现机制有深远影响。

    Fragment 中的多返回栈

    在 surface 层级,对于 多返回栈的支持 貌似很直接,但其实需要额外解释一下 "Fragment 返回栈" 到底是什么。FragmentManager 的返回栈其实包含的不是 Fragment,而是由 Fragment 事务组成的。更准确地说,是由那些调用了 addToBackStack(String name) API 的事务组成的。

    这就意味着当你调用 commit() 提交了一个调用过 addToBackStack() 方法的 Fragment 事务时, FragmentManager 会执行所有你在事务中所指定的操作 (比如 替换操作 ),从而将每个 Fragment 转换为预期的状态。然后 会将该事务作为它返回栈的一部分。

    当你调用 popBackStack() 方法时 (无论是直接调用,还是通过系统返回键以 内部机制调用),Fragment 返回栈的最上层事务会从栈中弹出 -- 比如新添加的 Fragment 会被移除,隐藏的 Fragment 会显示。这会使得 恢复到最初提交 Fragment 事务之前的状态。

    也就是说 变成了销毁操作: 任何已添加的 Fragment 在事务被弹出的时候都会丢失它的状态。换言之,你会失去视图的状态,任何所保存的实例状态 (Saved Instance State),并且任何绑定到该 Fragment 的 ViewModel 实例都会被清除。这也是该 API 和新的 saveBackStack() 方法之间的主要区别。 可以实现弹出事务所实现的返回效果,此外它还可以确保视图状态、已保存的实例状态,以及 ViewModel 实例能够在销毁时被保存。这使得 restoreBackStack() API 后续可以通过已保存的状态重建这些事务和它们的 Fragment,并且高效 "重现" 已保存的全部细节。太神奇了!

    而实现这个目的必须要解决大量技术上的问题。

    排除 Fragment 在技术上的障碍

    虽然 Fragment 总是会保存 Fragment 的视图状态 ,但是 Fragment 的 onSaveInstanceState() 方法只有在 Activity 的 onSaveInstanceState() 被调用时才会被调用。为了能够保证调用 saveBackStack() 时 SavedInstanceState 会被保存,我们 需要在 Fragment 生命周期切换 的正确时机注入对 onSaveInstanceState() 的调用。我们不能调用得太早 (你的 Fragment 不应该在 STARTED 状态下保存状态),也不能调用得太晚 (你需要在 Fragment 被销毁之前保存状态)。

    这样的前提条件就开启了需要 解决 FragmentManager 转换到对应状态的问题 ,以此来保障有一个地方能够将 Fragment 转换为所需状态,并且处理可重入行为和 Fragment 内部的状态转换。

    在 Fragment 的重构工作进行了 6 个月,进行了 35 次修改时,发现 Postponed Fragment 功能已经严重损坏 ,这一问题使得被推迟的事务处于一个中间状态 —— 既没有被提交也并不是未被提交。之后的 65 个修改和 5 个月的时间里,我们几乎重写了 管理状态、延迟状态切换和动画的内部代码,具体请参见我们之前的文章《 全新的 Fragment: 使用新的状态管理器 》。

    Fragment 中值得期待的地方

    随着技术问题的逐步解决,包括更加可靠和更易理解的 ,我们新增加了两个 API: 和 。

    如果你不使用这些新增 API,则一切照旧: 单个 返回栈和之前的功能相同。现有的 保持不变 —— 你可以将 name 赋值为 null 或者任意 。然而,当你使用多返回栈时, 的作用就非常重要了: 在你调用 和之后的 方法时,它将作为 Fragment 事务的唯一的 key。

    举个例子,会更容易理解。比如你已经添加了一个初始的 Fragment 到 Activity,然后提交了两个事务,每个事务中包含一个单独的 replace 操作:

    也就是说我们的 FragmentManager 会变成这样:

    提交三次之后的 FragmentManager 的状态

    比如说我们希望将 profile 页换出返回栈,然后切换到通知 Fragment。这就需要调用 并且紧跟一个新的事务:

    现在我们添加 ProfileFragment 的事务和添加 EditProfileFragment 的事务都保存在 "profile" 关键字下。这些 Fragment 已经完全将状态保存,并且 会随同事务状态一起保持它们的状态。很重要的一点: 这些 Fragment 的实例并不在内存中或者在 中 —— 存在的仅仅只有状态 (以及任何以 ViewModel 实例形式存在的非配置状态)。

    我们保存 profile 返回栈并且添加一个新的 commit 后的 FragmentManager 状态

    替换回来非常简单: 我们可以在 事务中同样调用 saveBackStack() 操作,然后调用 :

    这两个堆栈项高效地交换了位置:

    交换堆栈项后的 FragmentManager 状态

    维持一个单独且活跃的返回栈并且将事务在其中交换,这保证了当返回按钮被点击时, 和系统的其他部分可以保持一致的响应。实际上,整个逻辑并未改变,同之前一样,仍然弹出 Fragment 返回栈的最后一个事务。

    这些 API 都特意按照最小化设计,尽管它们会产生潜在的影响。这使得开发者可以基于这些接口设计自己的结构,而无需通过任何非常规的方式保存 Fragment 的视图状态、已保存的实例状态、非配置的状态。

    当然了,如果你不希望在这些 API 之上构建你的框架,那么可以使用我们所提供的框架进行开发。

    使用 Navigation 将多返回栈适配到任意屏幕类型

    Navigation Component 最初 是作为通用运行时组件进行开发的,其中不涉及 View、Fragment、Composable 或者其他屏幕显示相关类型及你可能会在 Activity 中实现的 "目的地界面"。然而, NavHost 接口 的实现中需要考虑这些内容,通过它添加一个或者多个 Navigator 实例时,这些实例 确实 清楚如何与特定类型的目的地进行交互。

    这也就意味着与 Fragment 的交互逻辑全部封装在了 navigation-fragment 开发库和它其中的 FragmentNavigator 与 DialogFragmentNavigator 中。类似的,与 Composable 的交互逻辑被封装在完全独立的 navigation-compose 开发库和它的 ComposeNavigator 中。这里的抽象设计意味着如果你希望仅仅通过 Composable 构建你的应用,那么当你使用 Navigation Compose 时无需任何涉及到 Fragment 的依赖。

    该级别的分离意味着 Navigation 中有两个层次来实现多返回栈:

    仍需特别注意那些 尚未 更新的 ,它们无法支持保存自身状态。底层的 API 已经整体重写来支持状态保存 (你需要覆写新增的 navigate() 和 API 的重载方法,而不是覆写之前的版本),即使 并未更新, 仍会保存 的状态 (在 Jetpack 世界中向后兼容是非常重要的)。

    如果你仅仅在应用中使用 Navigation,那么 这个层面更多的是实现细节,而不是你需要直接与之交互的内容。可以这么说,我们已经完成了将 和 迁移到新的 Navigator API 的工作,使其能够正确地保存和恢复它们的状态,在这个层面上你无需再做任何额外工作。

    在 Navigation 中启用多返回栈

    如果你正在使用 NavigationUI ,它是用于连接你的 到 Material 视图组件的一系列专用助手,你会发现对于菜单项、 BottomNavigationView (现在叫 NavigationRailView ) 和 NavigationView ,多返回栈是 默认启用 的。这就意味着结合 和 navigation-ui 使用就可以。

    NavigationUI API 是基于 Navigation 的其他公共 API 构建的,确保你可以准确地为自定义组件构建你自己的版本。保证你可以构建所需的自定义组件。启用保存和恢复返回栈的 API 也不例外,在 Navigation XML 中通过 NavOptions 上的新 API,也就是 navOptions Kotlin DSL,以及 的重载方法可以帮助你指定 pop 操作保存状态或者指定 navigate 操作来恢复之前已保存的状态。

    比如,在 Compose 中,任何全局的导航模式 (无论是底部导航栏、导航边栏、抽屉式导航栏或者任何你能想到的形式) 都可以使用我们在与 底部导航栏集成 所介绍的相同的技术,并且结合 saveState 和 restoreState 属性一起调用 :

    保存状态,锁定用户

    对用户来说,最令人沮丧的事情之一便是丢失之前的状态。这也是为什么 Fragment 用一整页来讲解 保存与 Fragment 相关的状态 ,而且也是我非常乐于更新每个层级来支持多返回栈的原因之一:

    如果你希望了解 更多使用该 API 的示例 ,请参考 NavigationAdvancedSample (它是最新更新的,且不包含任何用于支持多返回栈的 NavigationExtensions 代码)。

    对于 Navigation Compose 的示例 ,请参考 Tivi。

    如果你遇到任何问题,请使用官方的问题追踪页面提交关于 Fragment 或者 Navigation 的 bug,我们会尽快处理。

    三、Android-Compose下常用方法&虚拟键盘监听

    Android Compose可谓之新起之秀,用起来真棒,但是目前还在处于稳定初期,下面归纳了一些常用方法:

    另附一个虚拟键盘状态监听方法

    关于compose的问题,通过《Google官方梳理,Android 多返回栈技术详解》、《Android-Compose下常用方法&虚拟键盘监听》等文章的解答希望已经帮助到您了!如您想了解更多关于compose的相关信息,请到本站进行查找!

    爱资源吧版权声明:以上文中内容来自网络,如有侵权请联系删除,谢谢。

    compose
    每日一词∣城镇环境基础设施建设construction of urban and rural environmental infrastructure 2018考研英语长难句分析每日一句(012)