下面列出了android.os.HandlerThread#quit ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private synchronized void stopDraw() {
if (handler != null) {
handler.quit();
handler = null;
}
HandlerThread handlerThread = this.mHandlerThread;
mHandlerThread = null;
if (handlerThread != null) {
try {
handlerThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
handlerThread.quit();
}
}
private synchronized void stopDraw() {
if (handler != null) {
handler.quit();
handler = null;
}
HandlerThread handlerThread = this.mHandlerThread;
mHandlerThread = null;
if (handlerThread != null) {
try {
handlerThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
handlerThread.quit();
}
}
private void stopDraw() {
if (this.handler != null) {
this.handler.quit();
this.handler = null;
}
if (this.mHandlerThread != null) {
HandlerThread handlerThread = this.mHandlerThread;
this.mHandlerThread = null;
try {
handlerThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
handlerThread.quit();
}
}
private void stopDraw() {
DrawHandler handler = this.handler;
this.handler = null;
unlockCanvasAndPost();
if (handler != null) {
handler.quit();
}
if (this.mHandlerThread != null) {
HandlerThread handlerThread = this.mHandlerThread;
this.mHandlerThread = null;
try {
handlerThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
handlerThread.quit();
}
}
private void stopDraw() {
if (this.handler != null) {
this.handler.quit();
this.handler = null;
}
if (this.mHandlerThread != null) {
HandlerThread handlerThread = this.mHandlerThread;
this.mHandlerThread = null;
try {
handlerThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
handlerThread.quit();
}
}
private void stopDraw() {
if (handler != null) {
handler.quit();
handler = null;
}
if (mHandlerThread != null) {
HandlerThread handlerThread = this.mHandlerThread;
mHandlerThread = null;
try {
handlerThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
handlerThread.quit();
}
}
/**
* Helper method to {@link #runService(Context, Intent)}
* Starts the wait watcher thread if not already started.
* Halting condition depends on the state of {@link #handlerThread}
* @param context
*/
private static synchronized void init(final Context context) {
final HandlerThread waitingThread = new HandlerThread("service_startup_watcher");
waitingThread.start();
final Handler handler = new Handler(waitingThread.getLooper());
final NotificationManager notificationManager = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
final NotificationCompat.Builder mBuilder=new NotificationCompat.Builder(context);
mBuilder.setContentTitle(context.getString(R.string.waiting_title));
mBuilder.setContentText(context.getString(R.string.waiting_content));
mBuilder.setAutoCancel(false);
mBuilder.setSmallIcon(R.drawable.ic_all_inclusive_white_36dp);
mBuilder.setProgress(0, 0, true);
Runnable runnable = new Runnable() {
@Override
public void run() {
if (handlerThread==null || !handlerThread.isAlive()) {
// service is been finished, let's start this one
// pop recent intent from pendingIntents
final int size = pendingIntents.size();
if (size > 0) {
context.startService(pendingIntents.remove(size - 1));
}
if (pendingIntents.size()==0) {
// we've done all the work, free up resources (if not already killed by system)
notificationManager.cancel(ID_NOTIFICATION_WAIT);
handler.removeCallbacks(this);
waitingThread.quit();
return;
} else {
notificationManager.notify(ID_NOTIFICATION_WAIT, mBuilder.build());
}
}
handler.postDelayed(this, 1000);
}
};
handler.postDelayed(runnable, 0);
}
@Test
public void testSetRootAsyncWithCompatibleMeasureDuringLayout() throws InterruptedException {
Component oldComponent =
SimpleMountSpecTester.create(mContext).widthPx(100).heightPx(100).color(1234).build();
ComponentTree componentTree = ComponentTree.create(mContext, oldComponent).build();
componentTree.setLithoView(new LithoView(mContext));
int widthSpec1 = SizeSpec.makeSizeSpec(1000, SizeSpec.EXACTLY);
int heightSpec1 = SizeSpec.makeSizeSpec(1000, SizeSpec.AT_MOST);
int widthSpec2 = SizeSpec.makeSizeSpec(1000, SizeSpec.EXACTLY);
int heightSpec2 = SizeSpec.makeSizeSpec(500, SizeSpec.AT_MOST);
componentTree.attach();
componentTree.measure(widthSpec1, heightSpec1, new int[2], false);
final TestDrawableComponent.BlockInPrepareComponentListener blockInPrepare =
new TestDrawableComponent.BlockInPrepareComponentListener();
blockInPrepare.setDoNotBlockOnThisThread();
TestDrawableComponent newComponent =
TestDrawableComponent.create(mContext).widthPx(100).heightPx(100).color(1234).build();
newComponent.setTestComponentListener(blockInPrepare);
componentTree.setRootAsync(newComponent);
final TimeOutSemaphore asyncLayoutFinish =
runOnBackgroundThread(
new Runnable() {
@Override
public void run() {
mLayoutThreadShadowLooper.runToEndOfTasks();
}
});
blockInPrepare.awaitPrepareStart();
// At this point, the Layout thread is blocked in prepare (waiting for unblockAsyncPrepare) and
// will have already captured the "bad" specs, but not completed its layout.
// This is a bit of a hack: Robolectric's ShadowLegacyLooper implementation is synchronized
// on runToEndOfTasks and post(). Since we are simulating being in the middle of calculating a
// layout, this means that we can't post() to the same Handler (as we will try to do in measure)
// The "fix" here is to update the layout thread to a new handler/looper that can be controlled
// separately.
HandlerThread newHandlerThread = createAndStartNewHandlerThread();
componentTree.updateLayoutThreadHandler(
new LithoHandler.DefaultLithoHandler(newHandlerThread.getLooper()));
ShadowLooper newThreadLooper = Shadows.shadowOf(newHandlerThread.getLooper());
assertThat(componentTree.hasCompatibleLayout(widthSpec2, heightSpec2))
.describedAs("Asserting test setup, second set of specs should be compatible already.")
.isTrue();
componentTree.measure(widthSpec2, heightSpec2, new int[2], false);
assertThat(componentTree.getRoot()).isEqualTo(newComponent);
assertThat(componentTree.hasCompatibleLayout(widthSpec2, heightSpec2)).isTrue();
assertThat(componentTree.getMainThreadLayoutState().isForComponentId(newComponent.getId()))
.isTrue()
.withFailMessage(
"The main thread should calculate a new layout synchronously because the async layout will not have compatible size specs");
assertThat(componentTree.getMainThreadLayoutState().getHeight()).isEqualTo(100);
// Finally, let the async layout finish and make sure it doesn't replace the layout from measure
blockInPrepare.allowPrepareToComplete();
asyncLayoutFinish.acquire();
newComponent.setTestComponentListener(null);
newThreadLooper.runToEndOfTasks();
mLayoutThreadShadowLooper.runToEndOfTasks();
ShadowLooper.runUiThreadTasks();
assertThat(componentTree.getRoot()).isEqualTo(newComponent);
assertThat(componentTree.hasCompatibleLayout(widthSpec2, heightSpec2)).isTrue();
assertThat(componentTree.getMainThreadLayoutState().isForComponentId(newComponent.getId()))
.isTrue();
assertThat(componentTree.getMainThreadLayoutState().getHeight()).isEqualTo(100);
assertThat(mLithoStatsRule.getComponentCalculateLayoutCount())
.describedAs(
"We expect one initial layout, the async layout (thrown away), and a final layout after measure.")
.isEqualTo(3);
newHandlerThread.quit();
}
@Test
public void
testSetRootAsyncWithIncompatibleMeasureButCompatibleMeasureForExistingLayoutDuringLayout()
throws InterruptedException {
Component oldComponent =
SimpleMountSpecTester.create(mContext).widthPx(100).heightPx(100).color(1234).build();
ComponentTree componentTree = ComponentTree.create(mContext, oldComponent).build();
componentTree.setLithoView(new LithoView(mContext));
int widthSpec1 = SizeSpec.makeSizeSpec(1000, SizeSpec.EXACTLY);
int heightSpec1 = SizeSpec.makeSizeSpec(1000, SizeSpec.AT_MOST);
int widthSpec2 = SizeSpec.makeSizeSpec(1000, SizeSpec.EXACTLY);
int heightSpec2 = SizeSpec.makeSizeSpec(500, SizeSpec.AT_MOST);
componentTree.attach();
componentTree.measure(widthSpec1, heightSpec1, new int[2], false);
final TestDrawableComponent.BlockInPrepareComponentListener blockInPrepare =
new TestDrawableComponent.BlockInPrepareComponentListener();
blockInPrepare.setDoNotBlockOnThisThread();
TestDrawableComponent newComponent =
TestDrawableComponent.create(mContext).flexGrow(1).color(1234).build();
newComponent.setTestComponentListener(blockInPrepare);
componentTree.setRootAsync(newComponent);
final TimeOutSemaphore asyncLayoutFinish =
runOnBackgroundThread(
new Runnable() {
@Override
public void run() {
mLayoutThreadShadowLooper.runToEndOfTasks();
}
});
blockInPrepare.awaitPrepareStart();
// At this point, the Layout thread is blocked in prepare (waiting for unblockAsyncPrepare) and
// will have already captured the "bad" specs, but not completed its layout.
// This is a bit of a hack: Robolectric's ShadowLegacyLooper implementation is synchronized
// on runToEndOfTasks and post(). Since we are simulating being in the middle of calculating a
// layout, this means that we can't post() to the same Handler (as we will try to do in measure)
// The "fix" here is to update the layout thread to a new handler/looper that can be controlled
// separately.
HandlerThread newHandlerThread = createAndStartNewHandlerThread();
componentTree.updateLayoutThreadHandler(
new LithoHandler.DefaultLithoHandler(newHandlerThread.getLooper()));
ShadowLooper newThreadLooper = Shadows.shadowOf(newHandlerThread.getLooper());
assertThat(componentTree.hasCompatibleLayout(widthSpec2, heightSpec2))
.describedAs("Asserting test setup, second set of specs should be compatible already.")
.isTrue();
componentTree.measure(widthSpec2, heightSpec2, new int[2], false);
assertThat(componentTree.getRoot()).isEqualTo(newComponent);
assertThat(componentTree.hasCompatibleLayout(widthSpec2, heightSpec2)).isTrue();
assertThat(componentTree.getMainThreadLayoutState().isForComponentId(newComponent.getId()))
.isTrue()
.withFailMessage(
"The main thread should calculate a new layout synchronously because the async layout will not have compatible size specs");
assertThat(componentTree.getMainThreadLayoutState().getHeight()).isEqualTo(500);
// Finally, let the async layout finish and make sure it doesn't replace the layout from measure
blockInPrepare.allowPrepareToComplete();
asyncLayoutFinish.acquire();
newComponent.setTestComponentListener(null);
newThreadLooper.runToEndOfTasks();
mLayoutThreadShadowLooper.runToEndOfTasks();
ShadowLooper.runUiThreadTasks();
assertThat(componentTree.getRoot()).isEqualTo(newComponent);
assertThat(componentTree.hasCompatibleLayout(widthSpec2, heightSpec2)).isTrue();
assertThat(componentTree.getMainThreadLayoutState().isForComponentId(newComponent.getId()))
.isTrue();
assertThat(componentTree.getMainThreadLayoutState().getHeight()).isEqualTo(500);
assertThat(mLithoStatsRule.getComponentCalculateLayoutCount())
.describedAs(
"We expect one initial layout, the async layout (thrown away), and a final layout from measure.")
.isEqualTo(3);
newHandlerThread.quit();
}
@Override
public boolean quitSafely(HandlerThread thread) {
return thread.quit();
}
/**
* Called after all test classes are in place, ready to test
*/
protected void start() {
TestCaseCollector collector = getTestCaseCollector(this.getClass().getClassLoader());
try {
collector.addTestClasses(mTestClasses);
} catch (ClassNotFoundException e) {
// will be caught by uncaught handler
throw new RuntimeException(e.getMessage(), e);
}
if (mDebug) {
Debug.waitForDebugger();
}
mHandlerThread = new HandlerThread(HANDLER_THREAD_NAME);
mHandlerThread.setDaemon(true);
mHandlerThread.start();
UiAutomationShellWrapper automationWrapper = new UiAutomationShellWrapper();
automationWrapper.connect();
long startTime = SystemClock.uptimeMillis();
TestResult testRunResult = new TestResult();
ResultReporter resultPrinter;
String outputFormat = mParams.getString("outputFormat");
List<TestCase> testCases = collector.getTestCases();
Bundle testRunOutput = new Bundle();
if ("simple".equals(outputFormat)) {
resultPrinter = new SimpleResultPrinter(System.out, true);
} else {
resultPrinter = new WatcherResultPrinter(testCases.size());
}
try {
automationWrapper.setRunAsMonkey(mMonkey);
mUiDevice = MyUiDevice.getInstance();
UiAutomation uiAutomation = automationWrapper.getUiAutomation();
mUiDevice.initialize(new ShellUiAutomatorBridge(uiAutomation));
mUiDevice.setUiAutomation(uiAutomation);
String traceType = mParams.getString("traceOutputMode");
if (traceType != null) {
Tracer.Mode mode = Tracer.Mode.valueOf(Tracer.Mode.class, traceType);
if (mode == Tracer.Mode.FILE || mode == Tracer.Mode.ALL) {
String filename = mParams.getString("traceLogFilename");
if (filename == null) {
throw new RuntimeException("Name of log file not specified. " + "Please specify it using traceLogFilename parameter");
}
Tracer.getInstance().setOutputFilename(filename);
}
Tracer.getInstance().setOutputMode(mode);
}
// add test listeners
testRunResult.addListener(resultPrinter);
// add all custom listeners
for (TestListener listener : mTestListeners) {
testRunResult.addListener(listener);
}
// run tests for realz!
for (TestCase testCase : testCases) {
prepareTestCase(testCase);
testCase.run(testRunResult);
}
} catch (Throwable t) {
// catch all exceptions so a more verbose error message can be outputted
resultPrinter.printUnexpectedError(t);
} finally {
long runTime = SystemClock.uptimeMillis() - startTime;
resultPrinter.print(testRunResult, runTime, testRunOutput);
automationWrapper.disconnect();
automationWrapper.setRunAsMonkey(false);
mHandlerThread.quit();
}
}