Android - 声明性与程序化UI

时间:2010-04-01 14:10:48

标签: android performance

是否有人在Android中比较声明性(XML)与编程创建的UI的基准?

Google已采取措施加快声明性方法,但您仍然可以在运行时完成布局通胀步骤。

您是否曾因任何原因切换(或考虑)将UI从声明更改为程序化?

3 个答案:

答案 0 :(得分:23)

在运行时很少完成布局膨胀。正如LayoutInflator API docs中所暗示的那样:

  

出于性能原因,请查看   通货膨胀严重依赖   预处理XML文件   在构建时完成。因此它是   目前无法使用   带有XmlPullParser的LayoutInflater   在运行时通过纯XML文件

如果您查看source,许多视图都会根据其XML标记从哈希映射中提取。

在回答你是否对inflater进行基准测试的问题时,我不得不说。就个人而言,我发现在Android中对应用程序的布局inflater进行基准测试的想法相当于在Firefox中为您的网站对DOM解析器进行基准测试。我不认为这个练习毫无意义,但你应该有一个比“我的活动布局对于inflater来说太复杂”更好的理由......

如果您需要动态生成的布局,最好以编程方式创建它。如果您的视图需要花费很长时间才能充气,那么您应该简化视图XML。

答案 1 :(得分:3)

我开发了这个类来预先扩充视图池并在每次需要时重用它。我在更新UI时获得了几秒钟的性能,这令人印象深刻。

我的Logcat说:

updating UI inflating on demand >> 2136mS
updating UI reusing from pool >> 937mS

这是我的课,只是不介意我笨拙的Java编码风格,我是一名C ++嵌入式程序员。

import java.util.ArrayList;
import java.util.List;
import android.view.LayoutInflater;
import android.view.View;

    public class ViewPool {
        private List<View> mViews;
        private LayoutInflater mInf;
        private int mIdx;
        private int mResource;

        /**
         * Constructor, gives Inflater and resource ID to inflate
         * @param mInf Layout inflater
         * @param rID  Resource ID of view to inflate
         * @para number number of views that must inflate on first initialization
         */
        public ViewPool(LayoutInflater mInf, int rID, int number) {
            super();

            int idx;
            mViews = new ArrayList<View>();
            this.mInf = mInf;
            mResource = rID;
            mIdx=0; // index of first used item

            for(idx=0; idx<number;++idx)
            {
                mViews.add((View)mInf.inflate(mResource, null));
            }

        }

        /**
         * Start from first item of pool
         */
        public void Reset()
        {
            mIdx=0;
        }

        /**
         * Get a view from pool, if no more views on pool, inflate more 
         * @return
         */
        public View GetView()
        {
            View retval;

            retval = mViews.get(mIdx);
            ++mIdx;

            if(mIdx == mViews.size()) // no more views in pool??
                mViews.add((View)mInf.inflate(mResource, null)); // inflate more

            return(retval);
        }       
    }

答案 2 :(得分:3)

我对此做了一些非常非正式/黑客的测试,并发现采用程序化的方法,虽然不太好用,但在总时间的三分之一到一半之间剃光了。该测试仅在三星7“Galaxy上运行,而不是在AVD上运行。

正如我所说,这是一个非常非正式/黑客的测试(正如你会在代码中看到的那样),在非常有限的情况下,你可以快速组合起来以满足自己的好奇心,而不是通常用于公共消费。

R.layout.ll和R.layout.tv是分别包含空白LinearLayouts和TextViews的简单布局文件。

如果您只是处理一些观点,我会坚持使用XML / inflaters,但对于数百种观点而言,如果速度是一个问题,您可能会考虑采用编程方法。

package com.inflatervscode;

import java.util.Calendar;
import android.app.Activity;
import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.TextView;

public class InflaterVSCodeActivity extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

// Generates a few nested LinearLayouts/TextViews, a number of
// times, and works out how many milliseconds this took.
@Override
public void onResume() {
    super.onResume();
    setContentView(R.layout.main);

    int num_repeats = 500; // Change this to however many times you want to
                           // create a set of nested views.
    LinearLayout masterLL = (LinearLayout)findViewById(R.id.test);
    TextView results = (TextView)findViewById(R.id.results);

    Calendar c = Calendar.getInstance();
    long startTime = c.getTimeInMillis();

    for (int i=0;i<num_repeats;i++) {
            // Replace the section below with LinearLayout fll = new LinearLayout(this); etc
        LinearLayout fll = (LinearLayout)getLayoutInflater().inflate(R.layout.ll, null);
        LinearLayout sll = (LinearLayout)getLayoutInflater().inflate(R.layout.ll, null);
        LinearLayout tll = (LinearLayout)getLayoutInflater().inflate(R.layout.ll, null);
        TextView tv = (TextView)getLayoutInflater().inflate(R.layout.tv, null);

        tv.setText(i+"");
        tll.addView(tv);
        sll.addView(tll);
        fll.addView(sll);
        masterLL.addView(fll);
    }

    c = Calendar.getInstance();
    long endTime = c.getTimeInMillis();

    String tt = Long.toString((endTime-startTime));

    results.setText("Results for "+num_tests+" tests:\n\nStart:"+Long.toString(startTime)+"\nEnd  :"+Long.toString(endTime)+"\n\nDifference (ms):"+tt);
}

}