private boolean canSplitLayoutOnCurrentThread() { return ThreadUtils.isMainThread() ? mainService != null : bgService != null; }
public static void assertMainThread() { if (!ComponentsConfiguration.IS_INTERNAL_BUILD || ComponentsConfiguration.isEndToEndTestRun) { return; } else if (!isMainThread()) { throw new IllegalStateException("This should run on the main thread."); } }
private static void focusRequestOnUiThread(Runnable runnable) { if (isMainThread()) { runnable.run(); } else { sMainThreadHandler.obtainMessage(MESSAGE_FOCUS_REQUEST, runnable).sendToTarget(); } }
private void postLoadingStateToFocusDispatch(final LoadingEvent.LoadingState loadingState) { if (isMainThread()) { setLoadingStateToFocusDispatch(loadingState); } else { sMainThreadHandler .obtainMessage( MESSAGE_FOCUS_DISPATCHER_LOADING_STATE_UPDATE, new Runnable() { @Override public void run() { setLoadingStateToFocusDispatch(loadingState); } }) .sendToTarget(); } }
/** * Transfer mBackgroundLayoutState to mMainThreadLayoutState. This will proxy * to the main thread if necessary. If the component/size-spec changes in the * meantime, then the transfer will be aborted. */ private void postBackgroundLayoutStateUpdated() { if (isMainThread()) { // We need to possibly update mMainThreadLayoutState. This call will // cause the host view to be invalidated and re-laid out, if necessary. backgroundLayoutStateUpdated(); } else { // If we aren't on the main thread, we send a message to the main thread // to invoke backgroundLayoutStateUpdated. sMainThreadHandler.obtainMessage(MESSAGE_WHAT_BACKGROUND_LAYOUT_STATE_UPDATED, this) .sendToTarget(); } }
@Override protected Component onCreateLayout(ComponentContext c) { syncLayouts.set(0, ThreadUtils.isMainThread() ? SYNC : ASYNC); lockRangeIsNotNull.countDown(); return null; } };
@Override protected Component onCreateLayout(ComponentContext c) { syncLayouts.set(finalI, ThreadUtils.isMainThread() ? SYNC : ASYNC); if (finalI == 1) { lockInitRangeLayout.countDown(); } if (finalI == 2) { lockTest.countDown(); } return null; } };
@Override protected Component onCreateLayout(ComponentContext c) { try { lockInitRangeLayout.await(5, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } syncLayouts.set(0, ThreadUtils.isMainThread() ? SYNC : ASYNC); lockTest.countDown(); return null; } };
@GuardedBy("this") private void maybeFillHScrollViewport() { if (!mHScrollAsyncMode || mHasFilledViewport) { return; } // Now that we're filling, all new batches should be inserted async to not drop frames mCommitPolicy = CommitPolicy.LAYOUT_BEFORE_INSERT; if (ThreadUtils.isMainThread()) { applyReadyBatches(); } else { if (!mComponentTreeHolders.isEmpty()) { fillListViewport(mMeasuredSize.width, mMeasuredSize.height, null); } else if (!mAsyncBatches.isEmpty()) { List<ComponentTreeHolder> insertsInFirstBatch = new ArrayList<>(); for (AsyncOperation operation : mAsyncBatches.getFirst().mOperations) { if (operation instanceof AsyncInsertOperation) { insertsInFirstBatch.add(((AsyncInsertOperation) operation).mHolder); } } computeLayoutsToFillListViewport( insertsInFirstBatch, 0, mMeasuredSize.width, mMeasuredSize.height, null); } mMainThreadHandler.post(mApplyReadyBatchesRunnable); } mHasFilledViewport = true; }
@Override public void onPrepare() { // We only want to block/wait for the component instance that is created async if (ThreadUtils.isMainThread()) { return; } onAsyncPrepareStart.countDown(); try { if (!unblockAsyncPrepare.await(5, TimeUnit.SECONDS)) { throw new RuntimeException("Timed out waiting for prepare to unblock!"); } } catch (InterruptedException e) { throw new RuntimeException(e); } } });
private void postNewChangeSets(Throwable tracedThrowable) { if (mUseBackgroundChangeSets) { applyChangeSetsToTargetBackgroundAllowed(); return; } if (isMainThread()) { try { applyChangeSetsToTargetUIThreadOnly(); } catch (IndexOutOfBoundsException e) { throw new RuntimeException(getDebugInfo(this) + e.getMessage(), e); } } else { sMainThreadHandler .obtainMessage( MESSAGE_WHAT_BACKGROUND_CHANGESET_STATE_UPDATED, new ThreadTracingRunnable(tracedThrowable) { @Override public void tracedRun(Throwable tracedThrowable) { final SectionTree tree = SectionTree.this; try { tree.applyChangeSetsToTargetUIThreadOnly(); } catch (IndexOutOfBoundsException e) { throw new RuntimeException(getDebugInfo(tree) + e.getMessage(), e); } } }) .sendToTarget(); } }
@Override protected Component onCreateLayout(ComponentContext c) { syncLayouts.set(finalI, ThreadUtils.isMainThread() ? SYNC : ASYNC); if (finalI == 1) { try { lockInitRangeFinishes1.await(5, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } lockTest.countDown(); } if (finalI == 2) { try { lockInitRangeFinishes2.await(5, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } lockTest.countDown(); } return null; } };
public void clearRefreshing() { SectionsRecyclerView sectionsRecyclerView = mSectionsRecyclerView; if (sectionsRecyclerView == null || !sectionsRecyclerView.isRefreshing()) { return; } if (ThreadUtils.isMainThread()) { sectionsRecyclerView.setRefreshing(false); return; } sectionsRecyclerView.removeCallbacks(mClearRefreshRunnable); sectionsRecyclerView.post(mClearRefreshRunnable); }
ThreadUtils.isMainThread() ? resolver.mainService : resolver.bgService;
if (isMainThread()) { maybeDispatchFocusRequests(); } else {
if (ThreadUtils.isMainThread()) { maybeAcquireStateAndReleaseTree(holder); } else {
/** * Called after all the change set operations (inserts, removes, etc.) in a batch have completed. * Async variant, may be called off the main thread. */ public void notifyChangeSetCompleteAsync( boolean isDataChanged, ChangeSetCompleteCallback changeSetCompleteCallback) { ComponentsSystrace.beginSection("notifyChangeSetCompleteAsync"); try { if (SectionsDebug.ENABLED) { Log.d(SectionsDebug.TAG, "(" + hashCode() + ") notifyChangeSetCompleteAsync"); } mHasAsyncOperations = true; assertSingleThreadForChangeSet(); closeCurrentBatch(isDataChanged, changeSetCompleteCallback); if (ThreadUtils.isMainThread()) { applyReadyBatches(); if (isDataChanged) { maybeUpdateRangeOrRemeasureForMutation(); } } else { // measure() will post this for us if (mIsMeasured.get()) { mMainThreadHandler.post(mApplyReadyBatchesRunnable); } } clearThreadForChangeSet(); } finally { ComponentsSystrace.endSection(); } }
@Test public void testSplitMainThreadLayouts() { SplitLayoutResolver.createForTag(splitTag, mMainConfig, mBgConfig, mEnabledComponent); SplitLayoutResolver resolver = SplitLayoutResolver.getForTag(splitTag); when(ThreadUtils.isMainThread()).thenReturn(true); Whitebox.setInternalState(resolver, "mainService", mainService); Whitebox.setInternalState(resolver, "bgService", bgService); ComponentTree tree = ComponentTree.create(mContext, mComponent).splitLayoutTag(splitTag).build(); tree.setRootAndSizeSpec( mComponent, makeSizeSpec(100, EXACTLY), makeSizeSpec(100, EXACTLY), new Size()); verify(mainService).submit(any(Runnable.class), eq(0)); verify(mainService).submit(any(Runnable.class), eq(1)); verify(mainService, never()).submit(any(Runnable.class), eq(2)); verify(bgService, never()).submit(any(Runnable.class), any()); }
@Test public void testSplitBgThreadLayouts() { SplitLayoutResolver.createForTag(splitTag, mMainConfig, mBgConfig, mEnabledComponent); SplitLayoutResolver resolver = SplitLayoutResolver.getForTag(splitTag); when(ThreadUtils.isMainThread()).thenReturn(false); Whitebox.setInternalState(resolver, "mainService", mainService); Whitebox.setInternalState(resolver, "bgService", bgService); final ComponentTree tree = ComponentTree.create(mContext, mComponent).splitLayoutTag(splitTag).build(); tree.setRootAndSizeSpecAsync( mComponent, makeSizeSpec(100, EXACTLY), makeSizeSpec(100, EXACTLY)); mLayoutThreadShadowLooper.runOneTask(); verify(bgService).submit(any(Runnable.class), eq(0)); verify(bgService).submit(any(Runnable.class), eq(1)); verify(bgService, never()).submit(any(Runnable.class), eq(2)); verify(mainService, never()).submit(any(Runnable.class), any()); }
@Test public void testOnlyMainEnabled() { SplitLayoutResolver.createForTag(splitTag, mMainConfig, null, mEnabledComponent); SplitLayoutResolver resolver = SplitLayoutResolver.getForTag(splitTag); when(ThreadUtils.isMainThread()).thenReturn(false); Whitebox.setInternalState(resolver, "mainService", mainService); final ComponentTree tree = ComponentTree.create(mContext, mComponent).splitLayoutTag(splitTag).build(); tree.setRootAndSizeSpecAsync( mComponent, makeSizeSpec(100, EXACTLY), makeSizeSpec(100, EXACTLY)); mLayoutThreadShadowLooper.runOneTask(); verify(bgService, never()).submit(any(Runnable.class), eq(0)); } }