与 DataBinding 一起使用时,LiveData 不会通知 UI 有关更改
LiveData doesn't notify UI about changes when used with DataBinding
我想更改 UI,因为 LiveData
在与 DataBinding 一起使用时会更改。但随着 LiveData
的变化,它并未反映 UI.
的变化
MainViewModel.java
public class MainViewModel extends AndroidViewModel {
/**
* Boolean variable to see whether user is ClockedIn or ClockedOut
*/
public MutableLiveData<Boolean> isClockedIn;
public MainViewModel(Application application) {
super(application);
isClockedIn = new MutableLiveData<>();
//...
calculateClockedInOrNot(PreferencesManager.getString(mContext,PreferencesManager.CLOCK_STATUS_KEY));
}
/**
* An utility function to calculate whether user is clocked in or clocked out,
* this function is also called within this ViewModel after an api hit
*
* if string == "CLOCKED_OUT" or string == "mobileEventType.CLOCK_OUT" => user is clocked out
* else user is clocked in
*/
private void calculateClockedInOrNot(String string) {
if (string.equals("CLOCKED_OUT") || string.equals("mobileEventType.CLOCK_OUT")) {
//user is clocked out
isClockedIn.setValue(false);
} else {
//user is clocked in
isClockedIn.setValue(true);
}
}
//getter function
public MutableLiveData<Boolean> isClockedIn() {
return isClockedIn;
}
//other function left for brevity
}
MainActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Obtain the ViewModel component.
mainViewModel = ViewModelProviders.of(this).get(MainViewModel.class);
// Inflate view and obtain an instance of the binding class.
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
// Assign the component to a property in the binding class.
binding.setData(mainViewModel);
}
activity_main.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:bind="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="data"
type="com.app.bidunity.viewmodel.MainViewModel" />
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="@dimen/img_hight_location"
android:adjustViewBounds="true"
android:src="@{data.clockedIn ? @drawable/ic_location_on : @drawable/ic_location_off}"/>
<!--Other view left for brevity-->
</LinearLayout>
</layout>
build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.app.bidunity"
minSdkVersion 17
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
dataBinding {
enabled = true
}
compileOptions {
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
}
}
dependencies {
def arch_version = "2.0.0-rc01"
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
//material library
implementation 'com.google.android.material:material:1.0.0'
// ViewModel and LiveData
implementation "androidx.lifecycle:lifecycle-extensions:$arch_version"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.0-alpha4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4'
}
我正在使用 Android studio 3.3 Canary 11 以及 gradle 4.10.1 和 onclick
与数据绑定在 viewmodel 中工作正常,但即使在更改 isClockedIn
之后 ImageView
也没有改变它的可绘制性。我已经尝试了一切,我什至调试以查看 isClockedIn
是否在 运行 的中间发生变化,是的,它的值正在发生变化
你需要让你的 isClockedIn
变量 Observable Field,
所以从
替换它
public boolean isClockedIn = false;
至
public ObservableBoolean isClockedIn = new ObservableBoolean();
注意:还要确保 xml 与 ViewModel
中的变量名称相同
参考here
编辑:
如果你不想做ObservableField,那么它需要做一些其他的改变。
尽管有 ObservableField,您仍需要使您的可观察对象扩展 BaseObservable
并在您的 livedata 您需要在布尔值更改后调用 notifyPropertyChanged(BR.isClockedIn);
。
如果你想使用 LiveData 作为观察者,首先是为你的绑定提供一个生命周期
// Specify the current activity as the lifecycle owner (in your activity/fragment).
binding.setLifecycleOwner(this);
在您的 ViewModel 中,使用 LiveData 对象观察变化并对其应用 Transformation:
MutableLiveData<Boolean> dataToBeObserve = new MutableLiveData<>();
LiveData booleanDataChange = Transformations.map(dataToBeObserve, dataToBeObserve-> dataToBeObserve.value);
现在,使用此 booleanDataChange
到 xml 并更改您的 MutableLiveData 值以观察数据更改事件。
注意:您可以对更改事件使用相同的 LiveData,只需要将定义拆分为构造函数调用即可。
我想更改 UI,因为 LiveData
在与 DataBinding 一起使用时会更改。但随着 LiveData
的变化,它并未反映 UI.
MainViewModel.java
public class MainViewModel extends AndroidViewModel {
/**
* Boolean variable to see whether user is ClockedIn or ClockedOut
*/
public MutableLiveData<Boolean> isClockedIn;
public MainViewModel(Application application) {
super(application);
isClockedIn = new MutableLiveData<>();
//...
calculateClockedInOrNot(PreferencesManager.getString(mContext,PreferencesManager.CLOCK_STATUS_KEY));
}
/**
* An utility function to calculate whether user is clocked in or clocked out,
* this function is also called within this ViewModel after an api hit
*
* if string == "CLOCKED_OUT" or string == "mobileEventType.CLOCK_OUT" => user is clocked out
* else user is clocked in
*/
private void calculateClockedInOrNot(String string) {
if (string.equals("CLOCKED_OUT") || string.equals("mobileEventType.CLOCK_OUT")) {
//user is clocked out
isClockedIn.setValue(false);
} else {
//user is clocked in
isClockedIn.setValue(true);
}
}
//getter function
public MutableLiveData<Boolean> isClockedIn() {
return isClockedIn;
}
//other function left for brevity
}
MainActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Obtain the ViewModel component.
mainViewModel = ViewModelProviders.of(this).get(MainViewModel.class);
// Inflate view and obtain an instance of the binding class.
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
// Assign the component to a property in the binding class.
binding.setData(mainViewModel);
}
activity_main.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:bind="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="data"
type="com.app.bidunity.viewmodel.MainViewModel" />
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="@dimen/img_hight_location"
android:adjustViewBounds="true"
android:src="@{data.clockedIn ? @drawable/ic_location_on : @drawable/ic_location_off}"/>
<!--Other view left for brevity-->
</LinearLayout>
</layout>
build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.app.bidunity"
minSdkVersion 17
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
dataBinding {
enabled = true
}
compileOptions {
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
}
}
dependencies {
def arch_version = "2.0.0-rc01"
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
//material library
implementation 'com.google.android.material:material:1.0.0'
// ViewModel and LiveData
implementation "androidx.lifecycle:lifecycle-extensions:$arch_version"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.0-alpha4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4'
}
我正在使用 Android studio 3.3 Canary 11 以及 gradle 4.10.1 和 onclick
与数据绑定在 viewmodel 中工作正常,但即使在更改 isClockedIn
之后 ImageView
也没有改变它的可绘制性。我已经尝试了一切,我什至调试以查看 isClockedIn
是否在 运行 的中间发生变化,是的,它的值正在发生变化
你需要让你的 isClockedIn
变量 Observable Field,
所以从
替换它public boolean isClockedIn = false;
至
public ObservableBoolean isClockedIn = new ObservableBoolean();
注意:还要确保 xml 与 ViewModel
中的变量名称相同参考here
编辑:
如果你不想做ObservableField,那么它需要做一些其他的改变。
尽管有 ObservableField,您仍需要使您的可观察对象扩展 BaseObservable
并在您的 livedata 您需要在布尔值更改后调用 notifyPropertyChanged(BR.isClockedIn);
。
如果你想使用 LiveData 作为观察者,首先是为你的绑定提供一个生命周期
// Specify the current activity as the lifecycle owner (in your activity/fragment).
binding.setLifecycleOwner(this);
在您的 ViewModel 中,使用 LiveData 对象观察变化并对其应用 Transformation:
MutableLiveData<Boolean> dataToBeObserve = new MutableLiveData<>();
LiveData booleanDataChange = Transformations.map(dataToBeObserve, dataToBeObserve-> dataToBeObserve.value);
现在,使用此 booleanDataChange
到 xml 并更改您的 MutableLiveData 值以观察数据更改事件。
注意:您可以对更改事件使用相同的 LiveData,只需要将定义拆分为构造函数调用即可。