在外部線程并不能拿到匿名內(nèi)部類線程對象的Looper。比如主線程通贞,創(chuàng)建了一個Thread對象,并不能通過Thread對象獲取到該Thread的Looper對象。
而如果將Thread的Looper寫全局對象敬飒,那么就存在耦合,并不會隨著線程Thread的消失而消失芬位。
HandlerThread就是一個線程无拗。在HandlerThread中的run方法中,自動幫我們完成了Looper.prepare和Looper.loop()昧碉。
HandlerThread存在的意義主要是:
方便初始化英染,方便取線程Looper對象
保證了線程安全
解決有可能的異步問題。
面試:多線程的鎖機制被饿。
當有人通過HandlerThread的getLooper()方法獲取線程對應(yīng)的Looper對象的時候四康,如果Looper對象為null,那么就會調(diào)用wait()等待狭握。而在HandlerThread的run方法中闪金,如果Looper.prepare()成功之后,就會調(diào)用notifyAll()通知需要獲取鎖论颅。
wait():會釋放鎖
notifyAll():不會釋放當前持有的鎖哎垦,只是會喚醒其他等待這個鎖的線程,但是并不意味著會立馬執(zhí)行恃疯,需要等待notifyAll()所在的鎖中的代碼執(zhí)行完成并且釋放鎖之后撼泛,被喚醒的其他線程去持有鎖并且繼續(xù)執(zhí)行。
HandlerThread的應(yīng)用:在IntentService中
IntentService初始化之后澡谭,實現(xiàn)onHandleIntent方法愿题,而在IntentService中處理Handler消息的時候,就是調(diào)用onHandleIntent方法進行處理蛙奖。
而IntentService就是可以在Service中實現(xiàn)耗時操作潘酗,其實就是在其內(nèi)部有一個ServiceHandler,而ServiceHandler的創(chuàng)建雁仲,就是通過HandlerThread對象獲取到子線程的Looper對象仔夺,然后創(chuàng)建了ServiceHandler對象。
IntentService.ServiceHandler源碼:
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
// 處理消息之后攒砖,停止Service缸兔,自己停止自己日裙。
stopSelf(msg.arg1);
}
}
IntentService.onCreate()源碼:
@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();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
// 創(chuàng)建子線程HandlerThread對象的Handler
mServiceHandler = new ServiceHandler(mServiceLooper);
}
Service一般用于處理后臺耗時任務(wù)。
IntentService會維持一個子線程獨有的消息隊列惰蜜,保證每一個任務(wù)都是在同一個線程昂拂。這樣就可以保證在IntentService一定是處理的同一個線程的任務(wù)。這樣就可以保證任務(wù)在同一個線程中按照先后順序執(zhí)行抛猖。
應(yīng)用需求:一項任務(wù)分成幾個子任務(wù)格侯,子任務(wù)按順序先后執(zhí)行,子任務(wù)全部執(zhí)行完成之后财著,這項任務(wù)才算成功联四。
這個需求可以用多個線程來處理,一個線程處理完->下一個線程->下一個線程
IntentService也可以幫助我們實現(xiàn)這個需求撑教。而且朝墩,能夠很好的管理線程,保證只有一個子線程處理工作伟姐,而且是一個一個的完成任務(wù)收苏,有條不紊的進行對多個子任務(wù)的處理。
IntentService的使用:
public class MyIntentService extends IntentService {
/**
* 在構(gòu)造函數(shù)中傳入線程名字
**/
public myIntentService() {
// 調(diào)用父類的構(gòu)造函數(shù)
// 參數(shù) = 工作線程的名字
super("myIntentService");
}
/**
* 復(fù)寫onHandleIntent()方法
* 根據(jù) Intent實現(xiàn) 耗時任務(wù) 操作
**/
@Override
protected void onHandleIntent(Intent intent) {
// 根據(jù) Intent的不同玫镐,進行不同的事務(wù)處理
String taskName = intent.getExtras().getString("taskName");
switch (taskName) {
case "task1":
Log.i("myIntentService", "do task1");
break;
case "task2":
Log.i("myIntentService", "do task2");
break;
default:
break;
}
}
@Override
public void onCreate() {
Log.i("myIntentService", "onCreate");
super.onCreate();
}
/**
* 復(fù)寫onStartCommand()方法
* 默認實現(xiàn) = 將請求的Intent添加到工作隊列里
**/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("myIntentService", "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.i("myIntentService", "onDestroy");
super.onDestroy();
}
}
在AndroidManifest.xml中注冊
<service android:name=".myIntentService">
<intent-filter >
<action android:name="cn.scu.finch"/>
</intent-filter>
</service>
在Activity中啟動IntentService
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 同一服務(wù)只會開啟1個工作線程
// 在onHandleIntent()函數(shù)里倒戏,依次處理傳入的Intent請求
// 將請求通過Bundle對象傳入到Intent,再傳入到服務(wù)里
// 請求1
Intent i = new Intent("cn.scu.finch");
Bundle bundle = new Bundle();
bundle.putString("taskName", "task1");
i.putExtras(bundle);
startService(i);
// 請求2
Intent i2 = new Intent("cn.scu.finch");
Bundle bundle2 = new Bundle();
bundle2.putString("taskName", "task2");
i2.putExtras(bundle2);
startService(i2);
startService(i); //多次啟動
}
}
除了在IntentService使用HandlerThread以外:
(1)在Fragment的生命周期管理
Fragment一般是通過FragmentManager事務(wù)提交恐似,而提交的時候杜跷,是通過Handler發(fā)送消息執(zhí)行提交過程。
FragmentManager中使用了Handler進行提交矫夷。
void scheduleCommit() {
synchronized (this) {
boolean postponeReady =
mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;
if (postponeReady || pendingReady) {
mHost.getHandler().removeCallbacks(mExecCommit);
mHost.getHandler().post(mExecCommit);
}
}
}
(2)在Glide的生命周期管理也使用了類似的方式葛闷,即創(chuàng)建一個空的Fragment管理生命周期,如果Fragment是空的時候双藕,先從緩存去中淑趾,如果緩存中還是空的,則重新創(chuàng)建一個新的Fragment忧陪,這里使用緩存的目的扣泊,是因為Fragment事務(wù)提交的時候,是通過Handler發(fā)送消息提交事務(wù)嘶摊,而這個任務(wù)并不一定是立馬執(zhí)行延蟹,也不一定是在下一次任務(wù)來的時候就已經(jīng)提交完成,因為Glide可以多線程使用叶堆。當一個線程使用創(chuàng)建了空的Fragment生命周期管理阱飘,那么下一個線程異步請求創(chuàng)建空的生命周期管理的時候,先去查詢一個臨時HashMap緩存,這是因為Fragment事務(wù)提交是Handler發(fā)送消息沥匈,并不能保證立馬執(zhí)行完成蔗喂,而在臨時HashMap緩存一個空的Fragment生命周期,然后經(jīng)過兩次的判空高帖,而空的Fragment就算沒有綁定缰儿,那么也會先在緩存中存在這個對象,那么第二個線程進來之后就不會去創(chuàng)建這個空的Fragment生命周期管理棋恼。
@NonNull
private RequestManagerFragment getRequestManagerFragment(
@NonNull final android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}