如何提高布局性能

时间:2011-02-21 04:23:47

标签: android performance layout

我有动态且非常大的内容,需要在用户交互中填充(点击下一页/上一页)。 动态内容以编程方式显示在myTableLayout上(参见下面的xml)。每次用户点击下一个/上一个 页面然后我调用myTableLayout.removeAllViews(),做一些事情并重新填充myTableLayout.addView()。 在内容较小的情况下,它会快速绘制,但如果填充大量内容,我会注意到两到三秒的延迟。

我已经看到了一个与我的功能相同的应用程序(也有相当大的内容),但它的分页速度非常快 甚至在低端设备上也是如此。

需要一些关于如何提高布局性能的建议。

感谢。

注意:Upper TableLayout用作标题(header),在它下面的LinearLayout是放置内容的地方。

<TableLayout
    android:layout_width="fill_parent"
    android:layout_height="45dip"
    android:stretchColumns="0,2"
    android:shrinkColumns="0,2"
    >
        <TableRow>
            <LinearLayout
                android:id="@+id/llLeft"
                android:layout_width="wrap_content"
                android:layout_height="fill_parent"
            >
                <TextView
                    android:id="@+id/tvLeft1"
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                />
            </LinearLayout>

            <LinearLayout
                android:id="@+id/llCenter"
                android:layout_width="wrap_content"
                android:layout_height="fill_parent"
            >
                <TextView
                    android:id="@+id/tvCenter1"
                    android:layout_width="wrap_content"
                    android:layout_height="fill_parent"
                />

                <TextView
                    android:id="@+id/tvCenter2"
                    android:layout_width="wrap_content"
                    android:layout_height="fill_parent"
                />
            </LinearLayout>

            <LinearLayout
                android:id="@+id/llRight"
                android:layout_width="wrap_content"
                android:layout_height="fill_parent"
            >
                <TextView
                    android:id="@+id/tvRight1"
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                />
            </LinearLayout>
    </TableRow>
</TableLayout>

<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
>
    <com.MyScrollView
        android:id="@+id/myScrollView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        >

        <TableLayout
            android:id="@+id/**myTableLayout**"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:shrinkColumns="1"
            android:stretchColumns="1"
            />

    </com.MyScrollView>
</LinearLayout>

以下是创建动态内容的代码。从内存中获取的内容(ArrayList)因此不应该是问题。

private void gotoPage() {
    myTableLayout.removeAllViews();
    GlobalVar g = GlobalVar.getInstance();
    ArrayList<String> arrScripts = g.getDatasMap().get(SCRIPT_INDEX);
    ArrayList<String> arrTrans = g.getTranslationMap().get(SCRIPT_INDEX);
    Log.i(APP_NAME, "finished preparing data");

    try {

        // Data Title
        tvCenter1.setText(arrScripts.get(0));
        tvCenter2.setText(" (" + SCRIPT_INDEX + ")");

        int countScripts = arrScripts.size();
        for(int i=1; i<countScripts; i++) {

            // Row Script
            TableRow trScript = new TableRow(this);
            trScript.setPadding(0, 5, 0, 0);
            TextView tvIndex = new TextView(this);
            tvIndex.setGravity(Gravity.CENTER);
            tvIndex.setWidth(40);
            tvIndex.setText("" + i);

            TextView tvScript = new TextView(this);
            tvScript.setGravity(Gravity.RIGHT);
            tvScript.setTypeface(g.getFontTypeFace());
            tvScript.setTextSize(FONT_SIZE);
            tvScript.setPadding(0, 0, 5, 0);
            tvScript.setText(arrScripts.get(i));

            trScript.addView(tvIndex);
            trScript.addView(tvScript);

            TableRow trTrans = null;

            if(IS_USE_TRANSLATION) {
                // Row Translation
                trTrans = new TableRow(this);

                TextView tvBlank = new TextView(this);
                tvBlank.setPadding(0, 0, 0, 5);
                TextView tvTrans = new TextView(this);
                tvTrans.setPadding(0, 0, 0, 5);
                tvTrans.setText(arrTrans.get(i));

                trTrans.addView(tvBlank);
                trTrans.addView(tvTrans);
            }

            // Place for line separator
            View vSep = new View(this);
            ViewGroup.LayoutParams p = new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
            p.height = 3;
            vSep.setLayoutParams(p);

            // Combine rows to table
            if(IS_USE_SCRIPT) myTableLayout.addView(trScript);
            if(IS_USE_TRANSLATION) myTableLayout.addView(trTrans);
            myTableLayout.addView(vSep);
        }
    } catch (Exception e) {
        Log.e(APP_NAME, e.getMessage());
    }
}

这是traceview result

5 个答案:

答案 0 :(得分:4)

我同意@ amplify91它可能来自生成内容,但您可能想要查看的其他内容之一是您正在使用的布局数量。基本思想是“越少越好”。你可以查看一些谷歌layout tricks

示例:我看到您的标题为tablelinearlayouttextviewRelative layout作为孩子的textviews无法解决这个问题吗?

您将保存一些视图,并在布局树中保存一些“深度”。

答案 1 :(得分:2)

简单地说,完全摆脱TableLayout和TableRow以及TextView!

如果从Eclipse收集分析数据,您将看到大部分CPU /实时时间都来自TabletLayout和TextView的addView()方法。来电!

每次我用自定义实现替换TableLayout和TextView时,都会带来巨大的性能提升!

TextView应由自定义ViewView替换为自定义View,TableLayout。

编辑:我根据自己的需要创建了一些自定义视图。简单地说,我用onDraw()和onMeasure()方法覆盖了View类:

在下面的代码中,画家在静态构造函数中创建一次,textBaseline和textHeight也是如此,因为我对所有这些自定义“文本”视图使用单一字体大小。

@Override
protected void onDraw(Canvas canvas) 
{
    final int width = getWidth();
    final float size = painter.measureText(innerText);

    canvas.drawText(innerText, width - size - 5, textBaseline, painter);

    if (underline)
    {
        canvas.drawLine(0, canvas.getHeight() - 1, canvas.getWidth(), canvas.getHeight() - 1, painter);
    }
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
{
    int w = MeasureSpec.getSize(widthMeasureSpec);
    int h = MeasureSpec.getSize(heightMeasureSpec);

    if (innerText != null && painter != null)
    {
        switch (MeasureSpec.getMode(widthMeasureSpec))
        {
            case MeasureSpec.EXACTLY:
                break;
            case MeasureSpec.AT_MOST:
            case MeasureSpec.UNSPECIFIED:
                w = (int)( (painter.measureText(innerText) + 5) );
                break;
        }
    }
    switch (MeasureSpec.getMode(heightMeasureSpec))
    {
        case MeasureSpec.EXACTLY:
            break;
        case MeasureSpec.AT_MOST:
        case MeasureSpec.UNSPECIFIED:
            h = (int)( textHeight );
            break;
    }

    setMeasuredDimension(w, h);
}

答案 2 :(得分:1)

我认为您应该通过Debug.startMethodTracing("xx")Debug.stopMethodTracing()来调用您的代码,然后使用traceview来了解正在发生的事情。其他一切都只是猜测。

答案 3 :(得分:0)

我想说延迟不是从XML构建布局,而是从生成动态内容。它是什么类型的内容?你可以发布一些代码吗?如果您从网站访问它,您可能需要预先获取它。如果您在更改页面时创建,则可能是您创建它的方式。

答案 4 :(得分:0)

如果您要做的只是以格式良好的表格格式添加文本(所有列自动调整大小等),请不要使用TableLayout,只需使用java.util.Formatter之类的内容将文本格式化为桌子形状。这需要一些预先工作,比如计算每列的最大字符串长度,但最终导致大的性能提升,因为您基本上将视图使用量减少到单个TextView(将活动加载到几乎瞬间约为2秒)。 / p>

例如:

// Compute max string length of each column
for (Entry entry : entries) {
    if (entry.column1.length() > column1MaxLength) {
        column1MaxLength = entry.column1.length();
    }
    ...
    if (entry.columnN.length() > columnNMaxLength) {
        columnNMaxLength = entry.columnN.length();
    }
}

// Formatter internally stores output string in StringBuilder
Formatter formatter = new Formatter();

// Construct table header
formatter.format("%1$" + column1MaxLength + "s", "Column 1 Title");
...
formatter.format("%1$" + columnNMaxLength + "s", "Column N Title");

// Add each entry into table
for (Entry entry : entries) {
    formatter.format("%1$" + column1MaxLength + "s", entry.column1.value);
    ...
    formatter.format("%1$" + columnNMaxLength + "s", entry.columnN.value);
}

// Get string representing formatted table from Formatter and put into TextView
textView.setText(formatter.toString());