Android layout Inflate 性能浅析

本文从三个测试方法测试 android 的 LayoutInflater.inflate 函数的性能。先上代码;

以下的时间的单位都是ns(纳秒)

package com.chillingvan.samplecode.xml;import android.app.Activity;import android.content.res.XmlResourceParser;import android.os.Bundle;import android.util.Log;import android.view.LayoutInflater;import android.widget.Toast;import com.chillingvan.samplecode.R;public class XmlActivity extends Activity {    private static final String TAG = "XmlActivity";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_xml);        testInflatePerformance();        testInflateWithXmlParserPerformance();        testFindViewTime();    }    private void testInflatePerformance() {        long initTime = System.nanoTime();        int times = 50;        for (int i = 0; i < times; i++) {            long eachInitTime = System.nanoTime();            LayoutInflater.from(this).inflate(R.layout.activity_xml, null);            Log.d(TAG, "each parser time cost=" + (System.nanoTime() - eachInitTime ));        }        long timeCost = System.nanoTime() - initTime;        String log = String.format("testInflatePerformance: %d times time cost=%d ns", times, timeCost);        Log.d(TAG, log);        Toast.makeText(XmlActivity.this, log, Toast.LENGTH_SHORT).show();    }    private void testInflateWithXmlParserPerformance() {        long initTime = System.nanoTime();        // can only be setted to 1 because the parser cannot be reused.        // But the parser creating does not cost time..        // Because the parse time is the main part of the cost.        int times = 1;        XmlResourceParser xmlResourceParser = getResources().getLayout(R.layout.activity_xml);        for (int i = 0; i < times; i++) {            long eachInitTime = System.nanoTime();            LayoutInflater.from(this).inflate(xmlResourceParser, null);            Log.d(TAG, String.format("each parser time cost=%d ns",(System.nanoTime() - eachInitTime )));        }        long timeCost = System.nanoTime() - initTime;        String log = String.format("testInflateWithXmlParserPerformance: %d times time cost=%d ns", times, timeCost);        Log.d(TAG, log);        Toast.makeText(XmlActivity.this, log, Toast.LENGTH_SHORT).show();    }    private void testFindViewTime() {        long initTime = System.nanoTime();        int times = 40;        for (int i = 0; i < times; i++) {            long eachInitTime = System.nanoTime();            findViewById(R.id.xml_txt);            Log.d(TAG, String.format("each parser time cost=%d ns",(System.nanoTime() - eachInitTime )));        }        long timeCost = System.nanoTime() - initTime;        String log = String.format("testFindViewTime: %d times time cost=%d ns", times, timeCost);        Log.d(TAG, log);        Toast.makeText(XmlActivity.this, log, Toast.LENGTH_SHORT).show();    }}

来看第一个inflate(int res, ViewGroup)方法的测试性能:

    private void testInflatePerformance() {        long initTime = System.nanoTime();        int times = 50;        for (int i = 0; i < times; i++) {            long eachInitTime = System.nanoTime();            LayoutInflater.from(this).inflate(R.layout.activity_xml, null);            Log.d(TAG, "each parser time cost=" + (System.nanoTime() - eachInitTime ));        }        long timeCost = System.nanoTime() - initTime;        String log = String.format("testInflatePerformance: %d times time cost=%d ns", times, timeCost);        Log.d(TAG, log);        Toast.makeText(XmlActivity.this, log, Toast.LENGTH_SHORT).show();    }

连续inflate同一个layout文件50次的结果如下:
Android layout Inflate 性能浅析_第1张图片

可以看到每次inflate所花费的时间大致相同,说明 android 不会对重复 inflate 的数据进行缓存。

第二个方法:

    private void testInflateWithXmlParserPerformance() {        long initTime = System.nanoTime();        // can only be setted to 1 because the parser cannot be reused.        // But the parser creating does not cost time..        // Because the parse time is the main part of the cost.        int times = 1;        XmlResourceParser xmlResourceParser = getResources().getLayout(R.layout.activity_xml);        for (int i = 0; i < times; i++) {            long eachInitTime = System.nanoTime();            LayoutInflater.from(this).inflate(xmlResourceParser, null);            Log.d(TAG, String.format("each find view time cost=%d ns",(System.nanoTime() - eachInitTime )));        }        long timeCost = System.nanoTime() - initTime;        String log = String.format("testInflateWithXmlParserPerformance: %d times time cost=%d ns", times, timeCost);        Log.d(TAG, log);        Toast.makeText(XmlActivity.this, log, Toast.LENGTH_SHORT).show();    }

inflate((XmlPullParser parser, ViewGroup root))这个方法传给inflate的参数是一个 XmlResourceParser。 原本是用来测试性能的,但是实际上测不了,因为获取到的parser只能用来解析一次,再调用一次就会报错。
inflate((XmlPullParser parser, ViewGroup root))其实是inflate (int resource, ViewGroup root)内部使用的方法,可以在源码上找到相应细节。
结果:

可以看到和第一个方法差别不大,也就是说Inflate的消耗时间注意不是由获取parser这一过程消耗的。

第三个方法:

private void testFindViewTime() {
long initTime = System.nanoTime();
int times = 40;
for (int i = 0; i < times; i++) {
long eachInitTime = System.nanoTime();
findViewById(R.id.xml_txt);
Log.d(TAG, String.format("each parser time cost=%d ns",(System.nanoTime() - eachInitTime )));
}
long timeCost = System.nanoTime() - initTime;
String log = String.format("testFindViewTime: %d times time cost=%d ns", times, timeCost);
Log.d(TAG, log);
Toast.makeText(XmlActivity.this, log, Toast.LENGTH_SHORT).show();
}

结果:
Android layout Inflate 性能浅析_第2张图片
这个是测试findView的性能,从结果可以看到findView耗费的时间不多。

那么inflate方法花费的时间主要花在哪一部分?

/**     * Recursive method used to descend down the xml hierarchy and instantiate     * views, instantiate their children, and then call onFinishInflate().     *     * @param inheritContext Whether the root view should be inflated in its     *            parent's context. This should be true when called inflating     *            child views recursively, or false otherwise.     */    void rInflate(XmlPullParser parser, View parent, final AttributeSet attrs,            boolean finishInflate, boolean inheritContext) throws XmlPullParserException,            IOException {        final int depth = parser.getDepth();        int type;        while (((type = parser.next()) != XmlPullParser.END_TAG ||                parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {            if (type != XmlPullParser.START_TAG) {                continue;            }            final String name = parser.getName();            if (TAG_REQUEST_FOCUS.equals(name)) {                parseRequestFocus(parser, parent);            } else if (TAG_TAG.equals(name)) {                parseViewTag(parser, parent, attrs);            } else if (TAG_INCLUDE.equals(name)) {                if (parser.getDepth() == 0) {                    throw new InflateException(" cannot be the root element");                }                parseInclude(parser, parent, attrs, inheritContext);            } else if (TAG_MERGE.equals(name)) {                throw new InflateException(" must be the root element");            } else {                final View view = createViewFromTag(parent, name, attrs, inheritContext);                final ViewGroup viewGroup = (ViewGroup) parent;                final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);                rInflate(parser, view, attrs, true, true);                viewGroup.addView(view, params);            }        }        if (finishInflate) parent.onFinishInflate();    }

猜测主要花费在rInflate方法这里,是一个递归方法。

最后,总结以下,inflate方法的性能瓶颈不在读磁盘,而在解析上,所以越view 层级复杂的layout越低性能。

更多相关文章

  1. android常用方法汇总-更新中
  2. Android结束进程的方法
  3. Android 比Timer更好方法
  4. Android中AppWidget使用方法
  5. Android 官方 Lambda支持方法
  6. android BroadcastReceiver遇到 java.lang.IllegalAccessExcepti
  7. Android 调用系统相机拍照保存以及调用系统相册的方法
  8. Android软键盘弹出时不把布局顶上去的解决方法

随机推荐

  1. 怎么正确绘画人物头发?动漫头发上色画法
  2. xp一体机文件永久删除怎么找到
  3. VMware Workstation Linux 安装及桥接网
  4. 盲盒源码h5|数码盲盒源码开发搭建
  5. 插画要怎么构图?插画绘制构图技巧
  6. 人体躯干到底怎么画?超基础的人体躯干画法
  7. 哪些人适合学HTML5?
  8. web前端必备技术有哪些?
  9. Linux安装MySQL(使用yum)
  10. Android(安卓)Studio error: Unable to s