1.ViewModel的诞生与作用
Activity
package com.tiger.viewmodel;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private TextView textView;
private MyViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
viewModel = new ViewModelProvider(this).get(MyViewModel.class);//新版本写法 单例 spring注入
textView.setText(String.valueOf(viewModel.number));
}
public void plusNumber(View view) {
Log.d("ning",viewModel.toString());
textView.setText(String.valueOf(++viewModel.number));
}
}
ViewModel
package com.tiger.viewmodel;
import androidx.lifecycle.ViewModel;
public class MyViewModel extends ViewModel {
public int number;
}
xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.397" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="加1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.538"
android:onClick="plusNumber"/>
</androidx.constraintlayout.widget.ConstraintLayout>
解开了之前的疑惑。
application也是一个context 可以拿到资源文件很多资源。 可以用到上下文的地方可以用它,全局唯一,贯穿整个App运行生命周期。防止内存泄漏
2.LiveData
viewModel+LiveData
viewModel
package com.tiger.livedata;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class MyViewModel extends ViewModel {
private MutableLiveData<Integer> currentSecond;
public MutableLiveData<Integer> getCurrentSecond() {
if (currentSecond == null){
currentSecond = new MutableLiveData<>();
//初始化
currentSecond.setValue(0);
}
return currentSecond;
}
}
activity
package com.tiger.livedata;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import java.util.Timer;
import java.util.TimerTask;
public class MainActivity extends AppCompatActivity {
private TextView text;
private MyViewModel myViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = findViewById(R.id.text);
myViewModel = new ViewModelProvider(this).get(MyViewModel.class);
text.setText(String.valueOf(myViewModel.getCurrentSecond().getValue()));
myViewModel.getCurrentSecond().observe(this, new Observer<Integer>() {
@Override
public void onChanged(Integer i) {
text.setText(String.valueOf(i));
}
});
startTimer();
}
private void startTimer() {
new Timer().schedule(new TimerTask() {
@Override
public void run() {
//非UI线程用 postValue
//ui线程 用setValue
myViewModel.getCurrentSecond().postValue(myViewModel.getCurrentSecond().getValue()+1);
}
},1000,1000);
}
}
xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
3.ViewModel + LiveData实现 Fragment 间通信
firstFragment
package com.tiger.livedata2;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.SeekBar;
public class FirstFragment extends Fragment {
private MyViewModel myViewModel;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
Log.d("ning","FirstFragment onCreateView");
View root = inflater.inflate(R.layout.fragment_first, container, false);
SeekBar seekBar = root.findViewById(R.id.seekBar);
myViewModel = new ViewModelProvider(this.getActivity()).get(MyViewModel.class);
myViewModel.getProgress().observe(this.getActivity(), new Observer<Integer>() {
@Override
public void onChanged(Integer integer) {
seekBar.setProgress(integer,true);
Log.d("ning",Thread.currentThread().getName());
}
});
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
myViewModel.getProgress().setValue(progress);
Log.d("ning",Thread.currentThread().getName());
}
//Livedata
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
return root;
}
}
secondFragment
package com.tiger.livedata2;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.SeekBar;
public class SecondFragment extends Fragment {
private MyViewModel myViewModel;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
Log.d("ning","SecondFragment onCreateView");
View root = inflater.inflate(R.layout.fragment_second, container, false);
SeekBar seekBar = root.findViewById(R.id.seekBar);
myViewModel = new ViewModelProvider(this.getActivity()).get(MyViewModel.class);
myViewModel.getProgress().observe(this.getActivity(), new Observer<Integer>() {
@Override
public void onChanged(Integer integer) {
seekBar.setProgress(integer,true);
}
});
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
myViewModel.getProgress().setValue(progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
return root;
}
}
viewModel
package com.tiger.livedata2;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class MyViewModel extends ViewModel {
private MutableLiveData<Integer> progress;
public MutableLiveData<Integer> getProgress() {
if (progress == null){
progress = new MutableLiveData<>();
progress.setValue(0);
}
return progress;
}
}
mainActivity
package com.tiger.livedata2;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("ning","MainActivity onCreateView");
setContentView(R.layout.activity_main);
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".FirstFragment">
<SeekBar
android:id="@+id/seekBar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:max="100"
android:min="0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SecondFragment">
<SeekBar
android:id="@+id/seekBar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:max="100"
android:min="0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="@+id/fragment"
android:name="com.tiger.livedata2.FirstFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />
<fragment
android:id="@+id/fragment2"
android:name="com.tiger.livedata2.SecondFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline" />
</androidx.constraintlayout.widget.ConstraintLayout>
4.DataBinding
首先会有个坑 ,因为版本问题,重复代码太多,所以加入一个依赖
不加会爆以下错误
Duplicate class kotlin.collections.jdk8.CollectionsJDK8Kt found in modules kotlin-stdlib-1.8.10 (org.jetbrains.kotlin:kotlin-stdlib:1.8.10) and kotlin-stdlib-jdk8-1.6.21 (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.21) Duplicate class kotlin.internal.jdk7
implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.0"))
build.gradle.kts
plugins {
id("com.android.application")
}
android {
namespace = "com.tiger.databinding0"
compileSdk = 34
defaultConfig {
applicationId = "com.tiger.databinding0"
minSdk = 28
targetSdk = 34
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
// dataBinding {
// enable =true
// }
buildFeatures { dataBinding = true }
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}
dependencies {
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.8.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.0"))
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
}
xml
<?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="idol"
type="com.tiger.databinding0.Idol" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />
<ImageView
android:id="@+id/imageView"
android:layout_width="300dip"
android:layout_height="300dip"
android:src="@drawable/picture"
app:layout_constraintBottom_toTopOf="@+id/guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.495"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.454"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="姓名"
android:text="@{idol.name}"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline"
app:layout_constraintVertical_bias="0.144" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="76dp"
tools:text="五星"
android:text="@{idol.star}"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
idol
package com.tiger.databinding0;
public class Idol {
public String name;
public String star;
public Idol(String name, String star) {
this.name = name;
this.star = star;
}
}
mainActivity
package com.tiger.databinding0;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;
import android.os.Bundle;
import com.tiger.databinding0.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
Idol idol = new Idol("斯嘉丽", "六星");
activityMainBinding.setIdol(idol);
}
}
实现Activity与 layout布局的 解耦
layout绑定它的对象, Activity只需把这个对象set进去。就实现数据绑定了
5.import标签与事件绑定
mainActivity
package com.tiger.databinding0;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;
import android.os.Bundle;
import com.tiger.databinding0.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
Idol idol = new Idol("斯嘉丽", 3);
activityMainBinding.setIdol(idol);
activityMainBinding.setEventHandle(new EventHandleListener(this));
}
}
EventHandleListener
package com.tiger.databinding0;
import android.content.Context;
import android.view.View;
import android.widget.Toast;
public class EventHandleListener {
private Context context;
public EventHandleListener(Context context) {
this.context = context;
}
public void buttonOnClick(View view){
Toast.makeText(context,"喜欢",Toast.LENGTH_SHORT).show();
}
}
StarUtils
package com.tiger.databinding0;
/**
* @author ningchuanqi
* @version V1.0
*/
public class StarUtils {
public static String getStar(int star){
switch (star){
case 1:
return "一星";
case 2:
return "二星";
case 3:
return "三星";
case 4:
return "四星";
case 5:
return "五星";
}
return "";
}
}
xml
<?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="idol"
type="com.tiger.databinding0.Idol" />
<variable
name="eventHandle"
type="com.tiger.databinding0.EventHandleListener" />
<import type="com.tiger.databinding0.StarUtils"/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />
<ImageView
android:id="@+id/imageView"
android:layout_width="300dip"
android:layout_height="300dip"
android:src="@drawable/picture"
app:layout_constraintBottom_toTopOf="@+id/guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.495"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.454"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{idol.name}"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline"
app:layout_constraintVertical_bias="0.144"
tools:text="姓名" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="76dp"
android:text="@{StarUtils.getStar(idol.star)}"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
tools:text="五星" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="喜欢"
android:onClick="@{eventHandle.buttonOnClick}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline"
app:layout_constraintVertical_bias="0.694" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
6.二级页面的绑定
通过app: 传参
<include
layout="@layout/sub"
app:idol="@{idol}"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView" />
7.自定义binding加载图片
package com.tiger.databindng3;
import android.graphics.Color;
import android.text.TextUtils;
import android.util.Log;
import android.widget.ImageView;
import androidx.databinding.BindingAdapter;
import com.squareup.picasso.Picasso;
public class ImageViewBindingAdapter {
// @BindingAdapter("image")//这个image和布局里的 app:image 名字对应 它会把 url传过来 也会把imageView 传过来
// public static void setImage(ImageView imageView, String url) {
// Log.d("ning", url);
// if (!TextUtils.isEmpty(url)) {
// Picasso.get().load(url).placeholder(R.drawable.ic_launcher_background).into(imageView);
// } else {
// imageView.setBackgroundColor(Color.GRAY);
// }
// }
//
// //加载本地图片
// @BindingAdapter("image")//这个image和布局里的 app:image 名字对应 它会把 url传过来 也会把imageView 传过来
// public static void setImage(ImageView imageView, int resId) {
// Log.d("ning", "setImageResource");
// imageView.setImageResource(resId);
// }
@BindingAdapter(value = {"image", "defaultImageResource"}, requireAll = false)
//这个image和布局里的 app:image 名字对应 它会把 url传过来 也会把imageView 传过来
public static void setImage(ImageView imageView, String url, int resId) {
Log.d("ning", "setImageResource"+url+","+resId);
if (!TextUtils.isEmpty(url)) {
Picasso.get().load(url).placeholder(R.drawable.ic_launcher_background).into(imageView);
} else {
imageView.setImageResource(resId);
}
}
}
<?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="networkImage"
type="String" />
<variable
name="localImage"
type="int" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="@+id/imageView"
android:layout_width="300dip"
android:layout_height="300dip"
app:image="@{networkImage}"
app:defaultImageResource="@{localImage}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="@tools:sample/avatars" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
package com.tiger.databindng3;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;
import android.os.Bundle;
import com.tiger.databindng3.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
activityMainBinding.setNetworkImage("https://copyright.bdstatic.com/vcg/creative/cc9c744cf9f7c864889c563cbdeddce6.jpg@h_1280");
activityMainBinding.setLocalImage(R.drawable.picture);
}
}
8.双向绑定
BaseObservable
activity
package com.tiger.databinding4;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;
import android.os.Bundle;
import com.tiger.databinding4.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
UserViewModel userViewModel = new UserViewModel();
activityMainBinding.setUserViewModel(userViewModel);
activityMainBinding.setEvent(new EventHandleListener(userViewModel));
}
}
userviewmodel
package com.tiger.databinding4;
import android.util.Log;
import androidx.databinding.BaseObservable;
import androidx.databinding.Bindable;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class UserViewModel extends BaseObservable {
private User user;
public UserViewModel() {
this.user = new User("Jack");
}
@Bindable
public String getUserName(){
return user.userName;
}
public void setUserName(String userName){
if (userName!=null && !userName.equals(user.userName)){
user.userName = userName;
Log.d("ning","setUserName:"+userName);
//当内容发生变化的时候,通知更新页面
notifyPropertyChanged(BR.userName);
}
}
}
User
package com.tiger.databinding4;
public class User {
public String userName;
public User(String userName) {
this.userName = userName;
}
}
event
package com.tiger.databinding4;
import android.view.View;
public class EventHandleListener {
private UserViewModel userViewModel;
public EventHandleListener(UserViewModel userViewModel) {
this.userViewModel = userViewModel;
}
public void restore(View view){
userViewModel.setUserName("请输入内容:");
}
}
xml
<?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="userViewModel"
type="com.tiger.databinding4.UserViewModel" />
<variable
name="event"
type="com.tiger.databinding4.EventHandleListener" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!--双向绑定 @={} -->
<EditText
android:id="@+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName"
android:text="@={userViewModel.userName}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="输入框变成 请输入内容"
android:onClick="@{event.restore}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/editText"
app:layout_constraintVertical_bias="0.145" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
ObservableField
activity
package com.tiger.databinding5;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import com.tiger.databinding5.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
activityMainBinding.setUserViewModel(new UserViewModel());
}
}
user
package com.tiger.databinding5;
/**
* @author ningchuanqi
* @version V1.0
*/
public class User {
public String userName;
public User(String userName) {
this.userName = userName;
}
}
UserViewModel
package com.tiger.databinding5;
import android.util.Log;
import androidx.databinding.ObservableField;
/**
* @author ningchuanqi
* @version V1.0
*/
public class UserViewModel {
private ObservableField<User> userObservableField;
public UserViewModel(){
User user = new User("Jack");
userObservableField = new ObservableField<>();
userObservableField.set(user);
}
public String getUserName(){
return userObservableField.get().userName;
}
public void setUserName(String userName){
Log.d("ning","userObservableField:"+userName);
userObservableField.get().userName = userName;
}
}
xml
<?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="userViewModel"
type="com.tiger.databinding5.UserViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<EditText
android:id="@+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName"
android:text="@={userViewModel.userName}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
9. RecyclerView 的 绑定
activity
package com.tiger.databinding6;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;
import androidx.recyclerview.widget.LinearLayoutManager;
import android.os.Bundle;
import com.tiger.databinding6.databinding.ActivityMainBinding;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
List<Idol> idols = IdolUtils.get();
activityMainBinding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
RecyclerViewAdapter recyclerViewAdapter = new RecyclerViewAdapter(idols);
activityMainBinding.recyclerView.setAdapter(recyclerViewAdapter);
}
}
RecyclerViewAdapter
package com.tiger.databinding6;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;
import androidx.recyclerview.widget.RecyclerView;
import com.tiger.databinding6.databinding.ItemBinding;
import java.util.List;
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder> {
List<Idol> idols;
public RecyclerViewAdapter(List<Idol> idols) {
this.idols = idols;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//一个binding 对应一个Item
ItemBinding itemBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.item, parent, false);
return new MyViewHolder(itemBinding);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
Idol idol = idols.get(position);
holder.itemBinding.setIdol(idol);
}
@Override
public int getItemCount() {
return idols.size();
}
static class MyViewHolder extends RecyclerView.ViewHolder {
private ItemBinding itemBinding;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
}
public MyViewHolder(ItemBinding itemBinding) {
super(itemBinding.getRoot());
this.itemBinding = itemBinding;
}
}
}
ImageViewBindingAdapter
package com.tiger.databinding6;
import android.graphics.Color;
import android.text.TextUtils;
import android.util.Log;
import android.widget.ImageView;
import androidx.databinding.BindingAdapter;
import com.squareup.picasso.Picasso;
public class ImageViewBindingAdapter {
// @BindingAdapter("image")//这个image和布局里的 app:image 名字对应 它会把 url传过来 也会把imageView 传过来
// public static void setImage(ImageView imageView, String url) {
// Log.d("ning", url);
// if (!TextUtils.isEmpty(url)) {
// Picasso.get().load(url).placeholder(R.drawable.ic_launcher_background).into(imageView);
// } else {
// imageView.setBackgroundColor(Color.GRAY);
// }
// }
//
// //加载本地图片
// @BindingAdapter("image")//这个image和布局里的 app:image 名字对应 它会把 url传过来 也会把imageView 传过来
// public static void setImage(ImageView imageView, int resId) {
// Log.d("ning", "setImageResource");
// imageView.setImageResource(resId);
// }
@BindingAdapter(value = "itemImage", requireAll = false)
//这个image和布局里的 app:image 名字对应 它会把 url传过来 也会把imageView 传过来
public static void setImage(ImageView imageView, String url) {
if (!TextUtils.isEmpty(url)) {
Picasso.get().load(url).placeholder(R.drawable.ic_launcher_background).into(imageView);
} else {
imageView.setBackgroundColor(Color.GRAY);
}
}
}
Idol
package com.tiger.databinding6;
public class Idol {
public String chName;
public String enName;
public String image;
public Idol(String chName, String enName, String image) {
this.chName = chName;
this.enName = enName;
this.image = image;
}
}
IdolUtils
package com.tiger.databinding6;
import java.util.ArrayList;
import java.util.List;
/**
* @author ningchuanqi
* @version V1.0
*/
public class IdolUtils {
public static List<Idol> get(){
List<Idol> list = new ArrayList<>();
Idol i1 = new Idol("斯嘉丽.约翰逊","Scarlett Johansson","https://5b0988e595225.cdn.sohucs.com/images/20190624/d93dbf866aa2405f8b9b1d660c15db9d.jpeg");
list.add(i1);
Idol i2 = new Idol("安吉丽娜·朱莉","Angelina Jolie","https://5b0988e595225.cdn.sohucs.com/images/20190624/0657ccc0066b4e1797ead2b3293230b0.jpeg");
list.add(i2);
Idol i3 = new Idol("杰西卡·辛普森","Jessica Simpson","https://5b0988e595225.cdn.sohucs.com/images/20190624/49c95e9b542a4854b2232e67579b9215.jpeg");
list.add(i3);
Idol i4 = new Idol("萨尔玛·海耶克","Salma Hayek","https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3893590240,2013198505&fm=26&gp=0.jpg");
list.add(i4);
Idol i5 = new Idol("卡门·伊莱克特拉","Carmen Electra","https://5b0988e595225.cdn.sohucs.com/images/20190624/1399d0fda46c467dbd988f2996dccaad.jpeg");
list.add(i5);
Idol i6 = new Idol("凯瑟琳·海格尔","Katherine Heigl","https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fq_70%2Cc_zoom%2Cw_640%2Fimages%2F20180116%2F74c81a087a28446590734ca257e3eacf.jpeg&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1618118692&t=6c5c1eecb1b0db8664810bfc51f8609b");
list.add(i6);
Idol i7 = new Idol("珍妮佛·安妮斯顿","Jennifer Aniston","https://5b0988e595225.cdn.sohucs.com/images/20190624/98e8b18a86004eb79bef58318e93446d.jpeg");
list.add(i7);
Idol i8 = new Idol("梅根·福克斯","Megan Fox","https://5b0988e595225.cdn.sohucs.com/images/20190624/37991ee797e6496d99cdee5315082b76.jpeg");
list.add(i8);
Idol i9 = new Idol("杰西卡·阿尔芭","Jessica Alba","https://5b0988e595225.cdn.sohucs.com/images/20190624/eb49bf15b9634d579ff89f596c54e0ca.jpeg");
list.add(i9);
Idol i10 = new Idol("詹妮弗·洛芙·休伊特","Jennifer Love Hewitt","https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=791729948,2390587761&fm=26&gp=0.jpg");
list.add(i10);
return list;
}
}
xml
<?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>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
<?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">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingVertical="10dip">
<ImageView
android:id="@+id/imageView"
android:layout_width="100dip"
android:layout_height="100dip"
app:itemImage="@{idol.image}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintHorizontal_bias="0.432"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.054"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:id="@+id/textViewChName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{idol.chName}"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.138"
app:layout_constraintStart_toStartOf="@+id/guideline2"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.063"
tools:text="斯嘉丽.约翰逊" />
<TextView
android:id="@+id/textViewEnName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="28dp"
android:text="@{idol.enName}"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="@+id/textViewChName"
app:layout_constraintTop_toBottomOf="@+id/textViewChName"
tools:text="Scarlett Johansson" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.4" />
</androidx.constraintlayout.widget.ConstraintLayout>
<data>
<variable
name="idol"
type="com.tiger.databinding6.Idol" />
</data>
</layout>