儿童视图花费太多时间在屏幕上绘制

时间:2016-12-06 06:13:43

标签: android performance android-layout hierarchyviewer

我有Android布局设计,其中我有AppBar布局,其中包含Toolbar和另外一个LinearLayout设计,圈DrawableTextView 。这是相同的高度。因此,当我尝试获得ToolbarAppBar高度/宽度时,它仅返回0.

activity_main.xml中:          

    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?actionBarSize"
            android:background="@color/colorPrimary"
            app:layout_scrollFlags="enterAlways" />
       <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="?actionBarSize"
            android:layout_gravity="center_horizontal"
            android:background="@color/colorPrimary"
            android:orientation="horizontal"
            app:layout_scrollFlags="enterAlways">

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_gravity="center_horizontal"
                android:layout_marginLeft="2dp"
                android:layout_weight="1"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/marked_questions"
                    style="@style/textview_summary_omr_toolbar_count"
                    android:background="@drawable/bg_percentage_default"
                    android:text="18" />

                <TextView
                    style="@style/textview_heading_summary_omr_toolbar"
                    android:text="Marked" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_gravity="center_horizontal"
                android:layout_marginLeft="2dp"
                android:layout_weight="1"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/correct"
                    style="@style/textview_summary_omr_toolbar_count"
                    android:background="@drawable/bg_percentage_6"
                    android:text="18"

                    />

                <TextView
                    style="@style/textview_heading_summary_omr_toolbar"
                    android:text="Correct" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_gravity="center_horizontal"
                android:layout_marginLeft="2dp"
                android:layout_weight="1"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/wrong"
                    style="@style/textview_summary_omr_toolbar_count"
                    android:background="@drawable/bg_percentage_wrong"
                    android:text="18" />

                <TextView
                    style="@style/textview_heading_summary_omr_toolbar"
                    android:text="Wrong" />
            </LinearLayout>


            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_gravity="center_horizontal"
                android:layout_marginLeft="2dp"
                android:layout_weight="1"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/conflicts"
                    style="@style/textview_summary_omr_toolbar_count"
                    android:background="@drawable/bg_percentage_3"
                    android:text="0" />

                <TextView
                    style="@style/textview_heading_summary_omr_toolbar"
                    android:text="Conflicts" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_gravity="center_horizontal"
                android:layout_marginLeft="2dp"
                android:layout_weight="1"
                android:orientation="horizontal">

                <TextView
                    style="@style/textview_summary_omr_toolbar_count"
                    android:text="Score:"
                    android:textColor="@android:color/white" />

                <TextView
                    android:id="@+id/marks_scored"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_vertical"
                    android:gravity="center"
                    android:text="18/30"
                    android:textColor="@android:color/white"
                    android:textSize="18sp" />

            </LinearLayout>


        </LinearLayout>
    </android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>

MainActivity.java: 在这里,我正在初始化ToolbarAppBar并尝试在日志中打印两者的宽度和高度,这使我返回零。

public class MainActivity extends AppCompatActivity {
  private Toolbar toolbar;
  private AppBarLayout app_bar;
protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       app_bar = (AppBarLayout) findViewById(R.id.app_bar);
       toolbar = (Toolbar) findViewById(R.id.toolbar);
       logToolbarLayoutParams();

}
private void logToolbarLayoutParams() {
        Log.d(TAG,"Toolbar width/Height"+this.toolbar.getWidth()+"/"+this.toolbar.getHeight());
        Log.d(TAG,"App_bar width/height"+this.app_bar.getWidth()+"/"+this.app_bar.getHeight());

}

我也在stackoverflow中提到了这个问题。

final AppBarLayout app_bar = (AppBarLayout) findViewById(R.id.app_bar);
                ViewTreeObserver vto = app_bar.getViewTreeObserver();
                vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                        app_bar.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                        Log.d(TAG, "Global layout");
                        logToolbarLayoutParams();
            }
        });

如果我在MainActivity中添加以下代码,它会让我获得Toolbar的正确高度和宽度。从我之前提到的stackoverflow问题中,我开始知道,视图没有在屏幕上绘制,所以我必须等待。但我怀疑的是,我指定的设计并不复杂? 为什么它花了很多时间在屏幕上画画?我错过了什么吗?

我已经使用层次结构查看器找出了什么使得子布局加载缓慢。我发现我正在使用mulitple LinearLayout,其中单RelativeLayout可用于获得相同的结构。我已经改变了我的布局设计如下。 我仍然面临同样的问题。

已更新: activity_main.xml:

<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?actionBarSize"
            android:background="@color/colorPrimary"
            app:layout_scrollFlags="enterAlways" />
   <RelativeLayout
         android:id="@+id/summary_bottom_sheet"
         android:layout_width="match_parent"
         android:layout_height="?actionBarSize"
         android:layout_gravity="center_horizontal"
         android:background="@color/colorPrimary">


         <TextView
             android:id="@+id/marked_questions"
             style="@style/textview_summary_omr_toolbar_count"
             android:layout_alignParentLeft="true"
             android:layout_alignParentStart="true"
             android:background="@drawable/bg_percentage_default"
             android:text="18" />

         <TextView
             android:id="@+id/marked_textview"
             style="@style/textview_heading_summary_omr_toolbar"
             android:layout_toEndOf="@+id/marked_questions"
             android:layout_toRightOf="@+id/marked_questions"
             android:text="Marked" />


         <TextView
             android:id="@+id/correct"
             style="@style/textview_summary_omr_toolbar_count"
             android:layout_toEndOf="@+id/marked_textview"
             android:layout_toRightOf="@+id/marked_textview"
             android:background="@drawable/bg_percentage_6"
             android:text="18"

             />

         <TextView
             android:id="@+id/correct_textview"
             style="@style/textview_heading_summary_omr_toolbar"
             android:layout_toEndOf="@+id/correct"
             android:layout_toRightOf="@+id/correct"
             android:text="Correct" />


         <TextView
             android:id="@+id/wrong"
             style="@style/textview_summary_omr_toolbar_count"
             android:layout_toEndOf="@+id/correct_textview"
             android:layout_toRightOf="@+id/correct_textview"
             android:background="@drawable/bg_percentage_wrong"
             android:text="18" />

         <TextView
             android:id="@+id/wrong_textview"
             style="@style/textview_heading_summary_omr_toolbar"
             android:layout_toEndOf="@+id/wrong"
             android:layout_toRightOf="@+id/wrong"
             android:text="Wrong" />


         <TextView
             android:id="@+id/conflicts"
             style="@style/textview_summary_omr_toolbar_count"
             android:layout_toEndOf="@+id/wrong_textview"
             android:layout_toRightOf="@+id/wrong_textview"
             android:background="@drawable/bg_percentage_3"
             android:text="0" />

         <TextView
             android:id="@+id/conflicts_textview"
             style="@style/textview_heading_summary_omr_toolbar"
             android:layout_toEndOf="@+id/conflicts"
             android:layout_toRightOf="@+id/conflicts"
             android:text="Conflicts" />


         <TextView
             android:id="@+id/score_textview"
             style="@style/textview_summary_omr_toolbar_count"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_toEndOf="@+id/conflicts_textview"
             android:layout_toRightOf="@+id/conflicts_textview"
             android:background="@null"
             android:gravity="center"
             android:text="Score:"
             android:textColor="@android:color/white" />

         <TextView
             android:id="@+id/marks_scored"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_centerVertical="true"
             android:layout_gravity="center_vertical"
             android:layout_toEndOf="@+id/score_textview"
             android:layout_toRightOf="@+id/score_textview"
             android:gravity="center"
             android:text="18/30"
             android:textColor="@android:color/white"
             android:textSize="18sp" />
   </RelativeLayout>
 </android.support.design.widget.AppBarLayout>
 </android.support.design.widget.CoordinatorLayout>

以下是层次结构查看器Hierarchy_viewer我正在获取的图像

5 个答案:

答案 0 :(得分:3)

你在考虑这个错误。您的布局没有任何问题(因为它与您的问题有关)。要证明这一点,请完全更改布局并重试

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recyclerView);
    Log.d("SomeTag", "w: " + recyclerView.getWidth() + ", h: " + recyclerView.getHeight());
    Log.d("SomeTag", "mw: " + recyclerView.getMeasuredWidth() + ", mh: " + recyclerView.getMeasuredHeight());
}

仅包含1个孩子的视图的输出仍为

  

12-14 10:17:04.902 3004-3004 /? D / SomeTag:w:0,h:0

     

12-14 10:17:04.902 3004-3004 /? D / SomeTag:mw:0,mh:0

所以你的布局没有任何问题(除了你有一个用词不当。你调用方法logToolbarLayoutParams,但你根本没有访问布局参数。你试图在布局之前获取视图对象的属性传球已经发生。也许这是你的混乱)。所以你缺少的是对Android的布局系统,视图组和视图的理解。 Romain Guy在Devoxx上有一个关于如何构建自定义FlowLayout的非常酷的演讲。网站已关闭或视频被拉动但是here's the code in GitHub如果您查看onLayout方法,您可以看到ViewGroup遍历其所有子节点并调用child.layout()。在调用此方法之前,view.getWidth和view.getHeight方法将返回0.此操作系统在调度时调用此方法。所以基本上,即使在OS安排布局之前,您也试图立即访问宽度和高度。自己创建一个自定义视图组,添加一些断点,并试一试。

答案 1 :(得分:1)

toolbar.getWidth()会在测量布局之后告诉您视图的宽度
在给视图充气后,其宽度和高度始终为0,因为measure()layout()都没有出现过。

protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);
   toolbar = (Toolbar) findViewById(R.id.toolbar);

   // check after inflation -> will be 0
   logToolbarLayoutParams();
}

onGlobalLayout()会报告正确的数据,因为顾名思义 - onMeasure() onLayout()都已被调用。视图的尺寸是已知的。这意味着视图已被绘制onDraw()是第三步,最后步骤。

您的布局有多复杂或使用哪种视图也没有任何区别。在观点膨胀之后,测量和布局通过不会立即发生。

要获得并使用视图的正确尺寸,您有3个选项:

  1. 使用您已建议的ViewTreeObserver.OnGlobalLayoutListener#onGlobalLayout()
  2. 稍后检查尺寸,确定是否已绘制视图(例如,在用户互动时,在OnClickListener中)
  3. 转到自定义并创建自己的View。在那里,您有机会自己处理所有onMeasureonLayoutonDraw

答案 2 :(得分:0)

绘图视图需要相当长的时间,但我们可以通过删除嵌套布局来减少,并通过使用RelativeLayout或Constrain布局使视图层次结构变平。

找到透支。选择&#34;显示透支区域&#34;在Debug GPU中从设置中重写了开发人员选项。

在developer.android中研究thisthis关于优化布局主题的重要文章

答案 3 :(得分:-1)

我在同样的情况下解决了同样的问题。 ViewTreeObserver.OnGlobalLayoutListener()的所有解决方案看起来都很脏,对我不起作用。在当前屏幕上了解宽度和高度的最简单方法如下:

toolbar.post(new Runnable() {
        @Override
        public void run() {
            int headerWidth = toolbar.getWidth();
            int headerHeight = toolbar.getHeight();
            // do whatever you want ...
        }
    });

view.post()将在 结束于视图的消息队列 中添加您的代码,此时所有尺寸都已计算完毕。 imho,那显然也是可以理解的,然后是OnGlobalLayoutListener()。 希望它会对你有所帮助。

无论如何,这个解决方案仅仅是'#34;延迟获取大小&#34;,就像OnGlobalLayoutListener()一样。但这是系统的正常行为,在屏幕上绘制视图需要一些时间。最好的方法是不要期望计算的维度 - 而是应该协调.xml文件中的视图之间的所有关系。像WRAP_CONTENTMATCH_PARENT这样的属性是解决此类问题的最简单方法

答案 4 :(得分:-2)

您尝试在视图连接到屏幕之前获取视图的宽度和高度 您可以在onAttach方法

中创建自定义视图和所需的视图