본문 바로가기
프로그래밍 놀이터/안드로이드, Java

[Android/안드로이드] Android Layout Tricks #3 : Optimize by merging.

by 돼지왕 왕돼지 2012. 4. 17.
반응형




안녕하세요 돼지왕왕돼지입니다.

오늘은 "Android Layout Tricks #2 : Optimize by merging." 주제로 이야기하고자 합니다.

이 글은  http://android-developers.blogspot.com/2009/03/android-layout-tricks-3-optimize-by.html 를 의역한 글입니다.

Android Layout Tricks #3 : Optimize by merging.

<merge /> 는 view tree 의 level 을 줄이는 최적화를 위해 사용되는 tag 입니다. 예제를 보는 것이 이해를 하기가 빠르겠군요. 다음의 xml layout 은 image 와 그 제목을 표시하고 있습니다. ImageVIew 와 TextView 를 사용합니다.


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent">


    <ImageView  

        android:layout_width="fill_parent" 

        android:layout_height="fill_parent" 

        android:scaleType="center"

        android:src="@drawable/golden_gate" />

    

    <TextView

        android:layout_width="wrap_content" 

        android:layout_height="wrap_content" 

        android:layout_marginBottom="20dip"

        android:layout_gravity="center_horizontal|bottom"

        android:padding="12dip"

        android:background="#AA000000"

        android:textColor="#ffffffff"

        android:text="Golden Gate" />


</FrameLayout>


우리가 원하는 대로 그려지고, 이상이 없어 보입니다.



흥미롭게도, HierarchyViewer 의 결과를 보면 FrameLayout 이 쓸데 없이 2번 사용된 것을 볼 수 있습니다.



우리가 사용한 FrameLayout 이 그 부모와 같이 fill_parent 를 사용했다는 점과, background를 설정하지도 않고, 추가 padding 이나 gravity 등을 사용하지 않았다는 점에서 완전히 동일하므로 FrameLayout 을 2번 정의하는 것은 완벽한 낭비입니다. 특별한 이유 없이 UI 의 복잡도만 올려놓은 셈이죠. 하지만 우리가 어떻게 우리 예제 XML 에서 FrameLayout 을 제거할 수 있을까요? XML document 는 root tag 를 필요로 하고, XML layout 이 보통 root tag 로 오는데 말이죠.


이곳이 바로 <merge /> 가 사용될 곳입니다. LayoutInflater 가 이 merge 태그를 만나면, <merge /> 의 children 들을 <merge /> 의 parent 에 붙여버립니다. 햇갈리나요? 우리가 이미 기술한 XML 을 merge 태그를 사용하여 다시 기술해보겠습니다.


<merge xmlns:android="http://schemas.android.com/apk/res/android">


    <ImageView  

        android:layout_width="fill_parent" 

        android:layout_height="fill_parent" 

        android:scaleType="center"

        android:src="@drawable/golden_gate" />

    

    <TextView

        android:layout_width="wrap_content" 

        android:layout_height="wrap_content" 

        android:layout_marginBottom="20dip"

        android:layout_gravity="center_horizontal|bottom"

        android:padding="12dip"

        android:background="#AA000000"

        android:textColor="#ffffffff"

        android:text="Golden Gate" />


</merge>


이 새로운 xml 로 TextView 와 ImageView 는 바로 top-level FrameLayout 에 붙어버립니다.겉보기에는 같지만, view hierarchy 를 보면 더 간단해졌습니다.



여기서 <merge /> 태그를 사용한 것은 activity 의 기본 view group 이 FrameLayout 이며, 해당 xml 에서 사용했던 parent 가 다른 속성이 없는 FrameLayout 이었기 때문에 사용 가능했습니다. 만약 XML 에서 root layout으로 LinearLayout 을 사용했다면, 이 merge 를 사용할 수 없었겠죠. <merge /> 태그는 <include /> 태그와 함께 사용되어 최적의 효과를 내곤 합니다. 아래의 OKCancelBar 예제를 통해서 어떻게 두 태그가 협동하는지 함께 보겠습니다. 이 예제는 ImageView 가 있고, 그 위에 custom view 가 보여집니다.


<merge

    xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:okCancelBar="http://schemas.android.com/apk/res/com.example.android.merge">


    <ImageView  

        android:layout_width="fill_parent" 

        android:layout_height="fill_parent" 

        android:scaleType="center"

        android:src="@drawable/golden_gate" />

    

    <com.example.android.merge.OkCancelBar

        android:layout_width="fill_parent" 

        android:layout_height="wrap_content" 

        android:layout_gravity="bottom"

        android:paddingTop="8dip"

        android:gravity="center_horizontal"

        android:background="#AA000000"

        okCancelBar:okLabel="Save"

        okCancelBar:cancelLabel="Don't save" />


</merge>



OKCancelBar 는 매우 간단한 코드입니다. 2개의 버튼이 external XML 로 정의되어 있고, LayoutInflate 를 통해 load 됩니다. 


public class OkCancelBar extends LinearLayout {

    public OkCancelBar(Context context, AttributeSet attrs) {

        super(context, attrs);

        setOrientation(HORIZONTAL);

        setGravity(Gravity.CENTER);

        setWeightSum(1.0f);

        

        LayoutInflater.from(context).inflate(R.layout.okcancelbar, this, true);

        

        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.OkCancelBar, 0, 0);

        

        String text = array.getString(R.styleable.OkCancelBar_okLabel);

        if (text == null) text = "Ok";

        ((Button) findViewById(R.id.okcancelbar_ok)).setText(text);

        

        text = array.getString(R.styleable.OkCancelBar_cancelLabel);

        if (text == null) text = "Cancel";

        ((Button) findViewById(R.id.okcancelbar_cancel)).setText(text);

        

        array.recycle();

    }

}


2개의 버튼은 다음 XML 에 정의되어 있습니다. 


<merge xmlns:android="http://schemas.android.com/apk/res/android">

    <include

        layout="@layout/okcancelbar_button"

        android:id="@+id/okcancelbar_ok" />

        

    <include

        layout="@layout/okcancelbar_button"

        android:id="@+id/okcancelbar_cancel" />

</merge>


이런식으로 merge 와 include 를 사용하면, custom view 를 만들고 관리하기가 매우 쉽습니다.



<merge /> tag 는 매우 유용하며 당신의 코드를 기적처럼 만들 것입니다. 하지만 다음과 같은 제약사항이 있지요.


- <merge /> 는 root tag 로밖에 사용될 수 없습니다.
 

- inflate 를 할 때 <merge /> 를 만나게 되면, 당신은 "반드시" parent ViewGroup 을 명시해줘야 하고, attachToRoot 를 true 로 set 해주어야 합니다. ( inflate() 함수를 참조하세요 )



도움이 되셨다면 손가락 꾸욱~




 
반응형

댓글