Android프로그래밍

[Android] 안드로이드 뷰 바인딩(View binding) 기초 & 예제 코드 총정리 : DataBinding은?

안드로이드스튜디오를 최신버전으로 업그레이드 후 신규 프로젝트를 생성하면 기존에 보지 못했던 코드들이 자동 생성되는 것을 확인할 수 있다.

안드로이드스튜디오 3.5 버전까지는 개발자들이 findViewById를 사용했었다. 그리고 개발자들은 Butter knife라는 라이브러리나 extension을 이용해서 불편함을 해결했다. 이 후 안드로이드스튜디오 3.6 버전에서 이를 대체할 수 있는 view binding이 나왔다.

View Binding 사용한 방법

private ActivityMainBinding viewBinding;
 
@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);

   viewBinding = ActivityMainBinding.inflate(getLayoutInflater());
   setContentView(viewBinding.getRoot());

   viewBinding.textView.setText(userProfile.name);

   viewBinding.btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "hello", Toast.LENGTH_SHORT).show();
            }
        });


   // 람다식 -> : JDK 1.8버전 이상에서 사용가능
   viewBinding.btn.setOnClickListener(v -> Toast.makeText(this, "hello", Toast.LENGTH_SHORT).show());


   //롱클릭 람다식 표기법
   viewBinding.btn.setOnLongClickListener( v-> {
            Toast.makeText(this, "hello", Toast.LENGTH_SHORT).show();
            return true;
        });
}

 inflate는 xml에 있는 뷰를 객체화해준다고 생각하면 될 것이다.

기존 findViewById 방법

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

   setContentView(R.layout.activity_main)
   TextView textView = findViewById(R.id.text_view);
   textView.setText("Hello");
}


바인딩 클래스 명명 규칙(자동)

View Binding은 안드로이드 아키텍쳐 구성요소 중 하나로 뷰와 상호작용 하는 코드를 쉽게 작성할 수 있게 해준다. xml과 연결되는 바인딩 클래스가 자동으로 생성되고 그 클래스의 멤버로 xml의 ID를 가진 모든 뷰를 참조하는
참조 변수가 있다.

액티비티 레이아웃 파일명과 자동으로 만들어지는 바인딩 클래스명 예시는 다음과 같다.

//액티비티 레이아웃 파일명과 자동으로 만들어지는 바인딩 클래스명
activity_main.xml -> ActivityMainBinding
activity_second.xml -> ActivitySecondBinding

프레그먼트 레이아웃 파일명과 자동으로 만들어지는 바인딩 클래스명
fragment_home.xml -> FragmentHomeBinding
fragment_xxxx.xml -> FragmentXxxxBinding

//리사이클러뷰(아답터뷰)의 아이템 레이아웃 파일명과 자동으로 만들어지는 바인딩 클래스명
recycler_item.xml -> RecyclerItemBinding

findViewById에는 몇가지 문제점이 있는데, 실수로 없는 id를 사용하면 NULL 오류가 발생하고, 뷰의 타입을 잘못 적으면 오류가 발생하며, 코드가 많아진다.


뷰 바인딩 사용을 위한 기본 설정

build.gradle 파일에 아래와 같이 설정해주고, sync를 클릭하면 되는데, 안드로이드 스튜디오가 최신버전이라면 default 값으로 설정되어 있다.

// 안드로이드 스튜디오 4.0 이상
android {
	...
    buildFeatures {
        viewBinding true
    }
}

// 안드로이드 스튜디오 3.6 ~ 4.0
android {
    ...
    viewBinding {
        enabled true
    }
}


Fragment 뷰 바인딩 예제

public class HomeFragment extends Fragment {

    private FragmentHomeBinding binding;

    public View onCreateView(@NonNull LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {
        HomeViewModel homeViewModel =
                new ViewModelProvider(this).get(HomeViewModel.class);

        binding = FragmentHomeBinding.inflate(inflater, container, false);
        View root = binding.getRoot();


        final TextView baseDate = binding.baseDateText;
        baseDate.setText("");


//   final Button addbtn = binding.addBtn;
//   homeViewModel.getText().observe(getViewLifecycleOwner(), addbtn::setText);
        return root;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }
}

프래그먼트는 위와 사용되며, 차이점은 onDestroyView에서 binding에 null을 코딩해주어야 한다. 그 이유는 프래그먼트는 뷰보다 더 오래 살아남아 있기 때문이다.

Fragments outlive their views. Make sure you clean up any references to the binding class instance in the fragment's onDestroyView() method.



DataBinding (view binding + data binding) : 뷰결합 + 데이터 결합 아키텍쳐

android {
    
    .....


    //Android Studio 4.0 버전 이상일때,
    buildFeatures {
        dataBinding = true
    }
    
    //Android Studio 4.0 버전 미만일때,
    dataBinding {
    	enabled= true
    }
}

데이터 바인딩의 사용설정을 해주면 뷰바인딩과 마찬가지로 레이아웃 xml 파일과 연결되어 자동으로 바인딩 클래스가 생성된다. 차이점은 Data Binding의 root는 <layout>을 최상단에 추가해주어야 하고, <data> 요소가 추가해준다.

# activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <!-- 레이아웃뷰와 바인딩할 데이터들 명칭과 클래스지정 : 데이터바인딩으로 연결할 testVo 클래스를 이 레이아웃에서 testVo 라는 이름으로 참조하여 사용하겠다는 의미-->
    <data>
        <variable name="testVo"
            type="com.test.common.TestVo" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="16dp">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="8dp"
            android:text="@{String.valueOf(testVo.age)}"/>

        <CheckBox
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="북마크"
            android:checked="@{testVo.isBooked}"/> 

    </LinearLayout>

</layout>

import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;

import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

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

        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        binding.setTestVo(new TestVo("HONGGILDONG", 30, true));
    }
}
public class TestVo{

    String name; 
    int age;   
    boolean isBooked;  
    
    //생성자 
    public TestVo(String name, int age, boolean isBooked){
    	this.name = name;
        this.age = age;
        this.isBooked = isBooked;
    } 
    
}


[reference]

Android Developer 공식문서

https://kitesoft.tistory.com/118

error: Content is protected !!