summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Joanne Chung <joannechung@google.com> 2021-02-24 00:10:10 +0800
committer Joanne Chung <joannechung@google.com> 2021-02-25 18:41:50 +0800
commit401900c9b20dfaff1a32f28071022c4438c50880 (patch)
tree489df63acee762e13427f60d0b83ec8535d32f9c
parentb8737dac2c10558a05a8df5e6882b110136d72f9 (diff)
Optimization: find views in single traversal.
The app will pass a list of views for Textview translation. Currently, we traverse the view tree for each requested view. That means we will traverse view tree many times. If the requested size of view list is large, it shoule be a performance issue. We refine to find views in sinslge traversal in this change. Use a sample app with many views and layouts and compare the time of two implementations. The average time of original solution is 300000 ~ 600000 ns. The new approach is 150000 ~ 300000 ns. Bug:178989965 Test: Write a sample app with many views and complicate structure, see bug for test sample screenshot. Compare the execute time of two implementation. Change-Id: I5a051740ad40e77ed4a54294368031eb82ab87ab
-rw-r--r--core/java/android/view/translation/UiTranslationController.java56
1 files changed, 45 insertions, 11 deletions
diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
index b49d3c004f44..b1e45bbcd875 100644
--- a/core/java/android/view/translation/UiTranslationController.java
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -32,6 +32,9 @@ import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewRootImpl;
+import android.view.WindowManagerGlobal;
import android.view.autofill.AutofillId;
import android.view.translation.UiTranslationManager.UiTranslationState;
@@ -194,24 +197,19 @@ public class UiTranslationController {
private void onUiTranslationStarted(Translator translator, List<AutofillId> views) {
synchronized (mLock) {
// Find Views collect the translation data
- // TODO(b/178084101): try to optimize, e.g. to this in a single traversal
- final int viewCounts = views.size();
final ArrayList<TranslationRequest> requests = new ArrayList<>();
- for (int i = 0; i < viewCounts; i++) {
- final AutofillId viewAutofillId = views.get(i);
- final View view = mActivity.findViewByAutofillIdTraversal(viewAutofillId);
- if (view == null) {
- Log.w(TAG, "Can not find the View for autofill id= " + viewAutofillId);
- continue;
- }
- mViews.put(viewAutofillId, new WeakReference<>(view));
+ final ArrayList<View> foundViews = new ArrayList<>();
+ findViewsTraversalByAutofillIds(views, foundViews);
+ for (int i = 0; i < foundViews.size(); i++) {
+ final View view = foundViews.get(i);
+ final int currentCount = i;
mActivity.runOnUiThread(() -> {
final TranslationRequest translationRequest = view.onCreateTranslationRequest();
if (translationRequest != null
&& translationRequest.getTranslationText().length() > 0) {
requests.add(translationRequest);
}
- if (requests.size() == viewCounts) {
+ if (currentCount == (foundViews.size() - 1)) {
Log.v(TAG, "onUiTranslationStarted: send " + requests.size() + " request.");
mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
UiTranslationController::sendTranslationRequest,
@@ -222,6 +220,42 @@ public class UiTranslationController {
}
}
+ private void findViewsTraversalByAutofillIds(List<AutofillId> sourceViewIds,
+ ArrayList<View> foundViews) {
+ final ArrayList<ViewRootImpl> roots =
+ WindowManagerGlobal.getInstance().getRootViews(mActivity.getActivityToken());
+ for (int rootNum = 0; rootNum < roots.size(); rootNum++) {
+ final View rootView = roots.get(rootNum).getView();
+ if (rootView instanceof ViewGroup) {
+ findViewsTraversalByAutofillIds((ViewGroup) rootView, sourceViewIds, foundViews);
+ } else {
+ addViewIfNeeded(sourceViewIds, rootView, foundViews);
+ }
+ }
+ }
+
+ private void findViewsTraversalByAutofillIds(ViewGroup viewGroup,
+ List<AutofillId> sourceViewIds, ArrayList<View> foundViews) {
+ final int childCount = viewGroup.getChildCount();
+ for (int i = 0; i < childCount; ++i) {
+ final View child = viewGroup.getChildAt(i);
+ if (child instanceof ViewGroup) {
+ findViewsTraversalByAutofillIds((ViewGroup) child, sourceViewIds, foundViews);
+ } else {
+ addViewIfNeeded(sourceViewIds, child, foundViews);
+ }
+ }
+ }
+
+ private void addViewIfNeeded(List<AutofillId> sourceViewIds, View view,
+ ArrayList<View> foundViews) {
+ final AutofillId autofillId = view.getAutofillId();
+ if (sourceViewIds.contains(autofillId)) {
+ mViews.put(autofillId, new WeakReference<>(view));
+ foundViews.add(view);
+ }
+ }
+
private void runForEachView(Consumer<View> action) {
synchronized (mLock) {
final ArrayMap<AutofillId, WeakReference<View>> views = new ArrayMap<>(mViews);