Android-HandlerThread

在外部線程并不能拿到匿名內部類線程對象的Looper。比如主線程,創(chuàng)建了一個Thread對象,并不能通過Thread對象獲取到該Thread的Looper對象。
而如果將Thread的Looper寫全局對象,那么就存在耦合,并不會隨著線程Thread的消失而消失。
HandlerThread就是一個線程。在HandlerThread中的run方法中,自動幫我們完成了Looper.prepare和Looper.loop()。
HandlerThread存在的意義主要是:
方便初始化,方便取線程Looper對象
保證了線程安全
解決有可能的異步問題。
面試:多線程的鎖機制。
當有人通過HandlerThread的getLooper()方法獲取線程對應的Looper對象的時候,如果Looper對象為null,那么就會調用wait()等待。而在HandlerThread的run方法中,如果Looper.prepare()成功之后,就會調用notifyAll()通知需要獲取鎖。
wait():會釋放鎖
notifyAll():不會釋放當前持有的鎖,只是會喚醒其他等待這個鎖的線程,但是并不意味著會立馬執(zhí)行,需要等待notifyAll()所在的鎖中的代碼執(zhí)行完成并且釋放鎖之后,被喚醒的其他線程去持有鎖并且繼續(xù)執(zhí)行。

HandlerThread的應用:在IntentService中
IntentService初始化之后,實現onHandleIntent方法,而在IntentService中處理Handler消息的時候,就是調用onHandleIntent方法進行處理。
而IntentService就是可以在Service中實現耗時操作,其實就是在其內部有一個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一般用于處理后臺耗時任務。
IntentService會維持一個子線程獨有的消息隊列,保證每一個任務都是在同一個線程。這樣就可以保證在IntentService一定是處理的同一個線程的任務。這樣就可以保證任務在同一個線程中按照先后順序執(zhí)行。
應用需求:一項任務分成幾個子任務,子任務按順序先后執(zhí)行,子任務全部執(zhí)行完成之后,這項任務才算成功。
這個需求可以用多個線程來處理,一個線程處理完->下一個線程->下一個線程
IntentService也可以幫助我們實現這個需求。而且,能夠很好的管理線程,保證只有一個子線程處理工作,而且是一個一個的完成任務,有條不紊的進行對多個子任務的處理。
IntentService的使用:

public class MyIntentService extends IntentService {

  /** 
    * 在構造函數中傳入線程名字
    **/  
    public myIntentService() {
        // 調用父類的構造函數
        // 參數 = 工作線程的名字
        super("myIntentService");
    }

   /** 
     * 復寫onHandleIntent()方法
     * 根據 Intent實現 耗時任務 操作
     **/  
    @Override
    protected void onHandleIntent(Intent intent) {

        // 根據 Intent的不同,進行不同的事務處理
        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();
    }
   /** 
     * 復寫onStartCommand()方法
     * 默認實現 = 將請求的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);

            // 同一服務只會開啟1個工作線程
            // 在onHandleIntent()函數里,依次處理傳入的Intent請求
            // 將請求通過Bundle對象傳入到Intent,再傳入到服務里

            // 請求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事務提交,而提交的時候,是通過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事務提交的時候,是通過Handler發(fā)送消息提交事務,而這個任務并不一定是立馬執(zhí)行,也不一定是在下一次任務來的時候就已經提交完成,因為Glide可以多線程使用。當一個線程使用創(chuàng)建了空的Fragment生命周期管理,那么下一個線程異步請求創(chuàng)建空的生命周期管理的時候,先去查詢一個臨時HashMap緩存,這是因為Fragment事務提交是Handler發(fā)送消息,并不能保證立馬執(zhí)行完成,而在臨時HashMap緩存一個空的Fragment生命周期,然后經過兩次的判空,而空的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;
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容