編輯:關於Android編程
Activity在inflate layout時,通過DataBindingUtil來生成綁定,從代碼看,是遍歷contentView得到View數組對象,然後通過數據綁定library生成對應的Binding類,含Views、變量、listeners等。生成類位於
build/intermediates/classes/debug/…package…/databinding/xxx.Java下,具體如何生成這裡暫不作深入。
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" target="_blank">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; } ..... }
普通Javabean 對象
首先,通過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(); }其他步驟同普通Javabean 對象
ObservableFields 對象
前期步驟同普通JavaBean 對象@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(); } } ... } ... }
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{ final WeakListener mListener; public WeakPropertyListener(ViewDataBinding binder, int localFieldId) { mListener = new WeakListener (binder, localFieldId, this); } @Override public WeakListener getListener() { return mListener; } @Override public void addListener(Observable target) { // WeakPropertyListener 繼承於 Observable.OnPropertyChangedCallback, // 所以 this 其實就是 Observable對象的屬性監聽器 target.addOnPropertyChangedCallback(this); } ... } private static class WeakListener extends WeakReference { private final ObservableReference 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 在 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對象時都會調用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); } }觸發事件並執行
原理類似,只是利用 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綁定就結束了。
在微信的運營過程中難免會出現一些無法預料的事情,比如在朋友圈被惡評,甚至被某些別有用
一、導入*.jar包1.直接copy①復制*.jar包,粘貼到主工程目錄的libs下邊②右鍵,將此jar包設置成自己的library③然後在工程右鍵的選擇項目單擊Open
本示例以Servlet為例,演示Android與Servlet的通信。眾所周知,Android與服務器通信通常采用HTTP通信方式和Socket通信方式,而HTTP通信方
完美解決解決Android使用Zxing掃描二維碼改成豎屏後,後面的預覽畫面出現了拉伸,扭曲的情況第一步:找到com.zxing.camera包下的CameraConf