美文网首页android基础知识Android开发经验谈Android开发
Android主线程进行 Thread.Sleep()会导致AN

Android主线程进行 Thread.Sleep()会导致AN

作者: 我说的这句话是谎话 | 来源:发表于2018-04-12 12:07 被阅读270次

    首先 先 明白一个问题:什么是ANR

    Application Not Responding,意思是”应用没有响应“

    以前我的理解就是 “在主线程做了耗时操作”就会引起ANR,现在我觉得我是错误的,ANR的意思是应用没有响应,耗时操作实际上 并不一定会导致没有响应,我对没有响应的理解是

    有人(事件或操作)发出了一个请求,但是主线程没有对这个人进行反馈(可能是没时间、可能是不想理、可能是手被绑住了没有办法理你),这个叫没有响应

    那举个例子

    override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            // do some blablabla...
      
            Log.d("test", "准备sleep30秒")
            Thread.sleep(30000)
            Log.d("test", "sleep30秒完成")
    
            // do some blablabla...
    
        }
    

    这段代码在 onCreate 中 sleep 了 30秒,会出现 ANR 吗?

    答案是

    可能会,也可能不会

    当主线程在 Sleep 的时候,如果 UI线程不需要进行操作,也就是说没有消息会发送给UI线程并要求UI线程进行处理的时候 Sleep 30秒就不会导致ANR,因为没有 出现 ANR(应用没有响应)的情况啊,没有人向线程请求什么东西,也就不需要响应了,既然没有响应了,那怎么会有ANR呢?

    但是,但线程在Sleep的时候,主线程有接收到需要处理的请求的时候

    需要注意的是,需要处理的请求,不一定只是用户的手动触摸,也有可能是其他线程需要对线程进行UI更新的请求,这个时候UI线程正在Sleep,根本没有办法理你(不想理你),这就符合了ANR的条件,所以会出现ANR(比如说在这 30 秒内,点击了 返回按钮,就会出现 ANR)

    另外,如果在这个30秒内进行UI更新会发生ANR吗?

    override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            Handler().postDelayed(Runnable {
                Log.d("sleep_test", "准备更新text")
                btn_test.text = "update btn text"
                Log.d("sleep_test", "更新text完成")
            }, 10000)
    
            Log.d("sleep_test", "准备sleep30秒")
            Thread.sleep(30000)
            Log.d("sleep_test", "sleep30秒完成")
    
            Log.d("sleep_test", "first update")
            btn_test.text = "This is the first update"
    }
    

    输出结果为:

    D/sleep_test: 准备sleep30秒
    D/sleep_test: sleep30秒完成
    D/sleep_test: first update
    D/sleep_test: 准备更新text
    D/sleep_test: 更新text完成
    

    并没有发生ANR,这是因为这段代码里面的sleep休眠了线程,代码里面的更新操作根本没有在 sleep的时候被触发(处于休眠状态),也就没有了发送请求的前提条件,所以并没有发生ANR。但是如果用户手动进行了触摸操作,相当于有一个请求的事件了,而主线程又被休眠了,超过了规定的时间就会触发ANR提示

    在android里面都对其进行了常量定义

    Android N 的 ANR时间

    • Service 超时
    // How long we wait for a service to finish executing.
    static final int SERVICE_TIMEOUT = 20*1000; // 前台
    
    // How long we wait for a service to finish executing.
    static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10; // 后台
    
    • Broadcast 超时
    // How long we allow a receiver to run before giving up on it.
    static final int BROADCAST_FG_TIMEOUT = 10*1000;  // 前台
    static final int BROADCAST_BG_TIMEOUT = 60*1000;  // 后台
    
    • InputDispatching 超时
     // How long we wait until we timeout on key dispatching.
     static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
    
    • ContentProvider 超时
    // How long we wait for an attached process to publish its content providers
    // before we decide it must be hung.
    static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000;
    

    ANR的学习目前就到这个点,后续还要继续学习

    延伸:Thread.sleep() 还有其加锁的问题

    由于CPU分配的每个线程的时间片极为短暂(一般为几十毫秒),所以,CPU通过不停地切换线程执行,这样就给程序员一种错觉,以为多个线程是在同时执行。sleep就是正在执行的线程主动让出CPU,CPU去执行其他线程,在sleep指定的时间过后,CPU才会回到这个线程上继续往下执行。

    已发布至: jimbray

    相关文章

      网友评论

        本文标题:Android主线程进行 Thread.Sleep()会导致AN

        本文链接:https://www.haomeiwen.com/subject/vvexkftx.html