Android HandlerThread 和 IntentService

1.HandlerThread

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
    private @Nullable Handler mHandler;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    
   
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    
   
    protected void onLooperPrepared() {
    }

    @Override
    public void run() {
        // 獲取線程 id
        mTid = Process.myTid();
        //構建一個 Looper
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        //設置線程優(yōu)先級
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        // Looper 循環(huán)
        mTid = -1;
    }
    
     // 獲取當前線程的 Looper,
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
       
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }


     /**
     * @return a shared {@link Handler} associated with this thread
     * @hide 方法隱藏掉炼吴,無法調用
     */
    @NonNull
    public Handler getThreadHandler() {
        if (mHandler == null) {
            mHandler = new Handler(getLooper());
        }
        return mHandler;
    }

     //線程退出方法期丰,主要是調用 Looper.quit() 方法,不然一直在循環(huán)
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }

    //同上沸伏,不過這個方法會把消息隊列中的已有消息處理完才會安全地退出
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

    public int getThreadId() {
        return mTid;
    }
}

1.HandlerThread 運行 start() 方法须尚,回調 run() 方法。
2.在 run() 方法中通過 Looper.prepare() 來創(chuàng)建消息隊列假消,并通過 Looper.looper() 方法來開啟消息循環(huán)柠并。
3.由于 Loop.loop() 是一個死循環(huán),導致 run() 也是無線循環(huán)富拗,因此當我們不需要使用 HandlerThread 的時候臼予,要調用它的 quit() 方法或者 quiteSafely() 方法。

一般用法就是用來獲取一個異步的Lopper媒峡,從而創(chuàng)建一個異步線程的Handler

public class HandlerThreadActivity extends BaseActivity {
    
    private static final String TAG = "HandlerThreadActivity";

    private Button mStartBtn;
    private Handler mHandler;
    private HandlerThread mHandlerThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler_thread);
        mStartBtn = findViewById(R.id.start_btn);

        mHandlerThread = new HandlerThread("THREAD_NAME");
        mHandlerThread.start();
        mHandler = new Handler(mHandlerThread.getLooper());

        mStartBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Log.d(TAG, Thread.currentThread().getId() + " " + String.valueOf((Looper.myLooper() == Looper.getMainLooper())) + " 任務:" + this.hashCode());
                        SystemClock.sleep(3000);
                    }
                });
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandlerThread.quit();
    }
}

輸出日志:


image.png

2. IntentService

package android.app;
 
import android.annotation.WorkerThread;
import android.annotation.Nullable;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
 
public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;
 
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }
 
        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }
 
    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     */
    public IntentService(String name) {
        super();
        mName = name;
    }
 
    /**
     * Sets intent redelivery preferences.  Usually called from the constructor
     */
    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }
 
    @Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.
 
        super.onCreate();
      //注意這里瘟栖,創(chuàng)建了一個HandlerThread,也就是創(chuàng)建了一個異步線程的Looper
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
   
        mServiceLooper = thread.getLooper();
        //創(chuàng)建處理異步線程任務的Handler
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }
 
    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }
 
    /**
     * 每次啟動都會發(fā)送一個msg
     */
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }
 
    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }
 
    /**
     * Unless you provide binding for your service, you don't need to implement this
     */
    @Override
    @Nullable
    public IBinder onBind(Intent intent) {
        return null;
    }
 
    /**
     */
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}

一般用法是繼承IntentService,然后把要做的業(yè)務邏輯重寫在OnHandlerIntent()方法里谅阿,這個方法是運行在異步線程的,每次啟動一下該服務酬滤,執(zhí)行完后會自己銷毀签餐。例:

package com.bourne.android_common.ServiceDemo;
 
import android.app.IntentService;
import android.content.Intent;
import android.support.v4.content.LocalBroadcastManager;
 
import com.bourne.common_library.utils.Logout;
 
public class MyIntentService extends IntentService {
 
    /**
     * 是否正在運行
     */
    private boolean isRunning;
 
    /**
     *進度
     */
    private int count;
 
    /**
     * 廣播
     */
    private LocalBroadcastManager mLocalBroadcastManager;
 
    public MyIntentService() {
        super("MyIntentService");
        Logout.e("MyIntentService");
    }
 
    @Override
    public void onCreate() {
        super.onCreate();
        Logout.e("onCreate");
        mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
    }
 
    @Override
    protected void onHandleIntent(Intent intent) {
        Logout.e("onHandleIntent");
        try {
            Thread.sleep(1000);
            isRunning = true;
            count = 0;
            while (isRunning) {
                count++;
                if (count >= 100) {
                    isRunning = false;
                }
                Thread.sleep(50);
                sendThreadStatus("線程運行中...", count);
            }
 
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 發(fā)送進度消息
     */
    private void sendThreadStatus(String status, int progress) {
        Intent intent = new Intent(IntentServiceActivity.ACTION_TYPE_THREAD);
        intent.putExtra("status", status);
        intent.putExtra("progress", progress);
        mLocalBroadcastManager.sendBroadcast(intent);
    }
 
    @Override
    public void onDestroy() {
        super.onDestroy();
        Logout.e("線程結束運行..." + count);
    }
}

創(chuàng)建個Activity:

package com.bourne.android_common.ServiceDemo;
 
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
 
import com.bourne.android_common.R;
 
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
 
public class IntentServiceActivity extends AppCompatActivity {
    /**
     * 狀態(tài)文字
     */
    @BindView(R.id.tv_status)
    TextView tv_status;
 
    /**
     * 進度文字
     */
    @BindView(R.id.tv_progress)
    TextView tv_progress;
 
    /**
     * 進度條
     */
    @BindView(R.id.progressbar)
    ProgressBar progressbar;
 
    private LocalBroadcastManager mLocalBroadcastManager;
    private MyBroadcastReceiver mBroadcastReceiver;
    public final static String ACTION_TYPE_THREAD = "action.type.thread";
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_intent_service);
        ButterKnife.bind(this);
 
        //注冊廣播
        mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
        mBroadcastReceiver = new MyBroadcastReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ACTION_TYPE_THREAD);
        mLocalBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);
 
        initView();
    }
 
    public void initView() {
        tv_status.setText("線程狀態(tài):未運行");
        progressbar.setMax(100);
        progressbar.setProgress(0);
        tv_progress.setText("0%");
    }
 
    @Override
    protected void onDestroy() {
        super.onDestroy();
        //注銷廣播
        mLocalBroadcastManager.unregisterReceiver(mBroadcastReceiver);
    }
 
    public class MyBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            switch (intent.getAction()) {
 
                case ACTION_TYPE_THREAD:
                    //更改UI
                    int progress = intent.getIntExtra("progress", 0);
                    tv_status.setText("線程狀態(tài):" + intent.getStringExtra("status"));
                    progressbar.setProgress(progress);
                    tv_progress.setText(progress + "%");
                    if (progress >= 100) {
                        tv_status.setText("線程結束");
                    }
                    break;
            }
        }
    }
 
    @OnClick({R.id.btn_start})
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_start:
                Intent intent = new Intent(IntentServiceActivity.this, MyIntentService.class);
                startService(intent);
                break;
        }
    }
}

沒什么高深的東西,但是沒看過源碼可能不知道他的用法盯串,不少面試官會拿來問氯檐,用來檢測你對安卓api的熟悉程度。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末体捏,一起剝皮案震驚了整個濱河市冠摄,隨后出現的幾起案子,更是在濱河造成了極大的恐慌几缭,老刑警劉巖河泳,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異年栓,居然都是意外死亡拆挥,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門某抓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纸兔,“玉大人惰瓜,你說我怎么就攤上這事『嚎螅” “怎么了崎坊?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長洲拇。 經常有香客問我流强,道長,這世上最難降的妖魔是什么呻待? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任打月,我火速辦了婚禮,結果婚禮上蚕捉,老公的妹妹穿的比我還像新娘奏篙。我一直安慰自己,他們只是感情好迫淹,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布秘通。 她就那樣靜靜地躺著,像睡著了一般敛熬。 火紅的嫁衣襯著肌膚如雪肺稀。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天应民,我揣著相機與錄音话原,去河邊找鬼。 笑死诲锹,一個胖子當著我的面吹牛繁仁,可吹牛的內容都是我干的。 我是一名探鬼主播归园,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼黄虱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了庸诱?” 一聲冷哼從身側響起捻浦,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎桥爽,沒想到半個月后朱灿,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡聚谁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年母剥,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡环疼,死狀恐怖习霹,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情炫隶,我是刑警寧澤淋叶,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站伪阶,受9級特大地震影響煞檩,放射性物質發(fā)生泄漏。R本人自食惡果不足惜栅贴,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一斟湃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧檐薯,春花似錦凝赛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至赚楚,卻和暖如春毙沾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背宠页。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工左胞, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人勇皇。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓罩句,卻偏偏與公主長得像,于是被迫代替她去往敵國和親敛摘。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內容