HandlerThread
1. Override Runnable
public class LauncherModel extends BroadcastReceiver { ...... private LoaderTask mLoaderTask; private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader"); static { sWorkerThread.start(); } private static final Handler sWorker = new Handler(sWorkerThread.getLooper()); ...... public void startLoader(Context context, boolean isLaunching) { ...... synchronized (mLock) { ...... // Don't bother to start the thread if we know it's not going to do anything if (mCallbacks != null && mCallbacks.get() != null) { ...... mLoaderTask = new LoaderTask(context, isLaunching); sWorker.post(mLoaderTask); } } } ...... private class LoaderTask implements Runnable { ...... public void run() { ...... keep_running: { ...... // second step if (loadWorkspaceFirst) { ...... loadAndBindAllApps(); } else { ...... } ...... } ...... } ...... } ...... }
/** * This service essentially plays the role of a "worker thread", allowing us to store * incoming messages to the database, update notifications, etc. without blocking the * main thread that SmsReceiver runs on. */ public class SmsReceiverService extends Service { private static final String TAG = "SmsReceiverService"; private ServiceHandler mServiceHandler; private Looper mServiceLooper; private boolean mSending; ..... public Handler mToastHandler = new Handler(); // This must match SEND_PROJECTION. private static final int SEND_COLUMN_ID = 0; private static final int SEND_COLUMN_THREAD_ID = 1; private static final int SEND_COLUMN_ADDRESS = 2; private static final int SEND_COLUMN_BODY = 3; private static final int SEND_COLUMN_STATUS = 4; private int mResultCode; @Override public void onCreate() { // Start up the thread running the service. Note that we create a // separate thread because the service normally runs in the process's // main thread, which we don't want to block. HandlerThread thread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // Temporarily removed for this duplicate message track down. mResultCode = intent != null ? intent.getIntExtra("result", 0) : 0; if (mResultCode != 0) { Log.v(TAG, "onStart: #" + startId + " mResultCode: " + mResultCode + " = " + translateResultCode(mResultCode)); } Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); return Service.START_NOT_STICKY; } ..... @Override public void onDestroy() { // Temporarily removed for this duplicate message track down. // if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE) || LogTag.DEBUG_SEND) { // Log.v(TAG, "onDestroy"); // } mServiceLooper.quit(); } @Override public IBinder onBind(Intent intent) { return null; } private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } /** * Handle incoming transaction requests. * The incoming requests are initiated by the MMSC Server or by the MMS Client itself. */ @Override public void handleMessage(Message msg) { int serviceId = msg.arg1; Intent intent = (Intent)msg.obj; if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "handleMessage serviceId: " + serviceId + " intent: " + intent); } if (intent != null) { String action = intent.getAction(); int error = intent.getIntExtra("errorCode", 0); if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "handleMessage action: " + action + " error: " + error); } if (MESSAGE_SENT_ACTION.equals(intent.getAction())) { handleSmsSent(intent, error); } else if (SMS_RECEIVED_ACTION.equals(action)) { handleSmsReceived(intent, error); } else if (ACTION_BOOT_COMPLETED.equals(action)) { handleBootCompleted(); } else if (TelephonyIntents.ACTION_SERVICE_STATE_CHANGED.equals(action)) { handleServiceStateChanged(intent); } else if (ACTION_SEND_MESSAGE.endsWith(action)) { handleSendMessage(); } } // NOTE: We MUST not call stopSelf() directly, since we need to // make sure the wake lock acquired by AlertReceiver is released. SmsReceiver.finishStartingService(SmsReceiverService.this, serviceId); } } ..... }