android - 为什么膨胀一个 Android 布局需要这么长时间?
问题描述
我在 Android 中有一个对话框。打开时有明显的延迟。这是我所做的调查:
使用 System.currentTime 的粗略计时,我的 onCreateDialog 方法在正常的一天需要 500-700 毫秒的好日子需要 150 毫秒。
我实现了自己的 LayoutInflator.Factory。我的工厂什么都不做。它只是返回 null 以让默认工厂完成工作。然而,它会写出自上次调用以来经过的时间。这样,我可以打印出布局 xml 中的每个标签需要多长时间才能膨胀。非常令人惊讶的是,每个元素充气大约需要 20-70 毫秒!
我分析了该应用程序。看来很多时间确实花在了视图的构造函数或 LayoutParams 上。
对于粗略的检查,我测量了使用 System.currentTime 在 TextView 上调用构造函数的时间。事实证明,在我强大的 Alienware PC 上的模拟器中,实例化一个 TextView 对象需要 20-70 毫秒!似乎有什么不对劲,它可能需要这么长时间。
作为参考,布局膨胀、测量和渲染之间存在差异。我现在只关心通货膨胀的表现。
以下是我如何实现 LayoutInflator.Factory 来进行测量:
LayoutInflater inflater = LayoutInflater.from(getActivity());
LayoutInflater inflater2 = inflater.cloneInContext(getActivity());
inflater2.setFactory(new LayoutInflater.Factory() {
long inner = System.currentTimeMillis();
@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
Log.d(LOG_TAG, "onCreateView: Called factory for " + name + " took " + (System.currentTimeMillis() - inner));
inner = System.currentTimeMillis();
return null;
}
});
这是输出:
Called factory for TextView took 34
Called factory for TextView took 30
Called factory for android.support.constraint.Guideline took 76
...
以下是我如何测量实例化 TextView 和 LayoutParams 对象的时间。
Log.d(LOG_TAG, "onCreateDialog: 10 " + (System.currentTimeMillis() - last)); last = System.currentTimeMillis();
new TextView(getActivity());
Log.d(LOG_TAG, "onCreateDialog: 11 " + (System.currentTimeMillis() - last)); last = System.currentTimeMillis();
new ConstraintLayout(getActivity().getApplicationContext());
Log.d(LOG_TAG, "onCreateDialog: 12 " + (System.currentTimeMillis() - last)); last = System.currentTimeMillis();
这是我的布局,但应用程序中的所有布局似乎都受到了缓慢的影响:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/remote_message_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/remote_dialog_message"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/building_name_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp"
android:textColor="#000"
android:textSize="32sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/remote_message_text_view"
tools:text="Bakery"/>
<ImageView
android:id="@+id/building_icon_image_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:contentDescription="@string/building_icon_content_description"
app:layout_constraintEnd_toEndOf="@+id/right_guide_line"
app:layout_constraintStart_toStartOf="@+id/left_guide_line"
app:layout_constraintTop_toBottomOf="@+id/building_name_text_view"
tools:src="@drawable/bakery"/>
<TextView
android:id="@+id/action_heading_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingEnd="8dp"
android:paddingStart="8dp"
android:paddingTop="8dp"
android:text="@string/actions_heading"
android:textAllCaps="true"
android:textColor="#000"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/building_icon_image_view"/>
<android.support.v7.widget.GridLayout
android:id="@+id/action_grid_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingEnd="8dp"
android:paddingStart="8dp"
app:columnCount="3"
app:layout_constraintTop_toBottomOf="@+id/action_heading_text_view"
tools:layout_height="100dp"/>
<TextView
android:id="@+id/production_rules_heading_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingEnd="8dp"
android:paddingStart="8dp"
android:paddingTop="8dp"
android:text="@string/production_rules_heading"
android:textAllCaps="true"
android:textColor="#000"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/action_grid_layout"/>
<TextView
android:id="@+id/production_rules_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingEnd="8dp"
android:paddingStart="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/production_rules_heading_text_view"
tools:text="1 flour creates 1 bread."/>
<TextView
android:id="@+id/production_speed_heading_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingEnd="8dp"
android:paddingStart="8dp"
android:paddingTop="8dp"
android:text="@string/production_speed_heading"
android:textAllCaps="true"
android:textColor="#000"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/production_rules_text_view"/>
<TextView
android:id="@+id/production_speed_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingEnd="8dp"
android:paddingStart="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/production_speed_heading_text_view"
tools:text="1 peasant produces 1 unit per 60 minutes.\n(Add a peasant to cut the time to 30 minutes.)"/>
<TextView
android:id="@+id/countdown_heading_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingEnd="8dp"
android:paddingStart="8dp"
android:paddingTop="8dp"
android:text="@string/next_unit_count_down_heading"
android:textAllCaps="true"
android:textColor="#000"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/production_speed_text_view"/>
<TextView
android:id="@+id/countdown_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp"
android:textColor="#000"
android:textSize="32sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/countdown_heading_text_view"
tools:text="24 : 60 : 60"/>
<android.support.constraint.Guideline
android:id="@+id/left_guide_line"
android:layout_width="0dp"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_constraintGuide_begin="10dp"
app:layout_constraintGuide_percent=".33"/>
<android.support.constraint.Guideline
android:id="@+id/right_guide_line"
android:layout_width="0dp"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_constraintGuide_percent=".66"/>
</android.support.constraint.ConstraintLayout>
为什么膨胀布局如此缓慢。我怎样才能加快速度?
解决方案
创建视图只是 LayoutInflater 所做工作的一小部分。你没有初始化它们,你没有将它们添加到它们的父级,你没有在它们上设置属性,你没有创建 LayoutParams,你没有进行布局或测量传递。你甚至没有解析 xml。当你做 10% 的工作时,它需要 10% 的时间。你的比较完全没用。
推荐阅读
- c++ - 是否需要自定义分配器来管理 std::map 使用的所有内存?
- amazon-web-services - AWS Lambda Post、Delete、Put 请求在 Node js 中
- objective-c - XCUITests 检查 Deeplink / Universal 链接和 webview 加载 url
- pyspark - 在 Hive 或 Pyspark 中查询以获取每个星期日和星期六的日期
- wordpress - 即使在使用 FutureBuilder Flutter 之后也是“X”的实例
- sql - 哪种方式删除sql中的重复行更快?
- asp.net-core - 具有 IdentityServer4 和 Identity 的 Asp.Net 核心 Web 应用程序
- security - Clarification regarding SOC-2 compliance in multiple locations
- python - 我怎样才能使这个功能更干净?
- python - 如何正确抓取网站并从网站获取所有 td 文本