Android
데이터 바인딩 라이브러리
수색…
비고
설정
데이터 바인딩을 사용하기 전에 build.gradle
에서 플러그인을 활성화해야합니다.
android {
....
dataBinding {
enabled = true
}
}
참고 : 데이터 바인딩이 1.5.0 버전의 Android Gradle 플러그인에 추가되었습니다.
클래스 이름 바인딩
데이터 바인딩 플러그인은 레이아웃의 파일 이름을 파스칼 케이스로 변환하고 끝에 "바인딩"을 추가하여 바인딩 클래스 이름을 생성합니다. 따라서 item_detail_activity.xml
라는 이름의 클래스가 생성됩니다 ItemDetailActivityBinding
.
자원
기본 텍스트 필드 바인딩
Gradle (모듈 : 앱) 구성
android {
....
dataBinding {
enabled = true
}
}
데이터 모델
public class Item {
public String name;
public String description;
public Item(String name, String description) {
this.name = name;
this.description = description;
}
}
레이아웃 XML
첫 번째 단계는 레이아웃을 <layout>
태그로 묶고 <data>
요소를 추가하고 데이터 모델에 <variable>
요소를 추가하는 것입니다.
그런 다음 @{model.fieldname}
사용하여 데이터 모델의 필드에 XML 속성을 바인딩 할 수 있습니다. 여기서 model
은 변수의 이름이고 fieldname
은 액세스하려는 필드입니다.
item_detail_activity.xml :
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="item" type="com.example.Item"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{item.name}"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{item.description}"/>
</LinearLayout>
</layout>
바인딩으로 올바르게 구성된 각 XML 레이아웃 파일의 경우 Android Gradle 플러그인은 해당 클래스 인 바인딩을 생성합니다. 우리가 레이아웃 이름 item_detail_activity을 가지고 있기 때문에, 해당 생성 바인딩 클래스라고 ItemDetailActivityBinding
.
이 바인딩은 다음과 같이 Activity에서 사용할 수 있습니다.
public class ItemDetailActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ItemDetailActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.item_detail_activity);
Item item = new Item("Example item", "This is an example item.");
binding.setItem(item);
}
}
접근 자 메서드로 바인딩
모델에 비공개 메소드가있는 경우 데이터 바인딩 라이브러리를 통해 메소드의 전체 이름을 사용하지 않고도 뷰에서 액세스 할 수 있습니다.
데이터 모델
public class Item {
private String name;
public String getName() {
return name;
}
}
레이아웃 XML
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="item" type="com.example.Item"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Since the "name" field is private on our data model,
this binding will utilize the public getName() method instead. -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{item.name}"/>
</LinearLayout>
</layout>
클래스 참조하기
데이터 모델
public class Item {
private String name;
public String getName() {
return name;
}
}
레이아웃 XML
Java에서와 마찬가지로 참조 된 클래스를 가져와야합니다.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="android.view.View"/>
<variable name="item" type="com.example.Item"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- We reference the View class to set the visibility of this TextView -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{item.name}"
android:visibility="@{item.name == null ? View.VISIBLE : View.GONE"/>
</LinearLayout>
</layout>
주 : 패키지 java.lang.*
은 시스템에 의해 자동으로 임포트됩니다. ( JVM
for Java
마찬가지 임)
조각에서 데이터 바인딩
데이터 모델
public class Item {
private String name;
public String getName() {
return name;
}
public void setName(String name){
this.name = name;
}
}
레이아웃 XML
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="item" type="com.example.Item"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{item.name}"/>
</LinearLayout>
</layout>
파편
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
FragmentTest binding = DataBindingUtil.inflate(inflater, R.layout.fragment_test, container, false);
Item item = new Item();
item.setName("Thomas");
binding.setItem(item);
return binding.getRoot();
}
내장 된 양방향 데이터 바인딩
양방향 데이터 바인딩은 다음 특성을 지원합니다.
요소 | 속성 |
---|---|
AbsListView | android:selectedItemPosition |
CalendarView | android:date |
CompoundButton | android:checked |
DatePicker |
|
EditText | android:text |
NumberPicker | android:value |
RadioGroup | android:checkedButton |
RatingBar | android:rating |
SeekBar | android:progress |
TabHost | android:currentTab |
TextView | android:text |
TimePicker |
|
ToggleButton | android:checked |
Switch | android:checked |
용법
<layout ...>
<data>
<variable type="com.example.myapp.User" name="user"/>
</data>
<RelativeLayout ...>
<EditText android:text="@={user.firstName}" .../>
</RelativeLayout>
</layout>
바인딩 표현식 @={}
에는 양방향 바인딩에 필요한 추가 =
가 있습니다. 양방향 바인딩 식에서는 메서드를 사용할 수 없습니다.
RecyclerView 어댑터의 데이터 바인딩
RecyclerView
어댑터에서 데이터 바인딩을 사용할 수도 있습니다.
데이터 모델
public class Item {
private String name;
public String getName() {
return name;
}
}
XML 레이아웃
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{item.name}"/>
어댑터 클래스
public class ListItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Activity host;
private List<Item> items;
public ListItemAdapter(Activity activity, List<Item> items) {
this.host = activity;
this.items = items;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// inflate layout and retrieve binding
ListItemBinding binding = DataBindingUtil.inflate(host.getLayoutInflater(),
R.layout.list_item, parent, false);
return new ItemViewHolder(binding);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Item item = items.get(position);
ItemViewHolder itemViewHolder = (ItemViewHolder)holder;
itemViewHolder.bindItem(item);
}
@Override
public int getItemCount() {
return items.size();
}
private static class ItemViewHolder extends RecyclerView.ViewHolder {
ListItemBinding binding;
ItemViewHolder(ListItemBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
void bindItem(Item item) {
binding.setItem(item);
binding.executePendingBindings();
}
}
}
Binding으로 Listener를 클릭하십시오.
clickHandler 용 인터페이스 만들기
public interface ClickHandler {
public void onButtonClick(View v);
}
레이아웃 XML
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="handler"
type="com.example.ClickHandler"/>
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="click me"
android:onClick="@{handler.onButtonClick}"/>
</RelativeLayout>
</layout>
활동에서 이벤트 처리
public class MainActivity extends Activity implements ClickHandler {
private ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
binding.setHandler(this);
}
@Override
public void onButtonClick(View v) {
Toast.makeText(context,"Button clicked",Toast.LENGTH_LONG).show();
}
}
람다 표현식을 사용한 맞춤 이벤트
인터페이스 정의
public interface ClickHandler {
public void onButtonClick(User user);
}
Model 클래스 만들기
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
레이아웃 XML
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="handler"
type="com.example.ClickHandler"/>
<variable
name="user"
type="com.example.User"/>
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.name}"
android:onClick="@{() -> handler.onButtonClick(user)}"/>
</RelativeLayout>
</layout>
활동 코드 :
public class MainActivity extends Activity implements ClickHandler {
private ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
binding.setUser(new User("DataBinding User"));
binding.setHandler(this);
}
@Override
public void onButtonClick(User user) {
Toast.makeText(MainActivity.this,"Welcome " + user.getName(),Toast.LENGTH_LONG).show();
}
}
XML 코드에서는 사용할 수 없지만 Java 코드에서 설정할 수있는 일부 뷰 수신기의 경우 사용자 정의 바인딩을 사용하여 바인딩 할 수 있습니다.
사용자 정의 클래스
public class BindingUtil {
@BindingAdapter({"bind:autoAdapter"})
public static void setAdapter(AutoCompleteTextView view, ArrayAdapter<String> pArrayAdapter) {
view.setAdapter(pArrayAdapter);
}
@BindingAdapter({"bind:onKeyListener"})
public static void setOnKeyListener(AutoCompleteTextView view , View.OnKeyListener pOnKeyListener)
{
view.setOnKeyListener(pOnKeyListener);
}
}
핸들러 클래스
public class Handler extends BaseObservable {
private ArrayAdapter<String> roleAdapter;
public ArrayAdapter<String> getRoleAdapter() {
return roleAdapter;
}
public void setRoleAdapter(ArrayAdapter<String> pRoleAdapter) {
roleAdapter = pRoleAdapter;
}
}
XML
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/tools" >
<data>
<variable
name="handler"
type="com.example.Handler" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<AutoCompleteTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
bind:autoAdapter="@{handler.roleAdapter}" />
</LinearLayout>
</layout>
데이터 바인딩의 기본값
미리보기 창에는 데이터 바인딩 표현식에 대한 기본값이 표시됩니다.
예 :
android:layout_height="@{@dimen/main_layout_height, default=wrap_content}"
디자인하는 동안 wrap_content
를 취하고 미리보기 창에서 wrap_content
역할을합니다.
또 다른 예는 다음과 같습니다.
android:text="@{user.name, default=`Preview Text`}"
미리보기 창에 미리 Preview Text
가 표시되지만 장치 / 에뮬레이터에서 실행하면 실제로 바인딩 된 텍스트가 표시됩니다
사용자 정의 변수를 사용한 데이터 바인딩 (int, boolean)
때로는 단일 값을 기반으로보기 숨기기 / 표시 같은 기본 작업을 수행해야합니다. 단 하나의 변수에 대해서는 모델을 만들 수 없거나 모델을 만드는 것이 좋지 않습니다. DataBinding은 이러한 작업을 수행하기위한 기본 데이터 유형을 지원합니다.
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="android.view.View" />
<variable
name="selected"
type="Boolean" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World"
android:visibility="@{selected ? View.VISIBLE : View.GONE}" />
</RelativeLayout>
</layout>
그 값을 Java 클래스에서 설정합니다.
binding.setSelected(true);
대화 상자의 데이터 바인딩
public void doSomething() {
DialogTestBinding binding = DataBindingUtil
.inflate(LayoutInflater.from(context), R.layout.dialog_test, null, false);
Dialog dialog = new Dialog(context);
dialog.setContentView(binding.getRoot());
dialog.show();
}
BindingAdapter에서 위젯을 참조로 전달합니다.
레이아웃 XML
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/img"
android:layout_width="match_parent"
android:layout_height="100dp"
app:imageUrl="@{url}"
app:progressbar="@{progressBar}"/>
</LinearLayout>
</layout>
BindingAdapter 메서드
@BindingAdapter({"imageUrl","progressbar"})
public static void loadImage(ImageView view, String imageUrl, ProgressBar progressBar){
Glide.with(view.getContext()).load(imageUrl)
.listener(new RequestListener<String, GlideDrawable>() {
@Override
public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
progressBar.setVisibility(View.GONE);
return false;
}
}).into(view);
}