1. 程式人生 > >Android中在主執行緒呼叫Thread.sleep()會導致Handler.postDelayed()在sleep的這段時間無法執行。

Android中在主執行緒呼叫Thread.sleep()會導致Handler.postDelayed()在sleep的這段時間無法執行。

場景是一個公司之前的老專案裡面有人使用了Handler.postDelayed(mRunnable,1000)做一個重複計時並且累加的功能,需求是每一秒都要跑一次這個Runnable,同時是有視訊在播放的,Runnable裡面是比較視訊播放的進度和我跑了多少秒來比對,再確定要不要做一些什麼操作,然後一直這樣重複跑,但是這個介面會不定時會開啟一個畫素1px的Activity介面去做拍照的功能,在拍照介面有一行程式碼這麼寫的,而且是在主執行緒直接這麼寫的(很無語):

Thread.sleep(2000);

之前一直沒怎麼注意這一點,經過蛋疼的各種除錯發現剛好是在呼叫這行程式碼的2000ms時間內,我的Handler.postDelayed(mRunnable,1000)失效了。於是把sleep的程式碼移除成其他的方式,就恢復正常了。

於是自己寫了個demo再實際一下效果:

package com.wepon.sleep;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {

    private final 
String LOG_TAG = MainActivity.class.getSimpleName(); private TextView mTvDisplay; private Handler mHandler = new Handler(); private Runnable mRunnable = new Runnable() { @Override public void run() { Log.d(LOG_TAG, System.currentTimeMillis() / 1000 + ""); mTvDisplay.setText(System.currentTimeMillis
() / 1000 + ""); mHandler.postDelayed(this, 1000); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTvDisplay = findViewById(R.id.tv_display); // sleep findViewById(R.id.bt_sleep).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }); // 開始計數 findViewById(R.id.bt_start).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mHandler.postDelayed(mRunnable, 1000); } }); } @Override protected void onDestroy() { mHandler.removeCallbacks(mRunnable); super.onDestroy(); } }
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
    <Button
android:id="@+id/bt_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="71dp"
android:text="start" />
    <Button
android:id="@+id/bt_sleep"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignStart="@+id/bt_start"
android:layout_marginTop="160dp"
android:text="sleep 2秒" />
    <TextView
android:id="@+id/tv_display"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginStart="43dp"
android:layout_marginTop="25dp"
android:text="0"
android:textSize="18sp" />
</RelativeLayout>

跑這個demo,先 start 會進行 1 秒列印一次時間點,然後點 sleep 2秒就會中斷handler.postDelay()2秒了。如下:


希望踩這個坑的朋友能看到。。。還有就是不要在主執行緒去sleep,不要在主執行緒去sleep,不要在主執行緒去sleep!!