如果您对android.databinding.ObservableBoolean的实例源码和androiddataobb感兴趣,那么这篇文章一定是您不可错过的。我们将详细讲解android.data
如果您对android.databinding.ObservableBoolean的实例源码和android data obb感兴趣,那么这篇文章一定是您不可错过的。我们将详细讲解android.databinding.ObservableBoolean的实例源码的各种细节,并对android data obb进行深入的分析,此外还有关于android -------- Data Binding 的使用(三)Observable、Android Data Binding 系列 (二) -- Binding 与 Observer 实现原理、Android Studio 4.0.1:构建失败:不建议使用“ android.databinding.enableV2”选项、android – Observable返回类型必须参数化为Observable或Observable的实用技巧。
本文目录一览:- android.databinding.ObservableBoolean的实例源码(android data obb)
- android -------- Data Binding 的使用(三)Observable
- Android Data Binding 系列 (二) -- Binding 与 Observer 实现原理
- Android Studio 4.0.1:构建失败:不建议使用“ android.databinding.enableV2”选项
- android – Observable返回类型必须参数化为Observable或Observable
android.databinding.ObservableBoolean的实例源码(android data obb)
@Test public void takeTakesCorrectTimes() throws Exception { String string1 = "STRING 1"; String string2 = "STRING 2"; ObservableField<String> observed = new ObservableField<>(string1); ObservableBoolean observing = Cinder.computeBoolean(()-> observed.get().equals(string1),observed).take(2).immediate(); assertTrue(observing.get()); observed.set(string2); assertFalse(observing.get()); observed.set(string1); assertFalse(observing.get()); }
@Test public void skipSkipsCorrectTimes() throws Exception { String string1 = "STRING 1"; String string2 = "STRING 2"; ObservableField<String> observed = new ObservableField<>(string1); ObservableBoolean observing = Cinder.computeBoolean(()-> observed.get().equals(string1),observed).skip(1); observed.set(string1); assertFalse(observing.get()); observed.set(string2); assertFalse(observing.get()); observed.set(string1); assertTrue(observing.get()); }
public PasswordReadviewmodel(Navigator navigator,PasswordInteractor interactor,int id) { this.navigator = navigator; this.interactor = interactor; this.id = id; this.title = new ObservableField<>(); this.icon = new ObservableField<>(); this.username = new ObservableField<>(); this.password = new ObservableField<>(); this.displayPassword = new ObservableBoolean(false); this.customFields = new ObservableArrayList<>(); realmPassword = interactor.readPassword(id); realmPassword.addchangelistener(this::updateView); updateView(realmPassword); }
/** * Creates {@code RxCommand} to execute the specified command from the specified {@link * Observable} with the specified initial state. * * @param canExecuteSource an {@link Observable} to emit whether this {@code RxCommand} can * execute * @param canExecute whether this {@code RxCommand} can execute initially */ public RxCommand(@Nullable final Observable<Boolean> canExecuteSource,boolean canExecute) { canExecuteFlag = new ObservableBoolean(canExecute); if (canExecuteSource != null) { canExecuteSourcedisposable = canExecuteSource.distinctUntilChanged() .subscribeWith(new disposableObserver<Boolean>() { @Override public void onNext(Boolean value) { canExecuteFlag.set(value); } @Override public void onError(Throwable e) { kicker.onError(e); RxCommand.this.dispose(); } @Override public void onComplete() { kicker.onComplete(); RxCommand.this.dispose(); } }); } }
@Inject public SignInActivityviewmodel(BaseActivity activity,SignInUseCase signInUseCase,CheckSessionUseCase checkSessionUseCase) { super(activity); this.signInUseCase = signInUseCase; this.checkSessionUseCase = checkSessionUseCase; name = new ObservableField<>(); password = new ObservableField<>(); buttonEnabled = new ObservableBoolean(false); checkSessionUseCase.run() .compose(bindToLifecycle().forSingle()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(authToken -> { Timber.v("Check session: " + authToken.token); Toast.makeText(getContext(),"Already signed in",Toast.LENGTH_SHORT).show(); goToNext(); },Timber::e); }
Listener(final ObservableBoolean observableBoolean,final Observer<? super Boolean> observer) { this.observableBoolean = observableBoolean; this.onPropertyChangedCallback = new android.databinding.Observable.OnPropertyChangedCallback() { @Override public void onPropertyChanged(android.databinding.Observable observable,int ignoredPropertyId) { if (!isdisposed()) { ObservableBoolean observableBoolean = (ObservableBoolean) observable; observer.onNext(observableBoolean.get()); } } }; }
public Followersviewmodel(@NonNull DataListener dataListener,@NonNull Context context,TwitterSession session,Long userId) { this.dataListener = dataListener; this.context = context; this.session = session; this.userId = userId; activityFollowerProgressBar = new ObservableInt(View.VISIBLE); activityFollowerSwipeRefreshLayout = new ObservableInt(View.GONE); activityFollowerRecyclerView = new ObservableInt(View.GONE); activityFollowerIsPullToRefresh = new ObservableBoolean(false); initializeViews(); fetchFollowersList(false,false,cursor); }
/** * Default constructor. * @param context The context of the current activity. */ public Explorerviewmodel(Context context) { this.context = context; this.isLoading = new ObservableBoolean(false); this.isRefreshing = new ObservableBoolean(false); this.files = new ObservableArrayList<Fileviewmodel>(); this.isSelectionMode = new ObservableBoolean(false); this.numberSelectedItems = new ObservableInt(0); this.changeDirectory("/"); }
/** * Default constructor. * @param context The context of the current activity. */ public ListServerviewmodel(Activity context) { this.context = context; this.servers = new ObservableArrayList<FtpServerviewmodel>(); this.selectedServer = new ObservableField<FtpServerviewmodel>(); this.selectedServerVisible = new ObservableBoolean(); }
@Inject public PostListComponentviewmodel(Bus bus,IRepository repository,INavigator navigator,ILocalization localization) { super(bus); this.repository = repository; this.navigator = navigator; this.localization = localization; this.posts = new ObservableArrayList<>(); this.isBusy = new ObservableBoolean(); this.loadCommand = new Command(this::loadPosts); }
@Test public void fireNotifiesChange() throws Exception { ObservableEvent event = new ObservableEvent(); ObservableBoolean fired = Cinder.computeBoolean(()->true,event); event.fire(); assertTrue(fired.get()); }
@Test public void computesBoolean() throws Exception { boolean bool1 = true; boolean bool2 = false; ObservableBoolean truth = new ObservableBoolean(bool1); ObservableBoolean computedTruth = Cinder.computeBoolean(()->truth.get(),truth).immediate(); assertEquals(computedTruth.get(),bool1); truth.set(bool2); assertEquals(computedTruth.get(),bool2); }
@Test public void onceTakesOnce() throws Exception { String string1 = "STRING 1"; String string2 = "STRING 2"; ObservableField<String> observed = new ObservableField<>(string1); ObservableBoolean observing = Cinder.computeBoolean(()-> observed.get().equals(string1),observed).once().immediate(); assertTrue(observing.get()); observed.set(string2); assertTrue(observing.get()); }
@Test public void filterFilters() throws Exception { String badString = "BAD STRING"; String goodString = "GOOD STRING"; ObservableField<String> observed = new ObservableField<>(""); ObservableBoolean observing = Cinder.computeBoolean(()-> observed.get().equals(goodString),observed).filter(()->observed.get().startsWith("GOOD")); observed.set(badString); assertFalse(observing.get()); observed.set(goodString); assertTrue(observing.get()); }
@Test public void takeWhileTakesWhileTrue() throws Exception { String badString = "BAD STRING"; String goodString = "GOOD STRING"; ObservableField<String> observed = new ObservableField<>(""); ObservableBoolean observing = Cinder.computeBoolean(()-> observed.get().equals(goodString),observed).takeWhile(()->observed.get().startsWith("GOOD")); observed.set(goodString); assertTrue(observing.get()); observed.set(badString); assertTrue(observing.get()); }
@Test public void skipwhileSkipsWhileTrue() throws Exception { String badString = "BAD STRING"; String goodString = "GOOD STRING"; ObservableField<String> observed = new ObservableField<>(""); ObservableBoolean observing = Cinder.computeBoolean(()-> observed.get().equals(goodString),observed).skipwhile(()->observed.get().startsWith("BAD")); observed.set(badString); assertFalse(observing.get()); observed.set(goodString); assertTrue(observing.get()); }
@Test public void withDefaultAssignsDefault() throws Exception { ObservableBoolean observing = Cinder.computeBoolean(()->false ).withDefault(true); assertTrue(observing.get()); }
@Test public void convertsObservableBooleanToRx() throws Exception { ObservableBoolean observableBoolean = new ObservableBoolean(); Observable<Boolean> rxBoolean = RxCinder.convert(observableBoolean); final String TEST_KEY = "TEST_KEY"; final ArrayMap<String,Boolean> testMap = new ArrayMap<>(); rxBoolean.subscribe((b)->{ testMap.put(TEST_KEY,b);}); observableBoolean.set(true); assertTrue(testMap.get(TEST_KEY)); }
public Loginviewmodel(LoginInteractor interactor,ProNavigator navigator) { this.interactor = interactor; this.navigator = navigator; email = new ObservableField<>(); password = new ObservableField<>(); passwordRepeat = new ObservableField<>(); inProgress = new ObservableBoolean(); }
/** * I would like to use this in the layout expressions,but there seems to be an issue related to this. * See https://code.google.com/p/android/issues/detail?id=230115 */ public <T> void onFieldChanged(ObservableField<T> field,ObservableBoolean errorIndicator,boolean hasFocus,Validator<T> validator) { if (hasFocus) { errorIndicator.set(false); } else { T value = field.get(); errorIndicator.set(!validator.validate(value)); Log.d(TAG,"Field is invalid: " + errorIndicator.get()); dataValid.set(validateForm()); } }
private static TestObserver<Boolean> observableBooleanTestObserver(RxCommand command) { return Observe.allPropertiesOf(command.getEnabled()) .map(new Function<ObservableBoolean,Boolean>() { @Override public Boolean apply(ObservableBoolean value) throws Exception { return value.get(); } }) .test(); }
private static <T> TestObserver<Boolean> hasErrorObserver(final RxProperty<T> property) { return Observe.propertyOf(property.getHasError(),new Function<ObservableBoolean,Boolean>() { @Override public Boolean apply(ObservableBoolean value) throws Exception { return value.get(); } }) .test(); }
@Inject public StarredRepoListFragmentviewmodel(BaseFragment fragment,GetStarredReposUseCase getStarredReposUseCase,EventBus eventBus) { super(fragment); this.getStarredReposUseCase = getStarredReposUseCase; this.eventBus = eventBus; repos = new ObservableArrayList<>(); isConnecting = new ObservableBoolean(true); isRefreshing = new ObservableBoolean(false); }
@Inject public RepoListItemviewmodel(BaseFragment fragment,StarUseCase starUseCase,UnstarUseCase unstarUseCase,EventBus eventBus) { super(fragment); this.starUseCase = starUseCase; this.unstarUseCase = unstarUseCase; this.eventBus = eventBus; this.repo = new ObservableField<>(); this.starred = new ObservableBoolean(false); }
@Inject public RepoInfoFragmentviewmodel(BaseFragment fragment,GetRepoUseCase getRepoUseCase,CheckStarUseCase checkStarUseCase,EventBus eventBus) { super(fragment); this.getRepoUseCase = getRepoUseCase; this.checkStarUseCase = checkStarUseCase; this.starUseCase = starUseCase; this.unstarUseCase = unstarUseCase; this.eventBus = eventBus; this.repo = new ObservableField<>(); this.isConnecting = new ObservableBoolean(true); this.starred = new ObservableBoolean(false); }
@Inject public UserActivityviewmodel(BaseActivity activity,GetUserUseCase getUserUseCase,EventBus eventBus) { super(activity); this.getUserUseCase = getUserUseCase; this.eventBus = eventBus; this.user = new ObservableField<>(); this.isConnecting = new ObservableBoolean(true); }
@Inject public MyRepoListFragmentviewmodel(BaseFragment fragment,GetUserReposUseCase getUserReposUseCase,EventBus eventBus) { super(fragment); this.getUserReposUseCase = getUserReposUseCase; this.eventBus = eventBus; repos = new ObservableArrayList<>(); isConnecting = new ObservableBoolean(true); isRefreshing = new ObservableBoolean(false); }
public ObservableBoolean getIsFired() { return isFired; }
public void setIsFired(ObservableBoolean isFired) { this.isFired = isFired; notifyChange(); }
public ObservableBoolean getChecked() { return checked; }
public void setChecked(ObservableBoolean checked) { this.checked = checked; }
public ObservableBoolean getIsLoading() { return mIsLoading; }
public Mainviewmodel(Context context) { this.context = context; this.user = new UserBean(); this.agree = new ObservableBoolean(); }
public ObservableBoolean getAgree() { return agree; }
ObservableBooleanObservable(ObservableBoolean observableBoolean) { this.observableBoolean = observableBoolean; }
public VehicleInfo(ObservableBoolean isSelected,String logoUrl,String brand,String description) { this.isSelected = isSelected; this.logoUrl = logoUrl; this.brand = brand; this.description = description; }
/** * Default constructor. * @param mainviewmodel The parent view model. */ public Fileviewmodel(Explorerviewmodel mainviewmodel) { this.mainviewmodel = mainviewmodel; this.isSelected = new ObservableBoolean(false); }
public VehicleInfo(ObservableBoolean isSelected,String description) { this.isSelected = isSelected; this.logoUrl = logoUrl; this.brand = brand; this.description = description; }
public ObservableBoolean getIsBusy() { return isBusy; }
public Command(boolean canExecute,boolean isVisible,Action0 execute) { this.canExecute = new ObservableBoolean(canExecute); this.isVisible = new ObservableBoolean(isVisible); this.execute = execute; }
android -------- Data Binding 的使用(三)Observable
解决:databinding 中 ViewModel 数据发生改变,View 中也要改变(实时更新)
BaseObservable
在 ViewModel 中可以继承 BaseObservable
public class User extends BaseObservable {
public User(String frstName,String lastName){
this.frstName = frstName;
this.lastName = lastName;
observableArrayMap.put("zq","zhhhhh");
list.add("aaa");
list.add("bbb");
}
private String frstName;
private String lastName;
public ObservableArrayMap<String,String> observableArrayMap = new ObservableArrayMap<>();
public ObservableArrayList<String> list = new ObservableArrayList<>();
@Bindable
public String getFrstName() {
return frstName;
}
public void setFrstName(String frstName) {
this.frstName = frstName;
//刷新UI
notifyPropertyChanged(com.zhangqie.databinding.BR.frstName);
}
@Bindable
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
//全部刷新
//notifyChange();
}
}
在 set 方法里面,使用 notifyPropertyChanged 来通知 UI 刷新,notifyPropertyChanged 只会刷新具体的值,notifyChange 方法则会刷新所有的值。
BR 的域则是通过在 get 方法上加 @Bindable 生成的。
ObservableArrayMap
与 Java 的 Map 使用相同
public ObservableArrayMap<String,String> observableArrayMap = new ObservableArrayMap<>();
observableArrayMap.put("zq","zhhhhh");
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="user"
type="com.zhangqie.databinding.demo2.User" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=''@{user.observableArrayMap["zq"]}'' />
</LinearLayout>
</layout>
ObservableArrayList
与 Java 的 List 使用相同
public ObservableArrayList<String> list = new ObservableArrayList<>();
list.add("aaa");
list.add("bbb");
布局中:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=''@{user.list[0]}'' />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.list[1]}" />
Observable Fields
继承自 BaseObservable 的方法有点复杂,DataBinding 还提供了一种简单的写法 —-ObservableField 来实现数据实时刷新
public class UserObservableBean {
public ObservableInt userId = new ObservableInt();
public ObservableField<String> userName = new ObservableField<>();
public ObservableDouble userAge = new ObservableDouble();
public ObservableFloat userSex = new ObservableFloat();
}
直接把属性定义成 ObservableField 类型的,并且修饰符需要是 public final 的。
除了 ObservableField,还可以使用 ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat, ObservableDouble, ObservableParcelable。
访问值得时候,可以使用 get set 方法。
UserObservableBean userBean = new UserObservableBean();
userBean.userId.set(8);
userBean.userName.set("切切心语");
userBean.userAge.set(25);
userBean.userId.get();
userBean.userName.get();
userBean.userAge.get();
这种方式就方便多了;
Android Data Binding 系列 (二) -- Binding 与 Observer 实现原理
写在前面
上篇文章 Android Data Binding 系列 (一) -- 详细介绍与使用 介绍了 Data Binding
的基础及其用法,本文接上篇,结合 DataBindingDemo 来学习下 Data Binding
的实现。
绑定实现
Activity 在 inflate layout 时,通过 DataBindingUtil 来生成绑定,从代码看,是遍历 contentView 得到 View 数组对象,然后通过数据绑定 library 生成对应的 Binding 类,含 Views、变量、listeners 等。生成类位于 build/intermediates/classes/debug/...package.../databinding/xxx.java
下,具体如何生成这里暂不作深入。
绑定过程
- 首先,会在父类(ViewDataBinding)中实例化回调或 Handler,用于之后的绑定操作;
private static final boolean USE_CHOREOGRAPHER = SDK_INT >= 16;
if (USE_CHOREOGRAPHER) {
mChoreographer = Choreographer.getInstance();
mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
mRebindRunnable.run();
}
};
} else {
mFrameCallback = null;
mUIThreadHandler = new Handler(Looper.myLooper());
}
- 接着,通过调用
mapBindings(...)
遍历布局以获得包含 bound、includes、ID Views 的数组对象,再依次赋给对应 View
final Object[] bindings = mapBindings(bindingComponent, root, 3, sIncludes, sViewsWithIds);
this.mboundView0 = (android.widget.LinearLayout) bindings[0];
this.mboundView0.setTag(null);
- 然后,调用
invalidateAll() -> requestRebind() -> ... -> mRebindRunnable.run() -
执行 Runnable
// 用于动态重新绑定 Views
private final Runnable mRebindRunnable = new Runnable() {
@Override
public void run() {
synchronized (this) {
mPendingRebind = false;
}
.....
executePendingBindings();
}
};
- 最后,通过该 Runnable 会执行到
executePendingBindings() -> ... -> executeBindings()
,在这里会执行绑定相关操作。
@Override
protected void executeBindings() {
long dirtyFlags = 0;
synchronized(this) {
dirtyFlags = mDirtyFlags; // mDirtyFlags 变量更新的标志
mDirtyFlags = 0;
}
.....
}
设置变量 (数据对象)
普通 Java bean 对象
- 首先,通过 mDirtyFlags 标识变量 (所有变量共用)
synchronized(this) {
mDirtyFlags |= 0x1L;
}
- 然后,调用
notifyPropertyChanged(...)
来通知更新(若有回调)
public void notifyPropertyChanged(int fieldId) {
if (mCallbacks != null) {
mCallbacks.notifyCallbacks(this, fieldId, null);
}
}
- 最后,调用
requestRebind() -> ... -> executeBindings()
再次执行绑定操作,将数据更新到 Views 上
@Override
protected void executeBindings() {
long dirtyFlags = 0;
synchronized(this) {
dirtyFlags = mDirtyFlags;
mDirtyFlags = 0;
}
.....
}
Observable 对象
- 在设置变量时,会先调用
updateRegistration(..)
注册一个 Observable 对象的监听
public void setContact(com.connorlin.databinding.model.ObservableContact contact) {
updateRegistration(0, contact);
this.mContact = contact;
synchronized(this) {
mDirtyFlags |= 0x1L;
}
notifyPropertyChanged(BR.contact);
super.requestRebind();
}
- 其他步骤同普通 Java bean 对象
ObservableFields 对象
-
前期步骤同普通 Java Bean 对象
-
与 Observable 对象不同的是,Observable 对象的监听是在
executeBindings()
中注册的
@Override
protected void executeBindings() {
long dirtyFlags = 0;
synchronized(this) {
dirtyFlags = mDirtyFlags;
mDirtyFlags = 0;
}
...
if ((dirtyFlags & 0xfL) != 0) {
if ((dirtyFlags & 0xdL) != 0) {
if (contact != null) {
// read contact.mName
mNameContact = contact.mName;
}
updateRegistration(0, mNameContact);
if (mNameContact != null) {
// read contact.mName.get()
mNameContact1 = mNameContact.get();
}
}
...
}
...
}
注册 Observable 对象监听
- 入口
updateRegistration(0, contact)
:
protected boolean updateRegistration(int localFieldId, Observable observable) {
return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER);
}
private boolean updateRegistration(int localFieldId, Object observable,
CreateWeakListener listenerCreator) {
...
// 确保不重复监听,先移除再添加观察监听
unregisterFrom(localFieldId);
registerTo(localFieldId, observable, listenerCreator);
return true;
}
protected void registerTo(int localFieldId, Object observable,
CreateWeakListener listenerCreator) {
if (observable == null) {
return;
}
// 创建对象监听并存到mLocalFieldObservers中
WeakListener listener = mLocalFieldObservers[localFieldId];
if (listener == null) {
// CREATE_PROPERTY_LISTENER -> create(...)
listener = listenerCreator.create(this, localFieldId);
mLocalFieldObservers[localFieldId] = listener;
}
// 将监听绑定到Observable对象上
listener.setTarget(observable);
}
每个 Observable 对象都会添加一个观察监听,保存在数组 mLocalFieldObservers
中,并以 localFieldId
索引。
- CREATE_PROPERTY_LISTENER 为何物?
private static final CreateWeakListener CREATE_PROPERTY_LISTENER = new CreateWeakListener() {
@Override
public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {
// 返回从WeakPropertyListener实例中获取的监听器(WeakListener)
return new WeakPropertyListener(viewDataBinding, localFieldId).getListener();
}
}
private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
implements ObservableReference<Observable> {
final WeakListener<Observable> mListener;
public WeakPropertyListener(ViewDataBinding binder, int localFieldId) {
mListener = new WeakListener<Observable>(binder, localFieldId, this);
}
@Override
public WeakListener<Observable> getListener() {
return mListener;
}
@Override
public void addListener(Observable target) {
// WeakPropertyListener 继承于 Observable.OnPropertyChangedCallback,
// 所以 this 其实就是 Observable对象的属性监听器
target.addOnPropertyChangedCallback(this);
}
...
}
private static class WeakListener<T> extends WeakReference<ViewDataBinding> {
private final ObservableReference<T> mObservable;
protected final int mLocalFieldId;
private T mTarget;
...
public void setTarget(T object) {
unregister();
mTarget = object;
if (mTarget != null) {
// mObservable 是上面的 WeakPropertyListener对象
// mTarget 是绑定到listener上得Observable对象
mObservable.addListener(mTarget);
}
}
...
}
CREATE_PROPERTY_LISTENER 实际上只是一个接口实例,注册时会调用它的 create()
方法创建一个弱引用 listener,它的作用是将 listener 绑定到 Observable 对象上, 绑定时,会调用 listener.setTarget(...)
将 Observable 对象传给 WeakPropertyListener
实例,然后,WeakPropertyListener
会为 Observable 对象添加 OnPropertyChangedCallback
。
- addOnPropertyChangedCallback 实现
addOnPropertyChangedCallback 在 BaseObservable 中实现,首先会实例化一个 PropertyChangeRegistry
对象,同时创建一个用来通知 Observable 对象重新绑定更新的回调 CallbackRegistry.NotifierCallback
。然后将 OnPropertyChangedCallback
添加到 PropertyChangeRegistry 的回调列表中
@Override
public synchronized void addOnPropertyChangedCallback(OnPropertyChangedCallback callback) {
if (mCallbacks == null) {
mCallbacks = new PropertyChangeRegistry();
}
mCallbacks.add(callback);
}
这样,注册 Observable 对象的监听就完毕了。
更新 (重新绑定) Observable 对象
设置或更新 Observable 对象时都会调用 notifyPropertyChanged()
或 notifyChange()
来通知更新,那到底是如何更新的呢?
- 回调过程
public void notifyPropertyChanged(int fieldId) {
// mCallbacks 是 PropertyChangeRegistry对象,在 addOnPropertyChangedCallback 时实例化
// 如果注册了Observable对象监听,那么mCallbacks不为null
if (mCallbacks != null) {
mCallbacks.notifyCallbacks(this, fieldId, null);
}
}
// baseLibrary
private void notifyCallbacks(T sender, int arg, A arg2, int startIndex, int endIndex, long bits) {
long bitMask = 1L;
for(int i = startIndex; i < endIndex; ++i) {
if((bits & bitMask) == 0L) {
// mNotifier 是实例化PropertyChangeRegistry时创建的
// mNotifier 即 CallbackRegistry.NotifierCallback
this.mNotifier.onNotifyCallback(this.mCallbacks.get(i), sender, arg, arg2);
}
bitMask <<= 1;
}
}
// PropertyChangeRegistry.NOTIFIER_CALLBACK
public void onNotifyCallback(Observable.OnPropertyChangedCallback callback, Observable sender,
int arg, Void notUsed) {
// callback 是为Observable对象添加的OnPropertyChangedCallback,即WeakPropertyListener
callback.onPropertyChanged(sender, arg);
}
// WeakPropertyListener
public void onPropertyChanged(Observable sender, int propertyId) {
// binder 即生成的Binding类对象
ViewDataBinding binder = mListener.getBinder();
...
binder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId);
}
private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {
// onFieldChange 实现在生成的Binding类中
boolean result = onFieldChange(mLocalFieldId, object, fieldId);
if (result) {
// 如果对象属性变化,将重新绑定
requestRebind();
}
}
通过 notifyPropertyChanged 调用到 mNotifier 回调, mNotifier 通知 OnPropertyChangedCallback
Observable 对象属性发生变化,然后在 onPropertyChanged
中又转给 ViewDataBinding 对象 (生成的 Binding 类) 处理。
- 判断是否需要重新绑定并执行,在生成的 Binding 类中实现
// 生成的Binding类中得方法
protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {
// 如果变量不是Observable类型或没有添加 Bindable注解,就不会判断,直接返回false
switch (localFieldId) {
case 0 :
return onChangeContact((com.connorlin.databinding.model.ObservableContact) object, fieldId);
}
return false;
}
private boolean onChangeContact(com.connorlin.databinding.model.ObservableContact contact, int fieldId) {
switch (fieldId) {
case BR.name: {
synchronized(this) {
mDirtyFlags |= 0x4L;// 通过mDirtyFlags判断对象是否变化
}
return true;
}
...
}
return false;
}
至此,更新过程完毕。
整个注册与更新过程可以用一张流程图来概括:
事件处理
事件处理的原理很简单,在生成 Binding 类中会实现 View 事件的监听,在构造时实例化 View 的事件监听,然后在绑定时将事件监听对象赋值给对应 View,这样,点击时就会触发相应的监听。
这里以 DataBindingDemo 中 EventActivity
部分为例:
- 生成的 Binding 类并实现 View 的事件监听
public class ActivityEventBinding extends android.databinding.ViewDataBinding
implements android.databinding.generated.callback.OnCheckedChangeListener.Listener,
android.databinding.generated.callback.OnClickListener.Listener {
// Checkbox check监听
private final android.widget.CompoundButton.OnCheckedChangeListener mCallback3;
private final android.view.View.OnClickListener mCallback2;
private final android.view.View.OnClickListener mCallback1;
// listeners
private OnClickListenerImpl mAndroidViewViewOnCl;
...
// Listener Stub Implementations
public static class OnClickListenerImpl implements android.view.View.OnClickListener{
private com.connorlin.databinding.handler.EventHandler value;
public OnClickListenerImpl setValue(com.connorlin.databinding.handler.EventHandler value) {
this.value = value;
return value == null ? null : this;
}
@Override
public void onClick(android.view.View arg0) {
this.value.onClickFriend(arg0);
}
}
...
}
- 实例化 View 的事件监听
public ActivityEventBinding(android.databinding.DataBindingComponent bindingComponent, View root) {
super(bindingComponent, root, 0);
...
// listeners
mCallback3 = new android.databinding.generated.callback.OnCheckedChangeListener(this, 3);
mCallback2 = new android.databinding.generated.callback.OnClickListener(this, 2);
mCallback1 = new android.databinding.generated.callback.OnClickListener(this, 1);
invalidateAll();
}
- 在执行绑定中绑定 View 事件监听
@Override
protected void executeBindings() {
...
if ((dirtyFlags & 0x6L) != 0) {
if (handler != null) {
// read handler::onClickFriend
androidViewViewOnCli = (((mAndroidViewViewOnCl == null)
? (mAndroidViewViewOnCl = new OnClickListenerImpl()) : mAndroidViewViewOnCl).setValue(handler));
}
}
// batch finished
if ((dirtyFlags & 0x6L) != 0) {
this.mboundView1.setOnClickListener(androidViewViewOnCli);
}
if ((dirtyFlags & 0x4L) != 0) {
this.mboundView2.setOnClickListener(mCallback1);
this.mboundView3.setOnClickListener(mCallback2);
android.databinding.adapters.CompoundButtonBindingAdapter.setListeners(
this.mboundView4, mCallback3, (android.databinding.InverseBindingListener)null);
}
}
- 触发事件并执行
ViewStub
原理类似,只是利用 ViewStubProxy
来延迟绑定。
- 使用 layout 中的 ViewStub 实例化一个 ViewStubProxy 对象赋给 viewstub 变量,并与 Bingding 关联
public ActivityViewStubBinding(android.databinding.DataBindingComponent bindingComponent, View root) {
super(bindingComponent, root, 0);
final Object[] bindings = mapBindings(bindingComponent, root, 2, sIncludes, sViewsWithIds);
...
this.viewStub = new android.databinding.ViewStubProxy((android.view.ViewStub) bindings[1]);
this.viewStub.setContainingBinding(this);
...
}
- 实例化 ViewStubProxy 的同时会注册 inflate 监听
private OnInflateListener mProxyListener = new OnInflateListener() {
@Override
public void onInflate(ViewStub stub, View inflated) {
mRoot = inflated;
mViewDataBinding = DataBindingUtil.bind(mContainingBinding.mBindingComponent,
inflated, stub.getLayoutResource());
mViewStub = null;
if (mOnInflateListener != null) {
mOnInflateListener.onInflate(stub, inflated);
mOnInflateListener = null;
}
mContainingBinding.invalidateAll();
mContainingBinding.forceExecuteBindings();
}
};
public ViewStubProxy(ViewStub viewStub) {
mViewStub = viewStub;
mViewStub.setOnInflateListener(mProxyListener);
}
- inflate ViewStub
if (!mActivityViewStubBinding.viewStub.isInflated()) {
mActivityViewStubBinding.viewStub.getViewStub().inflate();
}
当 ViewStub infate 时,执行 mProxyListener
,其中会生成 ViewStub 的 Binding,并强制执行主 Binding 重绑
- 绑定 ViewStub
@Override
protected void executeBindings() {
long dirtyFlags = 0;
synchronized(this) {
dirtyFlags = mDirtyFlags;
mDirtyFlags = 0;
}
// batch finished
if (viewStub.getBinding() != null) {
viewStub.getBinding().executePendingBindings();
}
}
这样,ViewStub 绑定就结束了。
本篇完,敬请期待下篇...
我的简书账号是 ConnorLin,欢迎关注!
我的简书专题是 Android 开发技术分享,欢迎关注!
我的个人博客 欢迎关注!
原创文章,欢迎转载,转载请注明出处!
欢迎您扫一扫上面的微信公众号,订阅我的博客!
Android Studio 4.0.1:构建失败:不建议使用“ android.databinding.enableV2”选项
从gradle.properties
中删除这些行:
android.enableExperimentalFeatureDatabinding=false
android.databinding.enableV2=false
并修复您正确添加它们的原因(“无法猜测” ...)。另请参见是否另一个模块可能不使用选项android.databinding.enableV2
并尝试手动删除构建缓存并构建目录一次。更新IDE只会更新Gradle插件版本,它当然不会改变其他任何东西。如果您有这样的担忧,则可能应该使用某种版本控制系统,该系统以diff
的形式显示所有更改(这还提供了无限的撤消功能和许多其他有用的功能); Android Studio支持不带插件的功能。
问题在于该行:
android.databinding.enableV2 = false
必须从我的 HOME 目录中的gradle-properties文件中删除。在MAC上,它位于此处:
〜/ .gradle
android – Observable返回类型必须参数化为Observable或Observable
我正在使用改造2.0.0-beta2并且调试版本正常工作但我在使用Proguard进行发布版本时遇到以下错误.
这是更新的logcat错误.
11-17 18:23:22.751 16274-16274/ph.reggis.FEDT D/AndroidRuntime: Shutting down VM
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: FATAL EXCEPTION: main
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: Process: ph.reggis.FEDT,PID: 16274
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: java.lang.RuntimeException: Unable to resume activity {ph.reggis.FEDT/ph.reggis.FEDT.view.activity.NotificationListActivity}: java.lang.IllegalArgumentException: Unable to create call adapter for class b.a
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: for method InsularFMService.getNews
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3103)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3134)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2481)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at android.app.ActivityThread.-wrap11(ActivityThread.java)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:102)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at android.os.Looper.loop(Looper.java:148)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5417)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: Caused by: java.lang.IllegalArgumentException: Unable to create call adapter for class b.a
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: for method InsularFMService.getNews
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at retrofit.Utils.methodError(UnkNown Source)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at retrofit.MethodHandler.createCallAdapter(UnkNown Source)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at retrofit.MethodHandler.create(UnkNown Source)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at retrofit.Retrofit.loadMethodHandler(UnkNown Source)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at retrofit.Retrofit$1.invoke(UnkNown Source)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at java.lang.reflect.Proxy.invoke(Proxy.java:393)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at $Proxy0.getNews(UnkNown Source)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at ph.reggis.FEDT.b.C.d(UnkNown Source)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at ph.reggis.FEDT.view.fragment.NotificationListFragment.t(UnkNown Source)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at ph.reggis.FEDT.view.fragment.NotificationListFragment.l(UnkNown Source)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at android.support.v4.b.B.a(UnkNown Source)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at android.support.v4.b.B.a(UnkNown Source)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at android.support.v4.b.B.a(UnkNown Source)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at android.support.v4.b.B.i(UnkNown Source)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at android.support.v4.b.y.i(UnkNown Source)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at android.support.v4.b.t.onPostResume(UnkNown Source)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at android.support.v7.a.B.onPostResume(UnkNown Source)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at android.app.Activity.performResume(Activity.java:6336)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3092)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: Caused by: java.lang.IllegalStateException: Observable return type must be parameterized as ObservableNown Source)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at retrofit.Retrofit.nextCallAdapter(UnkNown Source)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: at retrofit.Retrofit.callAdapter(UnkNown Source)
11-17 18:23:22.752 16274-16274/ph.reggis.FEDT E/AndroidRuntime: ... 28 more
接口:
@GET("news")
Observable
分段:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constant.WS_URL_BASE)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
InsularFMService fmService = retrofit.create(InsularFMService.class);
//Observable
Graddle:
compile "com.squareup.retrofit:retrofit:2.0.0-beta2"
compile "com.squareup.retrofit:converter-gson:2.0.0-beta2"
compile "com.squareup.retrofit:adapter-rxjava:2.0.0-beta2"
Proguard的:
# Fixed: Caused by: java.lang.NoSuchFieldException: No field producerIndex
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
long producerIndex;
long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
long producerNode;
long consumerNode;
}
最佳答案
现在它正在将这些属性放在Proguard中.
# Application classes that will be serialized/deserialized over Gson
-keep class ph.reggis.FEDT.model.api.** { *; }
这是完整的设置
##---------------Begin: proguard configuration for Gson ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default,so configure it to keep all of it.
-keepattributes Signature
-keepattributes *Annotation*
# Gson specific classes
-keep class sun.misc.Unsafe { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class ph.reggis.FEDT.model.api.** { *; }
##---------------End: proguard configuration for Gson ----------
今天的关于android.databinding.ObservableBoolean的实例源码和android data obb的分享已经结束,谢谢您的关注,如果想了解更多关于android -------- Data Binding 的使用(三)Observable、Android Data Binding 系列 (二) -- Binding 与 Observer 实现原理、Android Studio 4.0.1:构建失败:不建议使用“ android.databinding.enableV2”选项、android – Observable返回类型必须参数化为Observable或Observable的相关知识,请在本站进行查询。
本文标签: