先决条件:
- Android上的Kotlin协程
- Kotlin协程中的挂起函数
Kotlin协程的范围可以定义为执行Kotlin协程的限制。范围帮助预测协程的生命周期。 Kotlin协程基本上有3个作用域:
- 全球范围
- 生命周期范围
- ViewModel范围
要在Build.gradle中导入的依赖项(应用程序级文件)
将以下依赖项导入到build.gradle(应用程序)级别的文件中。
implementation ‘org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.5’
implementation ‘org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.5’
def arch_version = ‘2.2.0-alpha01’
implementation “androidx.lifecycle:lifecycle-viewmodel-ktx:$arch_version”
implementation “androidx.lifecycle:lifecycle-runtime-ktx:$arch_version”
1.全球范围
全球范围是启动协程的方式之一。当协程在全球范围内启动时,它们的寿命与应用程序一样长。如果协程完成了一项工作,它将被销毁,直到应用程序死亡后才能存活,但是让我们想象一下这样一种情况:协程还有一些工作或指令要做,突然我们结束了应用程序,那么协程将因为协程的最大寿命等于应用程序的寿命,所以它们也会死亡。在全球范围内启动的协程将在单独的线程中启动。下面的示例显示在全局范围内的协程在单独的线程中启动。
Kotlin
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
val TAG = "Main Activity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
GlobalScope.launch {
Log.d(TAG, Thread.currentThread().name.toString())
}
Log.d("Outside Global Scope", Thread.currentThread().name.toString())
}
}
XML
Kotlin
// program for main activity which intent to another activity
// it uses global scope to launch the coroutine
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
const val TAG = "Main Activity"
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btnStartActivity.setOnClickListener {
// coroutine will launch when button got pressed
GlobalScope.launch {
// infinite loop
while (true) {
delay(1000L)
Log.d(TAG, "Still Running..")
}
}
GlobalScope.launch {
delay(5000L)
// new activity will get intended after 5 sec
val intent = Intent(this@MainActivity, SecondActivity::class.java)
startActivity(intent)
// calling finish() method,so that first activity will not be alive
// after being intended to second activity
finish()
}
}
}
}
XML
Kotlin
// program for second activity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
Log.i("Second Activity", "Second Activity Running ....")
Toast.makeText(this, "Second Activity", Toast.LENGTH_SHORT).show()
}
}
Kotlin
// program to show how lifecycle scope works
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
const val TAG = "Main Activity"
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btnStartActivity.setOnClickListener {
// launching the coroutine in the lifecycle scope
lifecycleScope.launch {
while (true) {
delay(1000L)
Log.d(TAG, "Still Running..")
}
}
GlobalScope.launch {
delay(5000L)
val intent = Intent(this@MainActivity, SecondActivity::class.java)
startActivity(intent)
finish()
}
}
}
}
以下是上述程序的日志输出:
众所周知,在全局范围内启动的协程与应用程序一样有效,但是开发人员需要协程与应用程序一样有效的机会很少。在全球范围内启动协程的主要问题是,当启动协程的活动死亡时,协程不会随着活动而死亡,因为协程的生存期取决于应用程序的生命周期,而不是活动的生命周期。由于协程正在使用启动它的活动的资源,并且由于该活动已经死亡,因此该资源将不会被垃圾回收,因为协程仍在引用该资源。此问题可能导致内存泄漏。因此,始终使用全局范围并不总是一个好主意。让我们尝试启动一个协程,并以1秒的延迟运行无限循环,并在从启动开始延迟5秒后,通过终止第一个活动和意图转移到另一个活动,在全局范围内启动另一个协程。我们在输出中可以看到,即使以编程方式终止了第一个活动,与第一个活动相关联的协程也不会消失。让我们尝试以编程方式了解上一段中的内容。以下是activity_main.xml和MainActivity.kt文件的代码。
XML格式
科特林
// program for main activity which intent to another activity
// it uses global scope to launch the coroutine
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
const val TAG = "Main Activity"
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btnStartActivity.setOnClickListener {
// coroutine will launch when button got pressed
GlobalScope.launch {
// infinite loop
while (true) {
delay(1000L)
Log.d(TAG, "Still Running..")
}
}
GlobalScope.launch {
delay(5000L)
// new activity will get intended after 5 sec
val intent = Intent(this@MainActivity, SecondActivity::class.java)
startActivity(intent)
// calling finish() method,so that first activity will not be alive
// after being intended to second activity
finish()
}
}
}
}
转到应用程序> Java >第一个程序包名称>右键单击>新建>活动>空活动以创建新活动并将其命名为SecondActivity 。下面是activity_second.xml和SecondActivity.kt文件的代码。
XML格式
科特林
// program for second activity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
Log.i("Second Activity", "Second Activity Running ....")
Toast.makeText(this, "Second Activity", Toast.LENGTH_SHORT).show()
}
}
输出:
从下面的注销中可以看出,即使在启动第二个活动之后,主活动的协同程序仍在运行。椭圆形的圆圈用于显示时间戳。
2.生命周期范围
生命周期作用域与全局作用域相同,但是唯一的区别是,当我们使用生命周期作用域时,活动中启动的所有协程在活动死亡时也会死亡。这是有益的,因为即使我们的活动终止,我们的协程也不会继续运行。为了在我们的项目中实现生命周期范围,只需在生命周期范围而不是全局范围中启动协程,即可在运行无限循环的主要活动中将全局范围更改为生命周期范围。除了上面提到的主要活动的代码中的一些更改外,所有代码都将保持不变。
科特林
// program to show how lifecycle scope works
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
const val TAG = "Main Activity"
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btnStartActivity.setOnClickListener {
// launching the coroutine in the lifecycle scope
lifecycleScope.launch {
while (true) {
delay(1000L)
Log.d(TAG, "Still Running..")
}
}
GlobalScope.launch {
delay(5000L)
val intent = Intent(this@MainActivity, SecondActivity::class.java)
startActivity(intent)
finish()
}
}
}
}
日志输出:
椭圆形的圆圈用于显示时间戳。
从上面的日志输出中可以看出,在启动第二个活动之后,主活动停止进行打印。
3. ViewModel范围
它也与生命周期作用域相同,唯一的区别是,只要视图模型处于活动状态,此范围内的协程将继续存在。 ViewModel是一个类,它通过遵循android中生命周期系统的原理来管理和存储与UI相关的数据。如果您想更深入地了解基本上视图模型类是什么,可以参考android官方文档的此链接。