美文网首页面试题
Android 布局优化

Android 布局优化

作者: 折剑游侠 | 来源:发表于2020-04-27 17:45 被阅读0次

    首先可以通过AS自带的工具查看布局层次

    Tools->Layout Inspector

    老生常谈的几个点

    • 减少布局层次,移除不必要的嵌套
    • 防止过度绘制(手机->开发者选项->调试GPU过度绘制)
    • 移除不必要的背景background
    • 使用merge、include、ViewStub标签
    • 使用ConstraintLayout优化复杂布局
    • 对于习惯使用RelativeLayout和LinearLayout布局的开发者而言,同层级优先使用LinearLayout,因为RelativeLayout至少会Measure两次;复杂布局优先使用RelativeLayout减少层级。

    merge标签通常配合include标签使用,作为被include的xml布局顶层。在include的时候直接将当前父View作为被include的xml顶层View,可以减少一层嵌套。

    ViewStub用来延迟加载,通常使用在网络请求结果有数据时展示的View,无数据则不加载,不浪费资源。

    activity_stub.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <ViewStub
            android:id="@+id/vs"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout="@layout/view_stub" />
    </RelativeLayout>
    

    view_stub.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <Button
            android:id="@+id/bt"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="ViewStub" />
    </RelativeLayout>
    

    使用

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_stub)
    
            val stub = findViewById<ViewStub>(R.id.vs)
            stub.inflate()
        }
    

    看看源码实现

    ViewStub构造方法

        public ViewStub(Context context, @LayoutRes int layoutResource) {
            this(context, null);
            mLayoutResource = layoutResource;
        }
    
        public ViewStub(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public ViewStub(Context context, AttributeSet attrs, int defStyleAttr) {
            this(context, attrs, defStyleAttr, 0);
        }
    
        public ViewStub(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context);
    
            final TypedArray a = context.obtainStyledAttributes(attrs,
                    R.styleable.ViewStub, defStyleAttr, defStyleRes);
            saveAttributeDataForStyleable(context, R.styleable.ViewStub, attrs, a, defStyleAttr,
                    defStyleRes);
            //inflatedId属性
            mInflatedId = a.getResourceId(R.styleable.ViewStub_inflatedId, NO_ID);
            //layout属性引入的xml
            mLayoutResource = a.getResourceId(R.styleable.ViewStub_layout, 0);
            mID = a.getResourceId(R.styleable.ViewStub_id, NO_ID);
            a.recycle();
    
            setVisibility(GONE);
            setWillNotDraw(true);
        }
    

    ViewStub.inflate

        public View inflate() {
            final ViewParent viewParent = getParent();
    
            if (viewParent != null && viewParent instanceof ViewGroup) {
                if (mLayoutResource != 0) {
                    //获取ViewStub父View
                    final ViewGroup parent = (ViewGroup) viewParent;
                    //解析xml成View树
                    final View view = inflateViewNoAdd(parent);
                    //添加View树到父View
                    replaceSelfWithView(view, parent);
    
                    mInflatedViewRef = new WeakReference<>(view);
                    if (mInflateListener != null) {
                        //回调
                        mInflateListener.onInflate(this, view);
                    }
    
                    return view;
                } else {
                    throw new IllegalArgumentException("ViewStub must have a valid layoutResource");
                }
            } else {
                throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent");
            }
        }
    

    ViewStub.inflateViewNoAdd

        private View inflateViewNoAdd(ViewGroup parent) {
            final LayoutInflater factory;
            if (mInflater != null) {
                factory = mInflater;
            } else {
                factory = LayoutInflater.from(mContext);
            }
            final View view = factory.inflate(mLayoutResource, parent, false);
    
            //inflatedId属性设置为View树的id
            if (mInflatedId != NO_ID) {
                view.setId(mInflatedId);
            }
            return view;
        }
    

    LayoutInflater解析ViewStub的layout属性下xml资源文件成View树

    ViewStub. replaceSelfWithView()

        private void replaceSelfWithView(View view, ViewGroup parent) {
            final int index = parent.indexOfChild(this);
            parent.removeViewInLayout(this);
    
            final ViewGroup.LayoutParams layoutParams = getLayoutParams();
            if (layoutParams != null) {
                parent.addView(view, index, layoutParams);
            } else {
                parent.addView(view, index);
            }
        }
    

    将View树添加到父View->parent

    ConstraintLayout

        implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    

    官方示例

    相关文章

      网友评论

        本文标题:Android 布局优化

        本文链接:https://www.haomeiwen.com/subject/mbhuwhtx.html