ViewModel

2024-03-10 06:12
文章标签 viewmodel

本文主要是介绍ViewModel,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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;@Overrideprotected 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"><TextViewandroid: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" /><Buttonandroid: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;@Overrideprotected 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>() {@Overridepublic void onChanged(Integer i) {text.setText(String.valueOf(i));}});startTimer();}private void startTimer() {new Timer().schedule(new TimerTask() {@Overridepublic void run() {//非UI线程用 postValue//ui线程 用setValuemyViewModel.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"><TextViewandroid: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;@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {// Inflate the layout for this fragmentLog.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>() {@Overridepublic void onChanged(Integer integer) {seekBar.setProgress(integer,true);Log.d("ning",Thread.currentThread().getName());}});seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {myViewModel.getProgress().setValue(progress);Log.d("ning",Thread.currentThread().getName());}
//Livedata@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic 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;@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {// Inflate the layout for this fragmentLog.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>() {@Overridepublic void onChanged(Integer integer) {seekBar.setProgress(integer,true);}});seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {myViewModel.getProgress().setValue(progress);}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic 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 {@Overrideprotected 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"><SeekBarandroid: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"><SeekBarandroid: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"><fragmentandroid: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.Guidelineandroid:id="@+id/guideline"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"app:layout_constraintGuide_percent="0.5" /><fragmentandroid: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 = 34defaultConfig {applicationId = "com.tiger.databinding0"minSdk = 28targetSdk = 34versionCode = 1versionName = "1.0"testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
//        dataBinding {
//            enable =true
//        }buildFeatures { dataBinding = true }}buildTypes {release {isMinifyEnabled = falseproguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"),"proguard-rules.pro")}}compileOptions {sourceCompatibility = JavaVersion.VERSION_1_8targetCompatibility = 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><variablename="idol"type="com.tiger.databinding0.Idol" /></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><androidx.constraintlayout.widget.Guidelineandroid:id="@+id/guideline"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"app:layout_constraintGuide_percent="0.5" /><ImageViewandroid: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" /><TextViewandroid: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" /><TextViewandroid: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 {@Overrideprotected 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 {@Overrideprotected 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><variablename="idol"type="com.tiger.databinding0.Idol" /><variablename="eventHandle"type="com.tiger.databinding0.EventHandleListener" /><import type="com.tiger.databinding0.StarUtils"/></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><androidx.constraintlayout.widget.Guidelineandroid:id="@+id/guideline"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"app:layout_constraintGuide_percent="0.5" /><ImageViewandroid: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" /><TextViewandroid: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="姓名" /><TextViewandroid: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="五星" /><Buttonandroid: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: 传参

<includelayout="@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><variablename="networkImage"type="String" /><variablename="localImage"type="int" /></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><ImageViewandroid: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 {@Overrideprotected 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 {@Overrideprotected 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");}@Bindablepublic 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><variablename="userViewModel"type="com.tiger.databinding4.UserViewModel" /><variablename="event"type="com.tiger.databinding4.EventHandleListener" /></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity">
<!--双向绑定 @={} --><EditTextandroid: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" /><Buttonandroid: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 {@Overrideprotected 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><variablename="userViewModel"type="com.tiger.databinding5.UserViewModel" /></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><EditTextandroid: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 {@Overrideprotected 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@Overridepublic MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {//一个binding 对应一个ItemItemBinding itemBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.item, parent, false);return new MyViewHolder(itemBinding);}@Overridepublic void onBindViewHolder(@NonNull MyViewHolder holder, int position) {Idol idol = idols.get(position);holder.itemBinding.setIdol(idol);}@Overridepublic 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.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><androidx.recyclerview.widget.RecyclerViewandroid: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.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:paddingVertical="10dip"><ImageViewandroid: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" /><TextViewandroid: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="斯嘉丽.约翰逊" /><TextViewandroid: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.Guidelineandroid: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><variablename="idol"type="com.tiger.databinding6.Idol" /></data>
</layout>

这篇关于ViewModel的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/793310

相关文章

MVC(Model-View-Controller)和MVVM(Model-View-ViewModel)

1、MVC MVC(Model-View-Controller) 是一种常用的架构模式,用于分离应用程序的逻辑、数据和展示。它通过三个核心组件(模型、视图和控制器)将应用程序的业务逻辑与用户界面隔离,促进代码的可维护性、可扩展性和模块化。在 MVC 模式中,各组件可以与多种设计模式结合使用,以增强灵活性和可维护性。以下是 MVC 各组件与常见设计模式的关系和作用: 1. Model(模型)

Android JetPack ViewModel 源码解析

是什么? ViewModel 用来存储页面相关的数据,当页面销毁的时候,存储数据也会清楚。但是当页面发生旋转的时候,并不会清楚数据。 怎么用? UserViewModel userViewModel = new ViewModelProvider(this).get(UserViewModel.class); UserViewModel 是自己写的ViewModel,就可以

Android实现自定义方向盘-7livedata,viewmodel相关问题

关于 ViewModel、LiveData、Singleton 模式和跨 Activity 数据共享的相关面试题通常会涉及 Android 架构组件、状态管理和数据持久化等方面的知识。以下是一些常见的面试题以及它们的解答思路: 1. 什么是 ViewModel?它的作用是什么? 回答要点: ViewModel 是 Android 架构组件之一,旨在以生命周期感知的方式存储和管理与 UI 相关的

Jetpack架构组件_ViewModel组件_1.简介和示例

1.简介        ViewModel是我们MVVM中的VM层,ViewModel类似于MVP中的P层,它是我们View层和Model层之间的一个桥梁。 1.1 和MVP的P层的主要区别是: (1)ViewModel是与我们Android系统挂钩的,是官方的一个类,MV之间的一个桥梁。 (2)ViewModel还保持数据。 1.2 Android为什么要引入ViewModel?

Compose 跨页面发送消息使用Channel还是全局ViewModel好?

复杂的app 难免遇到 跨页面传递消息的问题,那么使用 Channel 和全局共享viewModel的形式 对于跨页面传递消息,哪个方案 更好一些呢? AI 回答: 它触及了应用架构设计的核心。让我们比较一下使用 Channel 和全局共享 ViewModel 这两种方案的优缺点,以便更好地理解哪种方案更适合特定情况。 全局共享 ViewModel: 优点: 符合 MVVM 架构:与 A

LiveData+ViewModel用法2:多页面监听同一个状态

1.创建ViewModel public class SingletonViewModel extends ViewModel {private SingletonLiveData content;public SingletonLiveData getContent() {if (content == null) {content = SingletonLiveData.getInstance

LiveData+ViewModel用法1:获取数据

之前一直使用MVP开发。刚上班看一下MVVM。LiveData+ViewModel确实比较给力,但看到databinding感觉xml写法复杂了很多,先记录下LiveData配合ViewModel使用。 LiveData 优点不会再产生由于Activity处于stop状态而引起的崩溃。如果观察者的生命周期是不活跃的,例如 activity 处于后台,那么将不会收到任何 LiveData 事件。

ViewModel(6)ViewModel与Room结合进行数据库操作。

当 ViewModel 与 Room 结合使用时,可以构建出高效且架构良好的 Android 应用。 首先,创建 Room 数据库、实体、DAO 等相关组件。例如,假设有一个 User 实体表示用户信息: @Entity(tableName = "users")public class User {@PrimaryKey(autoGenerate = true)private int id;

ViewModel(8)单元测试

对 ViewModel 进行单元测试可以确保其数据处理逻辑的正确性和稳定性。以下是一个简单的示例,展示如何对 ViewModel 进行单元测试: 假设我们有一个 CounterViewModel,用于管理计数器: import androidx.lifecycle.ViewModel;public class CounterViewModel extends ViewModel {privat

ViewModel(9)viewmodel源码解读。

ViewModel 的源码实现较为复杂,以下是对其主要部分的解读: 一、核心类和接口 ViewModel:这是一个抽象类,定义了 ViewModel 的基本行为。它不持有对视图(如 Activity、Fragment)的引用,确保了 ViewModel 的独立性和可测试性。ViewModelProvider:用于创建 ViewModel 的实例。它接收一个 ViewModelStoreOwne