鸿蒙开发——Android到HarmonyOS迁移之路

一、Android人Android的优势

Android Studio和DevEco Studio,如果你用过New UI之前的Android Studio的话,你对于DevEco Studio会有一种,这是亲兄弟的感觉。

实际上他们也的确是亲兄弟。因为两者都是基于IDEA开发的IDE。所以很多东西都是相似的,切换使用起来也是非常快的。

<img src="https://zyc-essay.oss-cn-beijing.aliyuncs.com/picgo/image-20240717202044663.png" alt="image-20240717202044663" style="zoom:50%;" />

<img src="https://zyc-essay.oss-cn-beijing.aliyuncs.com/picgo/image-20240717202049916.png" alt="image-20240717202049916" style="zoom:50%;" />

两张IDE的截图,各位能分出来嘛~

既然两者如此相像,那很多工具也是DevEco有的:

熟悉的日志系统,熟悉的过滤规则:

熟悉的UI Inspector: 

熟悉的调试工具: 

1.性能优化经验的适用性

只要是代码,肯定逃不过性能优化。在性能有限的设备上,性能调优肯定是重中之重的。

  • 资源管理

    • Android和HarmonyOS都需要管理内存泄漏、避免内存溢出。在开发过程中,可以使用类似的工具如Memory Profiler、LeakCanary等来监控和优化内存使用。
  • UI优化

    • 一般来说,Android通过减少布局层次、使用更高效的布局(如ConstraintLayout)来优化UI性能。这些方法同样适用于HarmonyOS的UI设计(如RelativeContainer

我们可以借鉴以往的经验,从资源管理、UI优化、网络优化、电池管理等方面入手,结合HarmonyOS的特性,进一步提升应用的性能。 

2.ArkUI的MVVM模式

应用通过状态去渲染更新UI是程序设计中相对复杂,但又十分重要的,往往决定了应用程序的性能。对于一位Android开发来说,如果你是远古项目那你可能用的MVP,如果你是现代开发那你用的可能是MVVM,如果你是未来开发那你用的可能是MVVM。

​ ArkUI天生就是MVVM,在Android中定义MVVM,可以这么做:

Android
Model

Model负责处理应用的数据部分,包括从数据库、网络或其他数据源获取数据。它只包含数据的逻辑和业务规则。 

data class User(val name: String, val age: Int)

class UserRepository {
    fun getUser(userId: String): User {
        // 从数据源获取用户数据(例如网络请求或数据库查询)
        return User("John Doe", 25)
    }
}
View

View是应用的UI部分,负责展示数据和处理用户交互。在Android中,View通常是Activity或FragmentView通过观察ViewModel来获得数据的更新。(当然你可以是Compose)

<!-- activity_main.xml -->
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="viewModel"
            type="com.example.app.UserViewModel" />
    </data>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        
        <TextView
            android:id="@+id/userName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{viewModel.user.name}" />
        
        <TextView
            android:id="@+id/userAge"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/userName"
            android:text="@{viewModel.user.age}" />
    </RelativeLayout>
</layout>
ViewModel

ViewModel负责准备和管理数据以供UI使用。它处理应用的业务逻辑,并与Model进行交互。ViewModel不引用View

class UserViewModel(private val userRepository: UserRepository) : ViewModel() {
    private val _user = MutableLiveData<User>()
    val user: LiveData<User> get() = _user

    fun loadUser(userId: String) {
        // 从仓库获取用户数据并更新LiveData
        _user.value = userRepository.getUser(userId)
    }
}
数据绑定(Data Binding)

(当然也可用各种框架和工具类)

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private lateinit var viewModel: UserViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 设置数据绑定
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        
        // 初始化ViewModel
        viewModel = ViewModelProvider(this).get(UserViewModel::class.java)
        binding.viewModel = viewModel
        binding.lifecycleOwner = this

        // 加载用户数据
        viewModel.loadUser("userId")
    }
}

对于HarmonyOS来说:

 HarmonyOS   model没什么不同。

Model
class User {
  name: string
  age: number

  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
}
View

声明式~

build() {
  Column() {
    Text(`${this.user?.age}`)
    Text(`${this.user?.age}`)
  }
}

数据请求

class UserRepository {
  static async getUser(userId: String): Promise<User> {
    // 从数据源获取用户数据(例如网络请求或数据库查询)
    return new User("John Doe", 25)
  }
}
//这里是在Index中
async aboutToAppear(): Promise<void> {
  this.user = await UserRepository.getUser("123")
}

ViewModel

@Entry
@Component
struct Index {
  @State user?: User = undefined

  async aboutToAppear(): Promise<void> {
    this.user = await UserRepository.getUser("123")
  }

  build() {
    Column() {
      Text(`${this.user?.age}`)
      Text(`${this.user?.age}`)
    }
  }
}

可以看到,在ArkUI中,ViewModel是存储在自定义组件的状态变量(@State等)、LocalStorageAppStorage中的数据。

自定义组件通过执行其build()方法或者@Builder装饰的方法来渲染UI,即ViewModel可以渲染View。其提高我们对ViewModel的阅读能力,代码也更加的清晰。

3.一致的开发思维

​ 刚刚提到了这么多,其实就是说,对于一个Android开发者来讲,HarmonyOS的开发工具和环境相似,使得我们无需重新学习新的开发环境,可以迅速上手,降低了学习曲线。

​ 使用相同的设计模式和开发思维,能够将已有的经验和技巧无缝迁移到HarmonyOS开发中,减少适应时间。开发者可以直接应用在Android开发中积累的调试经验和性能优化技巧,在HarmonyOS开发中快速定位和解决问题,提高开发效率。

​ 通过一致的开发思维和设计模式,开发者能够编写高质量、可维护的代码,提升应用的稳定性和可扩展性,同时利用在Android开发中积累的性能优化经验,打造高性能的应用,提升用户体验。

二、Android人的挑战

​ 换到一个新的环境,不可能一帆风顺,总会有不一样的、不习惯的。作为开发,这都是我们的挑战。

  1. 架构差异
    • Activity、Fragment、View

      这三家大家都是非常熟悉的,对于Fragment的怨言也是无穷无尽的。简单的复述下:

      Activity:是Android应用的基本组件之一,负责创建窗口并管理用户界面。每个Activity都代表应用中的一个屏幕,包含用户可以与之交互的界面元素。

      Fragment:是Activity的一部分,提供了一种在Activity中构建模块化UI的方式。Fragment可以独立存在,也可以与其他Fragment组合在一个Activity中,以实现动态和灵活的UI设计。

      View:是Android UI框架的基础构建块,表示屏幕上的基本元素,例如按钮、文本框和图像视图。View可以组合成复杂的布局,用于构建应用的界面。

      1. Ability、Compoment

        Ability:是HarmonyOS应用的核心组件,类似于Android的Activity。

        Component:是HarmonyOS中构建UI的基础元素,类似于Android的View。

        ​ 在HarmonyOS中是没有Fragment的概念的,因为Component承接了所有的UI。使用不同的注解@Entry、@CustomDialog等。使用多个Component可以组合成复杂的布局和界面。

    ​ 对于Android开发来说,需要注意的是Ability的生命周期,以及Component的

    生命周期。之前在Fragment、Acitivity某个生命周期做得事情,在HarmonyOS中如何实现,对应的生命周期有什么不同,有没有类似的生命周期等。这都是容易弄错、忽略的。但是某种程度上,也是我们Android开发的优势。毕竟我们也是饱受生命周期折磨的人了。

  2. API和库的差异

    ​ 需要直面的一个很重要的事情就是,一些Android特有的API、三方库在HarmonyOS中可能没有直接的替代方案。

    ​ 这时候就需要你自己发动聪明的大脑去造轮子了。

    ​ 但是通常官方都提供了非常丰富的用例,比如TPC仓库,官方的社区,Sample仓库等。而且官方也是提供了提工单的方式,直面开发来解决问题。

    ​ 很多库,现在开发者和官方也是做了很多迁移工作的。

    ​ 总而言之就是,只要多问、多想、多找。都是有解决方案的。

  3. 语言和框架的差异

    1. 在Java和Kotlin中,类是构建对象的蓝图,通过类可以创建对象,这些对象是类的实例,具有类定义的属性和方法。

      ​ 在ArkTs中,类实际上是一个函数(构造函数),其方法定义在原型上,具有高度的动态特性。这种设计会导致有时类无法调用到它的方法,主要原因如下:

      方法未绑定到实例:如果方法在调用时没有正确绑定到实例,会导致 this 关键字指向错误。

      方法定义在原型上:方法定义在原型上,可能导致方法在某些情况下无法访问,特别是在不同的作用域或上下文中调用时。

      ​ 这对于我们这种使用Java和Kotlin为主力开发语言的人来说,这种动态性也可能导致类的方法在某些情况下无法正确调用,需要我们特别注意方法的绑定和调用上下文。

      ​ (你也不想天天看到无法找到方法的错误吧。)

    2. 变量作用域和生命周期管理

      ArkTS中的闭包在某些方面与 Kotlin 和 Java 的处理有所不同,这主要体现在变量作用域和生命周期的管理上:

      1. 变量作用域
      • Kotlin: Kotlin 采用了类似于 Java 的作用域管理,但支持更灵活的闭包处理。Kotlin 允许通过 letapplyrunwith, 和 also 等函数来创建闭包,变量作用域在这些函数的范围内有效。
      • Java: Java 中的闭包主要通过匿名内部类来实现。变量的作用域是基于匿名内部类的上下文的。Java 中闭包的使用通常较为简单,但变量在闭包中的生命周期较长,可能会引入额外的内存开销。
      • ArkTS: 在 ArkTS 中,需要注意变量是在函数内部还是外部定义的,以及是否通过闭包引用。闭包的作用域遵循 JavaScript/TypeScript 的规则

        特别注意:

        • 函数的作用域由函数定义的位置决定。内部函数可以访问其外部函数的变量
        • 当内部函数访问外部函数的变量时,闭包会持有对这些变量的引用
        • 如果闭包中持有对变量的引用,并且闭包仍然存在,那么这些变量不会被垃圾回收

      需要充分的理解ArkTS的闭包,才能避免一些奇怪的问题出现,也能扩展我们解决问题的思路。

    3. 组件构建方式

      对于Android来说,我们想写一个Custom View一般会采用继承现有的Group View来实现,但是在ArkUI中,继承UI是不被允许的。需要多多使用组合~

      ​ wrapBuilder、ComponentContent等。

      当然了如果你是Compose使用者,当我没说~

  1. 分布式能力

    ​ 为什么要把分布式单独拿出来说呢?因为大多数android开发对于分布式的认识是欠缺的。

    ​ 不只是Android 开发主要集中在单一设备上的应用开发,还有Android的分布式开发非常的复杂。需要我们去额外的考虑许许多多的东西。

    ​ 所以作为一个Android开发去做HarmonyOS开发,我们需要去主动的认识HarmonyOS的分布式。

    ​ 如何充分利用HarmonyOS自身的跨端迁移多端协同能力,去应用到我们的APP中,发挥最大的用处。是值得我们去认真研究的。

三、实际开发中的体验

​ 总体来说,HarmonyOS的开发,给我带来了非常多的惊喜的。

  1. 状态管理的优势

 

  1. 丰富的状态管理装饰器,的确让开发变得更加的顺手了起来。减少样板代码不可多得的好手。

    ​ 独立的状态管理逻辑使得测试变得更加容易。大大简化了复杂应用的状态管理过程~

  2. 丰富的组件

    很多时候,我们都在烦恼Android某些UI交互(Compose不算),比如获取Android RecycleView当前看见列表的中间Item:

    (伪代码)

    recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            super.onScrolled(recyclerView, dx, dy)
            val layoutManager = recyclerView.layoutManager as? LinearLayoutManager
            layoutManager?.let {
                val firstVisibleItemPosition = it.findFirstVisibleItemPosition()
                val lastVisibleItemPosition = it.findLastVisibleItemPosition()
                val middlePosition = (firstVisibleItemPosition + lastVisibleItemPosition
                // 获取中间项的 ViewHolder
                val middleViewHolder = recyclerView.findViewHolderForAdapterPosition(middlePosition)
                middleViewHolder?.let { viewHolder ->
                    // 处理中间项
                    handleMiddleItem(viewHolder)
                }
            }
        }
    })

    而在ArkUI中:

    (伪代码)

    List().onScrollIndex((start: number, end: number, center: number) =>{
            handleMiddleItem()
          })

    非常的简介,总体来说,ArkUI提供了许多我比较喜欢的API,也是解决了一些Android的开发痛点了。

  3. 一致性和统一性

    HarmonyOS 一次开发,多端部署。

  • 不同设备间的屏幕尺寸、色彩风格等存在差异,页面如何适配。
  • 不同设备的系统能力有差异,如智能穿戴设备是否具备定位能力、智慧屏是否具备摄像头等,功能如何兼容。

通过布局能力、交互归一、多台组件、资源能力、系统能力全面的支持,我们只需要少量的代码,就可以在多个平台部署,得到相似的UI、交互。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值