دیتا بایندینگ
استفاده از دیتا بایندینگ راهیه که از شر findViewById اینا راحت شیم و کدنویسی رو کوتاه تر میکنه.
برای فعال سازی دیتا بایندینگ، در build.gradle کد هایلایت شده رو اضافه میکنیم:
android {
compileSdkVersion 30
buildToolsVersion "30.0.2"
defaultConfig {
applicationId "com.mimdal.viewmodel"
minSdkVersion 19
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
//یه بار ارور داد اینو اضافه کردم درست شد. ولی یه بار دیگه که امتحان کردم جواب نداد :|
buildFeatures{
dataBinding = true
viewBinding = true
}
dataBinding{
enabled = true
}
}
دو تا روش برای دیتا بایندینگ داریم:
1. one way data binding
2. two way data binding
توی اولی فقط کلاس مدل با XML ارتباط داره (رابطه یک طرفه) ولی توی دومی هم کلاس مدل با XML ارتباط داره و هم برعکس (یعنی XML هم با کلاس مدل در ارتباطه)
one-way -> "@{}"
two-way -> "@={}"
ما از two way data binding استفاده میکنیم چون بهتره. اینجا
برای استفاده از data binding کل کدهای XML باید توی تگ layout باشن. قبل از ویوی روت در XML، تگ data باز و بسته میکنیم و داخل بادی آن یک variable معرفی میکنیم. این variable نمونه ای از کلاسی هست که میخوایم از متدهاش استفاده کنیم. type این variable آدرس دقیق اون کلاس رو در بر میگیره.
کدهای هایلایت مربوط به دیتا بایندینگ هستند.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="myuser"
type="com.mimdal.viewmodel.User" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<EditText
android:id="@+id/editTextUserName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="100dp"
android:layout_marginEnd="32dp"
android:ems="10"
android:hint="userName"
android:text="@={myuser.password}"
android:inputType="textPersonName"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<EditText
android:id="@+id/editTextPassword"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="32dp"
android:ems="10"
android:hint="Password"
android:inputType="textPersonName"
android:text="@={myuser.userName}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/editTextUserName" />
<Button
android:id="@+id/buttonCheck"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:text="Check"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/editTextPassword"
android:onClick="@{()->myuser.onClick()}"/> // این نوع تعریف بصورت لامبادا هست
<TextView
android:id="@+id/textViewShow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:text="@{`username and password:\n `+myuser.getTextViewShow()}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/buttonCheck" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
{}@ یعنی مقدار از کلاس مدل به این ویو ریخته بشه
{}=@ یعنی مقدار از XML به متغیر تعریف شده ریخته بشه.
به محض تعریف دیتا بایندینگ اکتیویتی setContentView بصورت زیر تغییر میکند:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
User user = new User();
activityMainBinding.setMyuser(user);
}
}
activityMainBinding دارای تمامی آی دی های لیوت هست. میشه به آی دی همه ویوها از طریق این کلاس (در کامپایل تایم ساخته میشه) دسترسی داشت و مثلا برای تکست ویو متن ست کرد. (البته این کارو نمیکنیم ولی خب میشه)
برای متغیری که در XML تعریف شده یک setter ساخته شده و در MainActivity به آن پاس داده میشود. (این رنگی)
کلاس مدل:
public class User extends BaseObservable {
private String userName;
private String password;
private String textViewShow;
private static final String TAG = "User";
public User(String userName, String password) {
this.userName = userName;
this.password = password;
}
public User() {
}
public String getTextViewShow() {
return textViewShow;
}
public void setTextViewShow(String textViewShow) {
this.textViewShow = textViewShow;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public void onClick(){
textViewShow = password + userName;
Log.d(TAG, "userName: "+ password);
Log.d(TAG, "email: "+ userName);
Log.d(TAG, "textViewShow: "+textViewShow);
}
}
با توجه به اینکه کلاس مدل observable نیست، متدهایی که توی XML و در فرآیند دیتا بایندینگ استفاده شده فقط در زمان اجرای اول فراخونی میشن. هر چقدر توی ادیت تکست ها ورودی وارد کنیم مقادیر فیلدهای آبجکت تغییر میکنه ولی ویو آپدیت نمیشه (توی متد onClick فیلدها لاگ شدن)