安卓 - 声明式UI vs 编程式UI

18

有没有人看过或编译过比较在Android中使用声明式(XML)和程序式创建UI的基准测试?

虽然谷歌已经采取了一些措施来加速声明式方法,但在运行时仍然需要完成布局膨胀步骤。

您是否曾考虑过将UI从声明式更改为程序式,或因任何原因进行过转换?


与问题无关,但是为什么我的头像变成了一个粉色的独角兽马和一道彩虹!!这应该被禁止。是时候我自己设置一个了。 - Steve
1
有时候我的 Gravatar 显示错误的图片,为什么? - Josh Lee
@jleedev 太搞笑了...我喜欢。一定是愚人节玩笑,或者我中了“独角兽蠕虫”的毒。 - Steve
今天早上看到我的头像时,我必须承认有点困惑...不过这给StackOverflow增添了一些色彩 :) - seanhodges
3个回答

24

很少有布局膨胀是在运行时完成的。如LayoutInflator API文档所示:

出于性能原因,视图膨胀严重依赖于在构建时对XML文件进行的预处理。因此,目前不可能在运行时使用XmlPullParser覆盖普通的XML文件来使用LayoutInflater。

如果您查看source,您会发现许多视图都是根据它们的XML标记从哈希映射中获取的。

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

如果您需要动态生成布局,则最好通过编程方式创建它。如果您的视图仅花费了很长时间来膨胀,则应简化视图XML。


5
此外,这些XML文件被编译成二进制文件,我们可以解析这些文件比普通的XML文件快几个数量级。 - Romain Guy

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);
        }       
    }

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);
}

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接