首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

为什么在使用setOnTouchListener时协程会破坏我的应用程序?

在使用 setOnTouchListener 时,协程可能会破坏应用程序的原因主要与协程的生命周期和触摸事件的处理机制有关。以下是详细解释:

基础概念

  1. 协程(Coroutine):协程是一种轻量级的线程,可以在不阻塞主线程的情况下执行异步任务。它们在 Kotlin 中非常流行,用于简化异步编程。
  2. setOnTouchListener:这是一个 Android API,用于设置一个监听器来处理视图上的触摸事件。

问题原因

  1. 生命周期不匹配:协程的生命周期可能与视图的生命周期不匹配。如果协程在视图销毁后仍然运行,可能会导致内存泄漏或其他异常。
  2. 触摸事件处理setOnTouchListener 需要在主线程中处理触摸事件,而协程可能会在不同的线程中执行,导致触摸事件处理不及时或不正确。

解决方法

  1. 使用 LifecycleScope:确保协程的生命周期与视图的生命周期一致。可以使用 LifecycleScope 来启动协程,这样当视图销毁时,协程也会自动取消。
  2. 使用 LifecycleScope:确保协程的生命周期与视图的生命周期一致。可以使用 LifecycleScope 来启动协程,这样当视图销毁时,协程也会自动取消。
  3. 使用 Dispatchers.Main:确保协程在主线程中执行触摸事件处理逻辑。
  4. 使用 Dispatchers.Main:确保协程在主线程中执行触摸事件处理逻辑。
  5. 手动管理协程:如果不想使用 LifecycleScope,可以手动管理协程的生命周期,确保在视图销毁时取消协程。
  6. 手动管理协程:如果不想使用 LifecycleScope,可以手动管理协程的生命周期,确保在视图销毁时取消协程。

应用场景

  • 触摸事件处理:在需要处理复杂触摸事件的场景中,使用协程可以避免阻塞主线程。
  • 异步操作:在触摸事件中执行异步操作,如网络请求或数据库操作。

示例代码

以下是一个完整的示例,展示了如何在 setOnTouchListener 中安全地使用协程:

代码语言:txt
复制
class MainActivity : AppCompatActivity() {
    private val job = Job()
    private val scope = CoroutineScope(job + Dispatchers.Main)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val view = findViewById<View>(R.id.touchView)
        view.setOnTouchListener { v, event ->
            scope.launch {
                when (event.action) {
                    MotionEvent.ACTION_DOWN -> {
                        // 处理按下事件
                    }
                    MotionEvent.ACTION_UP -> {
                        // 处理抬起事件
                    }
                }
            }
            true
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        job.cancel()
    }
}

参考链接

通过以上方法,可以有效避免协程在使用 setOnTouchListener 时破坏应用程序的问题。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

进程、线程、协程

,数据直接访问(数据共享) 为了保证数据安全,必须使用线程锁 GIL全局解释器锁 在python全局解释器下,保证同一时间只有一个线程运行 防止多个线程都修改数据 线程锁(互斥锁) GIL锁只能保证同一时间只能有一个线程对某个资源操作...排它锁:排它,任何线程读取这个这个数据的权利都没有 加上线程锁之后所有其他线程,读都不能读这个数据 有了GIL全局解释器锁为什么还需要线程锁 因为cpu是分时使用的 死锁定义 两个以上的进程或线程在执行过程中...协程微线程,纤程,本质是一个单线程 协程能在单线程处理高并发 线程遇到I/O操作会等待、阻塞,协程遇到I/O会自动切换(剩下的只有CPU操作) 线程的状态保存在CPU的寄存器和栈里而协程拥有自己的空间,...单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上 线程阻塞(Blocking)操作(如IO时)会阻塞掉整个程序 ?...当协程执行到yield关键字时,会暂停在那一行,等到主线程调用send方法发送了数据,协程才会接到数据继续执行。 但是,yield让协程暂停,和线程的阻塞是有本质区别的。

91620

这不会又是一个Go的BUG吧?

确实,删除第二个加读锁的代码就没问题了。如果事情到这就结束了,那这篇文章也没有必要写了,下面我们分析下为什么会死锁。 为什么会死锁 看到这个结果,我第一反应是Go的锁的重入性问题。...只要你愿意,用Java也能实现不可重入锁,但Java中大多数使用的还是可重入锁,因为用起来比较方便。 至于Go为什么不实现一个可重入的锁,可以参考煎鱼大佬的这篇文章《Go 为什么不支持可重入锁?》...一个协程(或线程)已经获取到了读锁,别的协程(线程)获取写锁时必然需要等待读锁的释放 既然这个协程(或线程)已经拥有了这个读锁,那么为什么再次获取读锁时需要管别的写锁是否等待呢?...这点其实在Go源码的注释中体现了,我也是后来才注意到: 图片 翻译一下是: 如果一个协程持有读锁,另一个协程可能会调用Lock加写锁,那么再也没有一个协程可以获得读锁,直到前一个读锁释放,这是为了禁止读锁递归...不过这个警示实在是太不起眼了,大概就是这个效果: 图片 这一幕像极了产品和程序员: 产品经理:我要实现这个功能,怎么实现我不管 Go:这破坏了我的设计原则,不接受这个功能 产品经理:大家都退一步,你换个代价小的方法解决吧

71473
  • 万字长文带你深入浅出 Golang Runtime

    很多人会疑问, 协程到底是个什么东西? 用户态的调度感觉很陌生, 很抽象, 到底是个什么东西我觉得要理解调度, 要理解两个概念: 运行和阻塞. 特别是在协程中, 这两个概念不容易被正确理解....我们理解概念时往往会代入自身感受, 觉得线程或协程运行就是像我们吭哧吭哧的处理事情, 线程或协程阻塞就是做事情时我们需要等待其他人. 然后就在这等着了. 要是其他人搞好了, 那我们就继续做当前的事....当前协程 A 新生成了协程 B, 然后协程 A 比较大概率会结束或者阻塞, 这样 m 直接去执行协程 B, 内存的亲和性也会好很多....首先为什么把全局队列打散, 以及 mcache 为什么跟随 P, 这个在 GM 模型那一页就讲的比较清楚了.然后为什么 P 的个数默认是 CPU 核数: Go 尽量提升性能, 那么在一个 n 核机器上,...fd 的非阻塞模式, 对于没有 ready 的非阻塞 fd 执行网络操作时, linux 内核不阻塞线程, 会直接返回 EAGAIN, 这个时候将协程状态设置为 wait, 然后 m 去调度其他协程.

    2.5K12

    线程(Thread)的基本概念

    为什么?...PCB; (2) 撤消进程,系统在撤消进程时,又必须先对其所占有的资源执行回收操作,然后再撤消PCB; (3) 进程切换,对进程进行上下文切换时,需要保留当前进程的CPU环境,设置新选中进程的CPU环境...扩展 协程 (coroutine) 一种用户态的轻量级线程,它不依赖操作系统的线程或进程调度,而是由应用程序自己来调度协 程的执行。协程之间的切换代价非常小,可以实现高效的并发和异步编程。...协程的实现方式有多种,常见的有对称协程和非对称协程。协程的使用场景主要是在需要高效的异步编程、高并发处理和任务调度的应用程序中,例如网络通信、爬虫、游戏等领域。...它可以在一个线程内并发执行多个协程,从而提高程序的并发性能。Java 纤程的实现方式通常是利用协程调度器来管理多个协程的执行,而协程之间的切换则由协程调度器负责。

    33230

    基于汇编的 CC++ 协程 - 实现

    正如上面两篇文章所说的,我们需要实现的目标有两个: 有同步式服务器编程的顺序思路,便于功能设计和代码调试——我使用了 libco 中的协程部分 有异步 I/O 的性能——我使用了 libevent 中的...以下具体解释实现原理: libco 协程接口 正如前文所说,我使用的是 libco 作为协程库。协程对于应用程序是透明的,但是对于库的实现而言,这才是核心。...co_resume(arg->coroutine); 如果当前协程还没有被执行过,那么执行了这句代码之后,程序会切换到创建 libco 协程时指定的协程函数开始执行。...暂停和恢复协程 在什么时候调用 co_yield是本协程实现的重点,调用 co_yield 的位置,是一个可能会导致上下文切换的地方,也是将异步编程框架转换为同步框架的关键技术点。...至此,《基于汇编的 C/C++ 协程》三大内容,也就完成了。后续如果有时间,我会再写一篇产品使用文档(readme),不过估计就不发布在这里了,而是直接发布在我的 GitHub 上。

    2.4K30

    【翻译】深入 Kotlin 协程

    我将会指导你使用协程相关的基本示例,并观察背后到底发生了什么。 为什么像协程这种解决方案非常有必要? 在现代应用程序开发中,处理多线程任务是不可避免的工作。...在 UI 线程上启动一个网络请求是不明智的做法(在安卓上这甚至不可能,因为你的应用程序会抛出一个丑陋的 NetworkOnMainThreadException 异常),由于网络请求经常会花费至少半秒的时长...那么让我们来看看具体怎样使用命令式的风格写出类似的异步代码吧! 如何使用协程? 协程基于一种新的函数类型,叫做挂起函数。我们可以在函数名称前使用一种新的语言关键字 suspend 来标记。...在当前的上下文中,我们可以通过调用协程(根据文档)来作为“轻量级”的线程。通常,一个协程坐落在一个实际的线程池当中,专门用于后台任务的执行操作,这也就是协程为什么如此高效的原因。...它有个默认值,最终指向一个定义好了的线程池。当然这完全可以使用其他实现方式。在上面那个例子中,我是在 UI 这个协程的上下文中使用 launch 函数,来自于 Anko 库。

    1.5K10

    深入分析 Java、Kotlin、Go 的线程和协程

    协程是什么 协程并不是 Go 提出来的新概念,其他的一些编程语言,例如:Go、Python 等都可以在语言层面上实现协程,甚至是 Java,也可以通过使用扩展库来间接地支持协程。...假设程序中默认创建两个线程为协程使用,在主线程中创建协程ABCD…,分别存储在就绪队列中,调度器首先会分配一个工作线程A执行协程A,另外一个工作线程B执行协程B,其它创建的协程将会放在队列中进行排队等待...633265-20201211165837001-1582226810.jpg 当协程A调用暂停方法或被阻塞时,协程A会进入到挂起队列,调度器会调用等待队列中的其它协程抢占线程A执行。...add 操作,但是由于创建线程太多,这个测试用例在我的机器上要跑 1 分钟左右。...,测试用例在我的机器上执行时间大概是 10 秒钟。

    78130

    深入理解Python异步编程(上)

    彻底理解异步编程是什么、为什么、怎么样。深入学习asyncio的基本原理和原型,了解生成器、协程在Python异步编程中是如何发展的。 前言 很多朋友对异步编程都处于“听说很强大”的认知状态。...但是回调会让程序变得复杂。要异步,必回调,又是否有办法规避其缺点呢?那需要弄清楚其本质,为什么回调是必须的?还有使用回调时克服的那些缺点又是为了什么? 答案是程序为了知道自己已经干了什么?正在干什么?...4.4.5 生成器协程风格和回调风格对比总结 在回调风格中: 存在链式回调(虽然示例中嵌套回调只有一层) 请求和响应也不得不分为两个回调以至于破坏了同步代码那种结构 程序员必须在回调之间维护必须的状态。...所以,在Python 3.3 引入yield from新语法之后,就不再推荐用yield去做协程。全都使用yield from由于其双向通道的功能,可以让我们在协程间随心所欲地传递数据。...在引入asyncio的时候,还提供了一个装饰器@asyncio.coroutine用于装饰使用了yield from的函数,以标记其为协程。但并不强制使用这个装饰器。

    7.1K56

    浅谈进程、线程和协程三者之间的区别和联系

    3,协程 相对子例程而言,协程更为一般和灵活,但在实践中使用没有子例程那样广泛。 根据维基百科对子例程的描述:是一个大型程序中的某部分代码,由一个或多个语句块组成。...4,区别和联系 首先,进程提供给应用程序的关键抽象为: 一个独立的逻辑控制流:它提供一个假象,好像我们的程序独占地使用处理器。 一个私有的地址空间,它提供一个假象,好像我们的程序独占地使用内存系统。...若只有一个进程,会造成同一时间只能干一样事的尴尬(当保存时,就不能通过键盘输入内容)。...这时协程出现了。 因此,协程通过在线程中实现调度,避免了陷入内核级别的上下文切换造成的性能损失,进而突破了线程在IO上的性能瓶颈。...为什么协程不需要经过内核级别的上下文切换,我是这样认为的: 进程和线程都是操作系统自带的,协程是有些程序原生支持的,例如go,lua, 有些是后期版本才有的,比如python2.5 C#等。

    7.7K95

    深入分析 Java、Kotlin、Go 的线程和协程

    协程是什么 协程并不是 Go 提出来的新概念,其他的一些编程语言,例如:Go、Python 等都可以在语言层面上实现协程,甚至是 Java,也可以通过使用扩展库来间接地支持协程。...假设程序中默认创建两个线程为协程使用,在主线程中创建协程ABCD…,分别存储在就绪队列中,调度器首先会分配一个工作线程A执行协程A,另外一个工作线程B执行协程B,其它创建的协程将会放在队列中进行排队等待...当协程A调用暂停方法或被阻塞时,协程A会进入到挂起队列,调度器会调用等待队列中的其它协程抢占线程A执行。...add 操作,但是由于创建线程太多,这个测试用例在我的机器上要跑 1 分钟左右。...,测试用例在我的机器上执行时间大概是 10 秒钟。

    1.2K31

    Kotlin | 关于协程异常处理,你想知道的都在这里

    ,其会改变异常的传递方式,当使用它时,我们子协程的失败不会影响到其他子协程与父协程,通俗点理解就是:子协程会自己处理异常,并不会影响其兄弟协程或者父协程,如下图所示: 举个简单的例子: val scope...结果是不能 为什么? 我不是已经使用了 SupervisorJob() 吗?...我们用一张图来看一下: 如上图所示,我们在 scope.launch 时传递了 SupervisorJob ,看着似乎没什么问题,我们期望的是 SupervisorJob 也会传递到子协程。...---- coroutineScope 其主要用于并行分解协程子任务时而使用,当其范围内任何子协程失败时,其所有的子协程也都将被取消,一旦内部所有的子协程完成,其也会正常返回。...引用官方的一句话就是:想要避免取消操作在异常发生时被传播,记得使用 SupervisorJob ;反之则使用 Job。 对于一个普通的协程,如何处理我的异常?

    92620

    当谈论协程时,我们在谈论什么

    第一部分介绍协程的历史; 第二部分主要是介绍函数调用和协作式多任务处理,虽然其他介绍协程的文章中也都讲解了函数调用,在本文中,我在构思如何进行分享时,特意使用汇编来实现函数调用 (汇编实现 main 调用...在本文中,我将试着去回答以下四个问题: Q1 (Why): 为什么需要协程? 我们会一起回顾协程出现的历史背景,当时要解决什么问题;同时,现在是什么场景,需要使用协程来进行处理?...这就是我本次分享想要达成的目标 —— 回答这四个问题。 首先我们来看第一个问题,为什么需要协程? Q1: 为什么需要协程?...,例如 recv(); 编译为动态链接库 librecvhook.so; 应用程序使用 recv(),在加载动态库时指定顺序,librecvhook.so > libc.so; 这样应用程序就会调用步骤...接下来,对今天的分享做一个总结。 总结 在今天的协程分享中,我尝试去回答了以下四个问题: Q1 (Why): 为什么需要协程? Q2 (What): 到底什么是协程?

    1.4K50

    大名鼎鼎的 Linux —— 进程,线程,协程

    前言 Linux 作为当今服务端最流行的操作系统,是每个后端工程师应当熟练使用和理解的。本篇文章会详细讲述 Linux 系统中的一些基础概念:进程、线程,以及后面由各编程语言所实现的协程。...当 IO 阻塞时,操作系统会挂起线程,然后让其他线程执行,不会让 cpu 傻傻等着 线程切换无非是改变 CPU 下一条指令执行的地址,那我们能不能在应用程序的用户态做到?...这样对于操作系统而言,这个程序实际上只阻塞了一次 协程调度 上面说到在 IO 阻塞的时候,会进行协程切换。那如何知道当前的 IO 是阻塞的呢? 答案就是之前写到的一篇文章——IO多路复用。...,上面我说到的方法是 php 的协程扩展 swoole 用到的方式。...但是因为 php 对线程的支持不是很好,所以 swoole 的协程是单线程的 golang golang 这种编译型语言对各种 io 函数进行了封装,这些封装的函数提供给应用程序使用,而其内部调用了操作系统的异步

    77200

    流畅的 Python 第二版(GPT 重译)(十)

    ③ 当在控制此协程的Task上调用cancel方法时,会引发asyncio.CancelledError。是时候退出循环了。...与持有锁以同步多个线程的操作相反,协程是“同步”的定义:任何时候只有一个协程在运行。当你想放弃控制时,你使用await将控制权交还给调度程序。...这就是为什么可以安全地取消一个协程:根据定义,只有在协程被挂起在await表达式时才能取消协程,因此你可以通过处理CancelledError异常来执行清理。...我预计在 6 个进程后运行时间会增加,因为 CPU 争用,而在 10 个进程时达到 12.51 秒的局部最大值。...我没有预料到,也无法解释为什么在 11 个进程时性能有所提高,并且从 13 到 20 个进程时几乎保持不变,中位时间仅略高于 6 个进程的最低中位时间。

    28010

    golang net包里的异步IO实现原理分析

    accept新的connection,使用异步编程我们知道,如果没有 新连接到来,该协程会一直被阻塞,直到新连接到来有人唤醒了该协程。...: Write尽量将用户缓冲区的内容全部写入至底层socket,如果遇到socket暂时不可写入,会阻塞当前协程; Read在某次读取成功时立即返回,可能会导致读取的数据量少于用户缓冲区的大小; 为什么会在实现上有此不同...,我想可能read的优先级比较高吧,应用程序可能一直在等着,我们不能等到数据一直读完才返回,会阻塞用户。...,在协程被唤醒的时候,该标记位应该会被置位。...sysmon:golang中的监控协程,会周期性检查就绪socket TODO: 为什么是在这些地方检查socket就绪事件呢?

    1.5K10

    Python 高级教程之线程进程和协程

    t1.start() t2.start() 一旦线程启动,当前程序(你可以把它想象成一个主线程)也会继续执行。为了在线程完成之前停止当前程序的执行,我们使用join方法。...它们用于协作式多任务处理,其中一个进程定期或在空闲时自愿放弃(放弃)控制权,以使多个应用程序能够同时运行。协程和子程序的区别是: 与子程序不同,协程有许多用于暂停和恢复执行的入口点。...Python 协程 在 Python 中,协程类似于生成器,但几乎没有额外的方法,而且我们使用yield语句的方式也有细微的变化。生成器为迭代生成数据,而协程也可以使用数据。...当我们调用协程时,什么都没有发生,它只在响应next()和send ()方法时运行。在上面的例子中可以清楚地看到这一点,因为只有在调用__next__()方法之后,我们的协程才开始执行。...关闭协程 协程可能无限期运行,关闭协程使用close()方法。当协程关闭时,它会生成GeneratorExit异常,该异常可以以通常捕获的方式捕获。

    36531

    同步与异步 Python 有何不同?

    在本文中,我将继续使用 Web 应用程序作为例子,但还有其它类型的应用程序也从并发中获益。因此,这个讨论并不仅仅是针对 Web 应用程序的。 术语“同步”和“异步”指的是编写并发应用程序的两种方式。...2 Python 中实现异步的 2 种方法 我敢肯定,你知道要在 Python 中写一个异步应用程序,你可以使用 asyncio package,这个包是在协程的基础上实现了所有异步应用程序都需要的暂停和恢复特性...我的意思是,基于协程的应用程序需要使用一种特定的语法来书写,而基于 greenlet 的应用程序看起来几乎和普通 Python 代码一样。...这非常酷,因为在某些情况下,这让同步代码可以被异步执行,这是诸如asyncio之类的基于协程的方案做不到的。 那么在 greenlet 方面,跟asyncio对等的库有哪些?...我希望你能记住以下两个关键点: 异步应用程序只有在高负载下才会比同步应用程序做得更好 多亏了 greenlets,即使你用一般方式写代码并使用 Flask 或 Django 之类的传统框架,也能从异步中受益

    1.2K20
    领券