1、 Android使用kotlin协程举例,麻烦版
var job:Job?=null
fun test15(){
//让协程跑在主线程当中,因为默认Default是非主线程。同事加上SupervisorJob 其中协程错误不要干扰到其它协程
job = GlobalScope.launch(Dispatchers.Main+ SupervisorJob()) {
launch {
throw NullPointerException("空指针")
}
val result = withContext(Dispatchers.IO){
"子线程中的请求结果"
}
launch {
//网络请求3
}
btn.text = result
}
}
override fun onDestroy() {
super.onDestroy()
//防止内存泄漏
job?.cancel()
}
2、上述太麻烦了,于是有个官方版本的 MainScope
//帮我们直接省了
public fun MainScope():CoroutineScope = CoroutineScope(SupervisorJob()+ Dispatchers.Main)
private val mainScope = MainScope()
private fun start() {
mainScope.launch {
launch {
throw NullPointerException("空指针")
}
val result = withContext(Dispatchers.IO) {
//网络请求...
"请求结果"
}
launch {
//网络请求3...
}
btn.text = result
}
}
override fun onDestroy() {
super.onDestroy()
mainScope.cancel()
}
3、在Activity与Framgent中使用协程
3.1、有生命周期很好用
- lifecycleScope会在DESTROYED是销毁,不用担心忘记主动协程cancel导致的内存泄漏,它自己在内部会cancel。
3.2、 在全局初始化时调用
init { lifecycleScope.launchWhenResumed { Log.d("init", "在类初始化位置启动协程") } }
- `launchWhenCreated`
- `launchWhenStarted`
- `launchWhenResumed`
- 值得一提的时onResume()执行完之后,STATE才被设置为RESUME。所以会先跑完onResume()
3.3、整一个CoroutineExceptionHadler就好了
class MainActivity : AppCompatActivity() {
val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
Log.d("exceptionHandler", "${coroutineContext[CoroutineName]} $throwable")
}
fun load() {
lifecycleScope.launch(exceptionHandler) {
//省略...
}
lifecycleScope.launch(exceptionHandler) {
//省略...
}
lifecycleScope.launch(exceptionHandler) {
//省略...
}
}
}
3.4、能不能CoroutineExceptionHadler也不写了?写个扩展函数呗!
3.4.1、Activity版本的
//GlobalCoroutineExceptionHandler.KT
class GlobalCoroutineExceptionHandler(private val errCode: Int, private val errMsg: String = "", private val report: Boolean = false):CoroutineExceptionHandler {
override val key: CoroutineContext.Key<*>
get() = CoroutineExceptionHandler
override fun handleException(context: CoroutineContext, exception: Throwable) {
val stackTraceToString = exception.stackTraceToString()
Log.e("$errCode","GlobalCoroutineExceptionHandler:${stackTraceToString}")
}
}
//其它扩展函数所用的kt文件
inline fun AppCompatActivity.requestMain(
errCode: Int = -1, errMsg: String = "", report: Boolean = false,
noinline block:suspend CoroutineScope.()->Unit){
lifecycleScope.launch(GlobalCoroutineExceptionHandler(errCode,errMsg, report)){
block.invoke(this)
}
}
inline fun AppCompatActivity.requestIO(
errCode: Int = -1, errMsg: String = "", report: Boolean = false,
noinline block: suspend CoroutineScope.() -> Unit): Job {
return lifecycleScope.launch(Dispatchers.IO + GlobalCoroutineExceptionHandler(errCode, errMsg, report)) {
block.invoke(this)
}
}
inline fun AppCompatActivity.delayMain(
errCode: Int = -1, errMsg: String = "", report: Boolean = false,
delayTime: Long, noinline block: suspend CoroutineScope.() -> Unit) {
lifecycleScope.launch(GlobalCoroutineExceptionHandler(errCode, errMsg, report)) {
withContext(Dispatchers.IO) {
delay(delayTime)
}
block.invoke(this)
}
}
//////ACTIVITY.KT
fun test16(){
requestMain {
delay(2000)
Toast.makeText(this@MainActivity,"haha",Toast.LENGTH_SHORT).show()
}
requestIO {
loadNetData()
}
delayMain(100){
Toast.makeText(this@MainActivity,"haha",Toast.LENGTH_SHORT).show()
}
}
private suspend fun loadNetData():String{
return withContext(Dispatchers.IO){
//网络请求
"kentwang"
}
}
3.4.2、Fragment版本的
inline fun Fragment.requestMain(
errCode: Int = -1, errMsg: String = "", report: Boolean = false,
noinline block: suspend CoroutineScope.() -> Unit) {
lifecycleScope.launch(GlobalCoroutineExceptionHandler(errCode, errMsg, report)) {
block.invoke(this)
}
}
inline fun Fragment.requestIO(
errCode: Int = -1, errMsg: String = "", report: Boolean = false,
noinline block: suspend CoroutineScope.() -> Unit) {
lifecycleScope.launch(Dispatchers.IO + GlobalCoroutineExceptionHandler(errCode, errMsg, report)) {
block.invoke(this)
}
}
inline fun Fragment.delayMain(
errCode: Int = -1, errMsg: String = "", report: Boolean = false, delayTime: Long,
noinline block: suspend CoroutineScope.() -> Unit) {
lifecycleScope.launch(GlobalCoroutineExceptionHandler(errCode, errMsg, report)) {
withContext(Dispatchers.IO) {
delay(delayTime)
}
block.invoke(this)
}
}
3.5、为什么Activity和Fragment要分开写?他们都是使用的lifecycleScope
,我们直接通过lifecycleScope
扩展就不可以了吗?不行!可能生命周期不一样
5、ViewModel中使用协程
inline fun ViewModel.requestMain(
errCode: Int = -1, errMsg: String = "", report: Boolean = false,
noinline block: suspend CoroutineScope.() -> Unit) {
viewModelScope.launch(GlobalCoroutineExceptionHandler(errCode, errMsg, report)) {
block.invoke(this)
}
}
inline fun ViewModel.requestIO(
errCode: Int = -1, errMsg: String = "", report: Boolean = false,
noinline block: suspend CoroutineScope.() -> Unit) {
viewModelScope.launch(Dispatchers.IO + GlobalCoroutineExceptionHandler(errCode, errMsg, report)) {
block.invoke(this)
}
}
inline fun ViewModel.delayMain(
errCode: Int = -1, errMsg: String = "", report: Boolean = false, delayTime: Long,
noinline block: suspend CoroutineScope.() -> Unit) {
viewModelScope.launch(GlobalCoroutineExceptionHandler(errCode, errMsg, report)) {
withContext(Dispatchers.IO) {
delay(delayTime)
}
block.invoke(this)
}
}
6、其它环境下使用
在Service
、Dialog
、PopWindow
以及一些其他的环境中又该如何使用。
协同作用域
:这一类我们就模仿MainScope
自定义一个CoroutineScope
。主从(监督)作用域
:这一类我们直接使用MainScope
,然后在此基础上做一些扩展即可。
6.1、Service等协同作用域
public fun NormalScope(): CoroutineScope = CoroutineScope(Dispatchers.Main)
abstract class BaseService :Service(){
private val normalScope = NormalScope()
override fun onDestroy() {
normalScope.cancel()
super.onDestroy()
}
protected fun requestMain(
errCode: Int = -1, errMsg: String = "", report: Boolean = false,
block: suspend CoroutineScope.() -> Unit) {
normalScope.launch(GlobalCoroutineExceptionHandler(errCode, errMsg, report)) {
block.invoke(this)
}
}
protected fun requestIO(
errCode: Int = -1, errMsg: String = "", report: Boolean = false,
block: suspend CoroutineScope.() -> Unit): Job {
return normalScope.launch(Dispatchers.IO + GlobalCoroutineExceptionHandler(errCode, errMsg, report)) {
block.invoke(this)
}
}
protected fun delayMain(
delayTime: Long,errCode: Int = -1, errMsg: String = "", report: Boolean = false,
block: suspend CoroutineScope.() -> Unit) {
normalScope.launch(GlobalCoroutineExceptionHandler(errCode, errMsg, report)) {
withContext(Dispatchers.IO) {
delay(delayTime)
}
block.invoke(this)
}
}
}
class MainService : BaseService() {
override fun onBind(intent: Intent): IBinder? = null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
requestIO {
//网络加载
}
return super.onStartCommand(intent, flags, startId)
}
}
- 同理在
Dialog
、PopWindow
以及一些其他的环境中可以依照此方法,定义符合我们自己需求的CoroutineScope
。一定要记得不要跨域使用,以及及时的关闭协程。