比较RxKotlin和Kotlin Coroutines

369 阅读6分钟

在靠近用户的地方部署容器

本工程教育(EngEd)计划由科支持。

在全球范围内即时部署容器。Section是经济实惠、简单而强大的。

免费入门

RxKotlin与Kotlin Coroutines的比较

3月1日, 2022

RxKotlin是一个建立在RxJava之上的kotlin库,它为RxJava增加了一个基本的轻量级扩展功能,使其更容易在Kotlin中工作。

另一方面,Kotlin Coroutines是小线程,使异步代码的执行更容易。

RxKotlin的主要特点是,它能够通过取代正常的Android技术来防止内存泄漏,其泄漏率高达90%,这与C语言中的垃圾收集类似。

先决条件

要跟上这个教程,你需要。

  • 对Kotlin编程语言有基本了解。
  • 对Android开发有基本的了解。
  • 熟悉Room数据库概念的实现。

目标

本文将带领读者了解RxKotlin的概念,以及它如何在Android应用程序中使用,它的优点、缺点,以及区别于kotlin coroutines的特点。

RxKotlin的特点

  • Observable - 这些是对来自网络服务或由用户引入的数据做出反应的数据或事件的序列。
  • Subscriber - 这是一个扩展函数,用在可观察变量上,以确保观察者发送事件。
  • Flowable - 这是RxKotlin上的一个框架,在观察者发出大量数据时使用。
  • Maybe - 这是RxKotlin上的一种编程策略,它可以发出错误、单一值或无值。对于需要更新和删除等内容的数据库概念来说,它是一个很好的策略。
  • Disposable - 它是RxKotlin库中的一个接口,提供用于取消订阅的方法 。dispose()

Rxkotlin对Kotlin Coroutines的优势

  • 在RxKotlin中可以使用内置的类Disposable ,来取消对观察者的订阅,这在Kotlin的coroutine中是没有的。
  • 为了处理背压问题,RxKotlin使用了Flowable。当一个观察者产生大量的数据,而用户的设备无法处理时,就会出现背压。
  • maybe 编程方法的帮助下,RxKotlin可以一次提供一个输出。

RxKotlin的劣势

  • observerOn() 和 ,在RxKotlin中被用来分配任务,这对大多数程序员来说是混乱的。subscriberOn()
  • RxKotlin中没有考虑Kotlin coroutines中存在的callback ,这个概念。
  • 后台线程替换在RxKotlin中并不明显,因为它的实现使代码不那么干净和冗长。

开始使用RxKotlin

为了理解RxKotlin的概念和实现,我们将使用一个房间数据库来使用RxKotlin存储和检索数据。

第一步:开始一个新项目

启动Android Studio IDE并创建一个空的活动项目,如下图所示。

new project

第2步:添加RxKotlin和房间数据库的依赖项

导航到项目并选择包Gradle scripts 。接下来,选择build.gradle 应用程序级别,并添加以下依赖项,然后同步项目。

//RxKotlin
implementation "io.reactivex.rxjava3:rxandroid:3.0.0"
implementation "io.reactivex.rxjava3:rxkotlin:3.0.1"

// Room Database
def room_version = "2.4.1"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"

确保你在插件内添加Kotlin-Kapt

第3步:创建用户界面

让我们创建一个用户界面,使我们能够在recyclerview中显示数据,以及向我们的房间数据库添加数据。我们将使用编辑文本和一个按钮来添加数据。

一旦你设计了用户界面,它应该如下图所示。

  • 显示数据。

display data

  • 添加数据。

add data

第4步:设置房间数据库

为了使用房间,我们必须首先设置所有需要的属性,其中包括Entity、Dao和Database。

实体类

这是一个数据类,用来表示一个表和它所拥有的所有内容。它的实现如下图所示。

@Entity(tableName = "Details_table")
data class DetailsEntity(
    @PrimaryKey(autoGenerate = true)
    val id: Int = 0,
    val name: String? = null,
    val weight: String? = null
)

数据访问对象(DAO)

这是一个包含所有将用于与数据库交互的方法的类。它的实现方式如下。

@Dao
interface DetailsDao {
    @Insert
    fun insertDetails(details: DetailsEntity)

    @Delete
    fun deleteDetails(details: DetailsEntity)

    @Query("SELECT * FROM Details_table ORDER BY id ASC")
    fun getAllDetails(): List<DetailsEntity>

    @Update
    fun updateDetails(details: DetailsEntity)
    abstract fun findCheese(s: String): List<DetailsEntity>
}

数据库类

数据库在应用程序的后端。下面的代码说明了应该如何设计和实现应用程序的数据库。

@Database(entities = [DetailsEntity::class], exportSchema = false, version = 1)
abstract class DetailsDatabase :RoomDatabase() {
    abstract val detailsDao: DetailsDao

    companion object {

        @Volatile
        private var INSTANCE: DetailsDatabase? = null

        fun getInstance(context: Context): DetailsDatabase {
            synchronized(this) {
                var instance = INSTANCE

                if (instance == null) {
                    instance = Room.databaseBuilder(context.applicationContext,
                        DetailsDatabase::class.java,
                        "notes_database").fallbackToDestructiveMigration().build()

                    INSTANCE = instance
                }
                return instance
            }
        }
    }
}

第5步:创建适配器类

适配器类用于连接房间数据库的实体和视图,以有效地显示数据。它的做法如下图所示。

class DetailsAdapter : ListAdapter<DetailsEntity, DetailsAdapter.MyViewHolder>(DiffUtilCallback) {

    // Compare old and new data
    object DiffUtilCallback : DiffUtil.ItemCallback<DetailsEntity>() {
        override fun areItemsTheSame(oldItem: DetailsEntity, newItem: DetailsEntity): Boolean {
            return oldItem == newItem
        }

        override fun areContentsTheSame(oldItem: DetailsEntity, newItem: DetailsEntity): Boolean {
            return oldItem.id == newItem.id
        }
    }

    // Connect the data with the views
    inner class MyViewHolder(private val binding: RxRowBinding) : RecyclerView.ViewHolder(binding.root) {
        fun bind(details: DetailsEntity?) {
            binding.tvName.text = details?.name
            binding.tvWeight.text = details?.weight
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        return MyViewHolder(
            RxRowBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        )
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val note = getItem(position)
        holder.bind(note)
    }
}

第6步:实现RxKotlin,向房间添加数据

在进行数据添加时,我们可以选择使用coroutines或RxKotlin,这两种方法都允许我们在后台进行。为了在RxKotlin中完成这个任务,我们将创建一个函数来协助我们执行这个程序,并将订阅加载到onCreate 方法中。下面是一个如何完成的例子。

private fun addingDetails(context: Context): Flowable<List<Long>> {
        return Maybe.fromAction<List<Long>>(){
            // creating database instance
            val database = DetailsDatabase.getInstance(context = context).detailsDao

            // Adding data using the data class
            val details = DetailsEntity(0,binding.edtName.text.toString(),binding.edtWeight.text.toString())
            // inserting data
            database.insertDetails(details)
        }.toFlowable() // using flowable to handle huge data emission
            .observeOn(AndroidSchedulers.mainThread())  //placing observer to the main thread
            .subscribeOn(Schedulers.io()) //subscribing to the IO thread
            .doOnComplete {
                Toast.makeText(context, "Completed", Toast.LENGTH_SHORT).show()
            }
            .doOnError {
                Toast.makeText(context, "A error ocurred", Toast.LENGTH_SHORT).show()
            }
    }

加载订阅

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityAddDetailBinding.inflate(layoutInflater)
    setContentView(binding.root)

    //creating database instance
    detailsDatabase = DetailsDatabase.getInstance(applicationContext)
    detailsDao = detailsDatabase.detailsDao

    // adding click listener button
    binding.btnAdd.setOnClickListener {
        if (binding.edtName.text.toString().isEmpty()){
            binding.edtName.error = "Required"
            return@setOnClickListener
        } else if (binding.edtWeight.text.toString().isEmpty()){
            binding.edtWeight.error = "Required"
            return@setOnClickListener
        }
        else{
            // load subscription using disposable
            val loadDisposable = addingDetails(this).subscribe()
            compositeDisposable.add(loadDisposable)

            // shifting to the next activity
            val intent = Intent(this, MainActivity::class.java)
            startActivity(intent)
            finish()
        }
    }
}

第7步:使用RxKotlin来显示数据

数据一旦被输入到数据库中就应该被显示出来。为了显示数据,我们遵循下面的步骤。

// setting data to the recyclerview
private fun dataDisplay(context: Context): Flowable<List<Long>> {
    return Maybe.fromAction<List<Long>>(){

        //creating and submitting list to the recyclerview
        val myList = detailsDao.getAllDetails()
        adapter.submitList(myList)
        binding.detailsRecycler.adapter = adapter

    }.toFlowable()
        .observeOn(AndroidSchedulers.mainThread())
        .subscribeOn(Schedulers.io())
        .doOnComplete {
            Toast.makeText(context, "Added", Toast.LENGTH_SHORT).show()
        }
        .doOnError {
            Toast.makeText(context, "Error Ocurred", Toast.LENGTH_SHORT).show()
        }
}

运行该应用程序后,你应该期待以下输出。

demo

结论

在本教程中,我们讨论了RxKotlin和Kotlin Coroutines之间的区别、RxKotlin的优势和劣势、RxKotlin实现中使用的术语以及如何使用RxKotlin。

你可以在这个GitHub资源库中获得完整的代码。


同行评审贡献者:。Eric Gacoki

类似文章

[

How to Create a Reusable React Form component Hero Image

语言

如何创建一个可重复使用的React表单组件

阅读更多

](www.section.io/engineering…

Building a payroll system with next.js Hero Image

语言, Node.js

用Next.js构建一个薪资系统

阅读更多

](www.section.io/engineering…

Creating and Utilizing Decorators in Django example image

架构

在Django中创建和使用装饰器

阅读更多

](www.section.io/engineering…)