diff --git a/KDataBinder/.idea/uiDesigner.xml b/KDataBinder/.idea/uiDesigner.xml new file mode 100644 index 0000000000000..e96534fb27b68 --- /dev/null +++ b/KDataBinder/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/data-binding/annotationprocessor/build.gradle b/tools/data-binding/annotationprocessor/build.gradle new file mode 100644 index 0000000000000..19c563def5142 --- /dev/null +++ b/tools/data-binding/annotationprocessor/build.gradle @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +apply plugin: 'java' +apply plugin: 'maven' + +buildscript { + repositories { + mavenLocal() + mavenCentral() + } +} + +repositories { + mavenCentral() +} + +sourceSets { + main { + java { + srcDir 'src/main/java' + } + } +} + +uploadArchives { + repositories { + mavenDeployer { + repository(url: mavenLocal().url) + pom.version = '0.1-SNAPSHOT' + pom.artifactId = 'annotationprocessor' + pom.groupId='com.android.databinding' + } + } +} diff --git a/tools/data-binding/library/src/main/java/com/android/databinding/library/AbsObservable.java b/tools/data-binding/library/src/main/java/com/android/databinding/library/AbsObservable.java new file mode 100644 index 0000000000000..9a2f4386f36f8 --- /dev/null +++ b/tools/data-binding/library/src/main/java/com/android/databinding/library/AbsObservable.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.databinding.library; + +public abstract class AbsObservable implements Observable { + private ChangeListenerRegistry mCallbacks; + + public AbsObservable() { + } + + @Override + public synchronized void addListener(OnPropertyChangedListener listener) { + if (mCallbacks == null) { + mCallbacks = new ChangeListenerRegistry(); + } + mCallbacks.add(listener); + } + + @Override + public synchronized void removeListener(OnPropertyChangedListener listener) { + if (mCallbacks != null) { + mCallbacks.remove(listener); + } + } + + public synchronized void notifyChange() { + if (mCallbacks != null) { + mCallbacks.notifyCallbacks(this, 0); + } + } + + public synchronized void notifyChange(int id) { + if (mCallbacks != null) { + mCallbacks.notifyCallbacks(this, id); + } + } +} diff --git a/tools/data-binding/library/src/main/java/com/android/databinding/library/BaseObservable.java b/tools/data-binding/library/src/main/java/com/android/databinding/library/BaseObservable.java deleted file mode 100644 index 30c4a743122ee..0000000000000 --- a/tools/data-binding/library/src/main/java/com/android/databinding/library/BaseObservable.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.databinding.library; - -import java.util.concurrent.CopyOnWriteArraySet; - -public class BaseObservable implements Observable { - final ObservableHelper mHelper; - - public BaseObservable() { - mHelper = new ObservableHelper(this); - } - - @Override - public void register(ObservableListener listener) { - mHelper.register(listener); - } - - @Override - public void unRegister(ObservableListener listener) { - mHelper.unRegister(listener); - } - - public void fireChange() { - mHelper.fireChange(); - } - public void fireChange(String fieldName) { - mHelper.fireChange(fieldName); - } - public void fireChange(int fieldId) {mHelper.fireChange(fieldId);} -} diff --git a/tools/data-binding/library/src/main/java/com/android/databinding/library/CallbackRegistry.java b/tools/data-binding/library/src/main/java/com/android/databinding/library/CallbackRegistry.java new file mode 100644 index 0000000000000..820561f045c6c --- /dev/null +++ b/tools/data-binding/library/src/main/java/com/android/databinding/library/CallbackRegistry.java @@ -0,0 +1,395 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.databinding.library; + +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +/** + * Tracks callbacks for the event. This class supports reentrant modification + * of the callbacks during notification without adversely disrupting notifications. + * A common pattern for callbacks is to receive a notification and then remove + * themselves. This class handles this behavior with constant memory under + * most circumstances. + * + *

A subclass of {@link com.android.databinding.library.CallbackRegistry.NotifierCallback} must be passed to + * the constructor to define how notifications should be called. That implementation + * does the actual notification on the listener.

+ * + *

This class supports only callbacks with at most two parameters. + * Typically, these are the notification originator and a parameter, but these may + * be used as required. If more than two parameters are required or primitive types + * must be used, A should be some kind of containing structure that + * the subclass may reuse between notifications.

+ * + * @param The callback type. + * @param The notification sender type. Typically this is the containing class. + */ +public class CallbackRegistry implements Cloneable { + private static final String TAG = "CallbackRegistry"; + + /** An ordered collection of listeners waiting to be notified. */ + private List mCallbacks = new ArrayList(); + + /** + * A bit flag for the first 64 listeners that are removed during notification. + * The lowest significant bit corresponds to the 0th index into mCallbacks. + * For a small number of callbacks, no additional array of objects needs to + * be allocated. + */ + private long mFirst64Removed = 0x0; + + /** + * Bit flags for the remaining callbacks that are removed during notification. + * When there are more than 64 callbacks and one is marked for removal, a dynamic + * array of bits are allocated for the callbacks. + */ + private long[] mRemainderRemoved; + + /** The recursion level of the notification */ + private int mNotificationLevel; + + /** The notification mechanism for notifying an event. */ + private final NotifierCallback mNotifier; + + /** + * Creates an EventRegistry that notifies the event with notifier. + * @param notifier The class to use to notify events. + */ + public CallbackRegistry(NotifierCallback notifier) { + mNotifier = notifier; + } + + /** + * Notify all callbacks. + * + * @param sender The originator. This is an opaque parameter passed to + * {@link com.android.databinding.library.CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int)} + * @param arg An opaque parameter passed to + * {@link com.android.databinding.library.CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int)} + */ + public synchronized void notifyCallbacks(T sender, int arg) { + mNotificationLevel++; + notifyRecurse(sender, arg); + mNotificationLevel--; + if (mNotificationLevel == 0) { + if (mRemainderRemoved != null) { + for (int i = mRemainderRemoved.length - 1; i >= 0; i--) { + final long removedBits = mRemainderRemoved[i]; + if (removedBits != 0) { + removeRemovedCallbacks((i + 1) * Long.SIZE, removedBits); + mRemainderRemoved[i] = 0; + } + } + } + if (mFirst64Removed != 0) { + removeRemovedCallbacks(0, mFirst64Removed); + mFirst64Removed = 0; + } + } + } + + /** + * Notify up to the first Long.SIZE callbacks that don't have a bit set in removed. + * + * @param sender The originator. This is an opaque parameter passed to + * {@link com.android.databinding.library.CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int)} + * @param arg An opaque parameter passed to + * {@link com.android.databinding.library.CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int)} + */ + private void notifyFirst64(T sender, int arg) { + final int maxNotified = Math.min(Long.SIZE, mCallbacks.size()); + notifyCallbacks(sender, arg, 0, maxNotified, mFirst64Removed); + } + + /** + * Notify all callbacks using a recursive algorithm to avoid allocating on the heap. + * This part captures the callbacks beyond Long.SIZE that have no bits allocated for + * removal before it recurses into {@link #notifyRemainder(Object, int, int)}. + * + *

Recursion is used to avoid allocating temporary state on the heap.

+ * + * @param sender The originator. This is an opaque parameter passed to + * {@link com.android.databinding.library.CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int)} + * @param arg An opaque parameter passed to + * {@link com.android.databinding.library.CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int)} + */ + private void notifyRecurse(T sender, int arg) { + final int callbackCount = mCallbacks.size(); + final int remainderIndex = mRemainderRemoved == null ? -1 : mRemainderRemoved.length - 1; + + // Now we've got all callbakcs that have no mRemainderRemoved value, so notify the + // others. + notifyRemainder(sender, arg, remainderIndex); + + // notifyRemainder notifies all at maxIndex, so we'd normally start at maxIndex + 1 + // However, we must also keep track of those in mFirst64Removed, so we add 2 instead: + final int startCallbackIndex = (remainderIndex + 2) * Long.SIZE; + + // The remaining have no bit set + notifyCallbacks(sender, arg, startCallbackIndex, callbackCount, 0); + } + + /** + * Notify callbacks that have mRemainderRemoved bits set for remainderIndex. If + * remainderIndex is -1, the first 64 will be notified instead. + * + * @param sender The originator. This is an opaque parameter passed to + * {@link com.android.databinding.library.CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int)} + * @param arg An opaque parameter passed to + * {@link com.android.databinding.library.CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int)} + * @param remainderIndex The index into mRemainderRemoved that should be notified. + */ + private void notifyRemainder(T sender, int arg, int remainderIndex) { + if (remainderIndex < 0) { + notifyFirst64(sender, arg); + } else { + final long bits = mRemainderRemoved[remainderIndex]; + final int startIndex = (remainderIndex + 1) * Long.SIZE; + final int endIndex = Math.min(mCallbacks.size(), startIndex + Long.SIZE); + notifyRemainder(sender, arg, remainderIndex - 1); + notifyCallbacks(sender, arg, startIndex, endIndex, bits); + } + } + + /** + * Notify callbacks from startIndex to endIndex, using bits as the bit status + * for whether they have been removed or not. bits should be from mRemainderRemoved or + * mFirst64Removed. bits set to 0 indicates that all callbacks from startIndex to + * endIndex should be notified. + * + * @param sender The originator. This is an opaque parameter passed to + * {@link com.android.databinding.library.CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int)} + * @param arg An opaque parameter passed to + * {@link com.android.databinding.library.CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int)} + * @param startIndex The index into the mCallbacks to start notifying. + * @param endIndex One past the last index into mCallbacks to notify. + * @param bits A bit field indicating which callbacks have been removed and shouldn't + * be notified. + */ + private void notifyCallbacks(T sender, int arg, final int startIndex, final int endIndex, + final long bits) { + long bitMask = 1; + for (int i = startIndex; i < endIndex; i++) { + if ((bits & bitMask) == 0) { + mNotifier.onNotifyCallback(mCallbacks.get(i), sender, arg); + } + bitMask <<= 1; + } + } + + /** + * Add a callback to be notified. If the callback is already in the list, another won't + * be added. This does not affect current notifications. + * @param callback The callback to add. + */ + public synchronized void add(C callback) { + int index = mCallbacks.lastIndexOf(callback); + if (index < 0 || isRemoved(index)) { + mCallbacks.add(callback); + } + } + + /** + * Returns true if the callback at index has been marked for removal. + * + * @param index The index into mCallbacks to check. + * @return true if the callback at index has been marked for removal. + */ + private boolean isRemoved(int index) { + if (index < Long.SIZE) { + // It is in the first 64 callbacks, just check the bit. + final long bitMask = 1L << index; + return (mFirst64Removed & bitMask) != 0; + } else if (mRemainderRemoved == null) { + // It is after the first 64 callbacks, but nothing else was marked for removal. + return false; + } else { + final int maskIndex = (index / Long.SIZE) - 1; + if (maskIndex >= mRemainderRemoved.length) { + // There are some items in mRemainderRemoved, but nothing at the given index. + return false; + } else { + // There is something marked for removal, so we have to check the bit. + final long bits = mRemainderRemoved[maskIndex]; + final long bitMask = 1L << (index % Long.SIZE); + return (bits & bitMask) != 0; + } + } + } + + /** + * Removes callbacks from startIndex to startIndex + Long.SIZE, based + * on the bits set in removed. + * @param startIndex The index into the mCallbacks to start removing callbacks. + * @param removed The bits indicating removal, where each bit is set for one callback + * to be removed. + */ + private void removeRemovedCallbacks(int startIndex, long removed) { + // The naive approach should be fine. There may be a better bit-twiddling approach. + final int endIndex = startIndex + Long.SIZE; + + long bitMask = 1L << (Long.SIZE - 1); + for (int i = endIndex - 1; i >= startIndex; i--) { + if ((removed & bitMask) != 0) { + mCallbacks.remove(i); + } + bitMask >>>= 1; + } + } + + /** + * Remove a callback. This callback won't be notified after this call completes. + * @param callback The callback to remove. + */ + public synchronized void remove(C callback) { + if (mNotificationLevel == 0) { + mCallbacks.remove(callback); + } else { + int index = mCallbacks.lastIndexOf(callback); + if (index >= 0) { + setRemovalBit(index); + } + } + } + + private void setRemovalBit(int index) { + if (index < Long.SIZE) { + // It is in the first 64 callbacks, just check the bit. + final long bitMask = 1L << index; + mFirst64Removed |= bitMask; + } else { + final int remainderIndex = (index / Long.SIZE) - 1; + if (mRemainderRemoved == null) { + mRemainderRemoved = new long[mCallbacks.size() / Long.SIZE]; + } else if (mRemainderRemoved.length < remainderIndex) { + // need to make it bigger + long[] newRemainders = new long[mCallbacks.size() / Long.SIZE]; + System.arraycopy(mRemainderRemoved, 0, newRemainders, 0, mRemainderRemoved.length); + mRemainderRemoved = newRemainders; + } + final long bitMask = 1L << (index % Long.SIZE); + mRemainderRemoved[remainderIndex] |= bitMask; + } + } + + /* + private void clearRemovalBit(int index) { + if (index < Long.SIZE) { + // It is in the first 64 callbacks, just check the bit. + final long bitMask = 1L << index; + mFirst64Removed &= ~bitMask; + } else if (mRemainderRemoved != null) { + final int maskIndex = (index / Long.SIZE) - 1; + if (maskIndex < mRemainderRemoved.length) { + // There is something marked for removal, so we have to check the bit. + final long bitMask = 1L << (index % Long.SIZE); + mRemainderRemoved[maskIndex] &= ~bitMask; + } + } + } + */ + + /** + * Makes a copy of the registered callbacks and returns it. + * + * @return a copy of the registered callbacks. + */ + public synchronized ArrayList copyListeners() { + ArrayList callbacks = new ArrayList(mCallbacks.size()); + int numListeners = mCallbacks.size(); + for (int i = 0; i < numListeners; i++) { + if (!isRemoved(i)) { + callbacks.add(mCallbacks.get(i)); + } + } + return callbacks; + } + + /** + * Returns true if there are no registered callbacks or false otherwise. + * + * @return true if there are no registered callbacks or false otherwise. + */ + public synchronized boolean isEmpty() { + if (mCallbacks.isEmpty()) { + return true; + } else if (mNotificationLevel == 0) { + return false; + } else { + int numListeners = mCallbacks.size(); + for (int i = 0; i < numListeners; i++) { + if (!isRemoved(i)) { + return false; + } + } + return true; + } + } + + /** + * Removes all callbacks from the list. + */ + public synchronized void clear() { + if (mNotificationLevel == 0) { + mCallbacks.clear(); + } else if (!mCallbacks.isEmpty()) { + for (int i = mCallbacks.size() - 1; i >= 0; i--) { + setRemovalBit(i); + } + } + } + + public synchronized CallbackRegistry clone() { + CallbackRegistry clone = null; + try { + clone = (CallbackRegistry) super.clone(); + clone.mFirst64Removed = 0; + clone.mRemainderRemoved = null; + clone.mNotificationLevel = 0; + clone.mCallbacks = new ArrayList(); + final int numListeners = mCallbacks.size(); + for (int i = 0; i < numListeners; i++) { + if (!isRemoved(i)) { + clone.mCallbacks.add(mCallbacks.get(i)); + } + } + } catch (CloneNotSupportedException e) { + Log.e(TAG, "Could not clone CallbackRegistry", e); + } + return clone; + } + + /** + * Class used to notify events from CallbackRegistry. + * + * @param The callback type. + * @param The notification sender type. Typically this is the containing class. + */ + public abstract static class NotifierCallback { + /** + * Used to notify the callback. + * + * @param callback The callback to notify. + * @param sender The opaque sender object. + * @param arg The opaque notification parameter. + * @see CallbackRegistry#CallbackRegistry(com.android.databinding.library.CallbackRegistry.NotifierCallback) + */ + public abstract void onNotifyCallback(C callback, T sender, int arg); + } +} diff --git a/tools/data-binding/library/src/main/java/com/android/databinding/library/ChangeListenerRegistry.java b/tools/data-binding/library/src/main/java/com/android/databinding/library/ChangeListenerRegistry.java new file mode 100644 index 0000000000000..46de74391474d --- /dev/null +++ b/tools/data-binding/library/src/main/java/com/android/databinding/library/ChangeListenerRegistry.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.databinding.library; + +/** + * Created by mount on 12/15/14. + */ +public class ChangeListenerRegistry extends + CallbackRegistry { + + private static final CallbackRegistry.NotifierCallback NOTIFIER_CALLBACK = new CallbackRegistry.NotifierCallback() { + @Override + public void onNotifyCallback(OnPropertyChangedListener callback, Observable sender, + int arg) { + callback.onPropertyChanged(arg); + } + }; + + public ChangeListenerRegistry() { + super(NOTIFIER_CALLBACK); + } +} diff --git a/tools/data-binding/library/src/main/java/com/android/databinding/library/Observable.java b/tools/data-binding/library/src/main/java/com/android/databinding/library/Observable.java index e825dd59c73a6..59ffd0e5bd463 100644 --- a/tools/data-binding/library/src/main/java/com/android/databinding/library/Observable.java +++ b/tools/data-binding/library/src/main/java/com/android/databinding/library/Observable.java @@ -17,6 +17,6 @@ package com.android.databinding.library; public interface Observable { - public void register(ObservableListener listener); - public void unRegister(ObservableListener listener); + public void addListener(OnPropertyChangedListener listener); + public void removeListener(OnPropertyChangedListener listener); } diff --git a/tools/data-binding/library/src/main/java/com/android/databinding/library/ObservableHelper.java b/tools/data-binding/library/src/main/java/com/android/databinding/library/ObservableHelper.java deleted file mode 100644 index bac5686d9a9ca..0000000000000 --- a/tools/data-binding/library/src/main/java/com/android/databinding/library/ObservableHelper.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.databinding.library; - -import java.util.concurrent.CopyOnWriteArraySet; - -public class ObservableHelper implements Observable { - final Observable owner; - CopyOnWriteArraySet mListeners; - - public ObservableHelper(Observable owner) { - this.owner = owner; - } - - private synchronized CopyOnWriteArraySet getListeners(boolean createIfMissing) { - if (mListeners == null) { - if (createIfMissing) { - mListeners = new CopyOnWriteArraySet<>(); - } - } - return mListeners; - } - - public void fireChange() { - fireChange(""); - } - public void fireChange(String fieldName) { - fireChange(DataBinder.convertToId(fieldName)); - } - public void fireChange(int fieldId) { - final CopyOnWriteArraySet listeners = getListeners(false); - if (listeners == null) { - return; - } - for (ObservableListener listener : listeners) { - listener.onChange(fieldId); - } - } - - @Override - public void register(ObservableListener listener) { - getListeners(true).add(listener); - } - - @Override - public void unRegister(ObservableListener listener) { - final CopyOnWriteArraySet listeners = getListeners(false); - if (listener != null) { - listeners.remove(listener); - } - } -} diff --git a/tools/data-binding/library/src/main/java/com/android/databinding/library/ObservableListener.java b/tools/data-binding/library/src/main/java/com/android/databinding/library/OnPropertyChangedListener.java similarity index 86% rename from tools/data-binding/library/src/main/java/com/android/databinding/library/ObservableListener.java rename to tools/data-binding/library/src/main/java/com/android/databinding/library/OnPropertyChangedListener.java index 04ccd381098f4..eab1e9cd9f1bf 100644 --- a/tools/data-binding/library/src/main/java/com/android/databinding/library/ObservableListener.java +++ b/tools/data-binding/library/src/main/java/com/android/databinding/library/OnPropertyChangedListener.java @@ -16,7 +16,6 @@ package com.android.databinding.library; -public interface ObservableListener { - public void onChange(); - public void onChange(int fieldId); +public interface OnPropertyChangedListener { + public void onPropertyChanged(int fieldId); } diff --git a/tools/data-binding/library/src/main/java/com/android/databinding/library/ViewDataBinder.java b/tools/data-binding/library/src/main/java/com/android/databinding/library/ViewDataBinder.java index f1a3bf5021132..c0ac85cb0c6e1 100644 --- a/tools/data-binding/library/src/main/java/com/android/databinding/library/ViewDataBinder.java +++ b/tools/data-binding/library/src/main/java/com/android/databinding/library/ViewDataBinder.java @@ -16,16 +16,11 @@ package com.android.databinding.library; -import android.util.SparseIntArray; import android.view.View; import java.lang.Override; import java.lang.Runnable; import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; abstract public class ViewDataBinder { WeakReferencedListener[] mLocalFieldObservers; @@ -112,7 +107,7 @@ abstract public class ViewDataBinder { listener.setTarget(observable); } - protected abstract class WeakReferencedListener implements ObservableListener { + protected abstract class WeakReferencedListener implements OnPropertyChangedListener { WeakReference mTarget; public WeakReferencedListener() { @@ -121,7 +116,7 @@ abstract public class ViewDataBinder { public void setTarget(Observable observable) { if (observable != null) { mTarget = new WeakReference<>(observable); - observable.register(this); + observable.addListener(this); } else { mTarget = null; } @@ -130,7 +125,7 @@ abstract public class ViewDataBinder { public boolean unregister() { Observable oldTarget = getTarget(); if (oldTarget != null) { - oldTarget.unRegister(this); + oldTarget.removeListener(this); } mTarget = null; return oldTarget != null; @@ -148,16 +143,7 @@ abstract public class ViewDataBinder { } @Override - public void onChange() { - Observable obj = getTarget(); - if (obj == null) { - return;//how come i live if it died ? - } - ViewDataBinder.this.handleFieldChange(mLocalFieldId, obj, 0); - } - - @Override - public void onChange(int fieldId) { + public void onPropertyChanged(int fieldId) { Observable obj = getTarget(); if (obj == null) { return;//how come i live if it died ? diff --git a/tools/data-binding/samples/BindingDemo/app/build.gradle b/tools/data-binding/samples/BindingDemo/app/build.gradle index 45e7ebebfffcb..2347998c85494 100644 --- a/tools/data-binding/samples/BindingDemo/app/build.gradle +++ b/tools/data-binding/samples/BindingDemo/app/build.gradle @@ -17,6 +17,8 @@ apply plugin: 'com.android.application' apply plugin: 'com.android.databinding' +def generatedSources = "$buildDir/generated/source/br" + android { compileSdkVersion 21 buildToolsVersion "21.1.1" @@ -38,6 +40,19 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + sourceSets { + //main.java.srcDirs += generatedSources + } +} + +android.applicationVariants.all { variant -> + variant.javaCompile.doFirst { + println "*** compile doFirst ${variant.name}" + new File(generatedSources).mkdirs() + variant.javaCompile.options.compilerArgs += [ + '-s', generatedSources + ] + } } dependencies { @@ -47,4 +62,5 @@ dependencies { compile 'com.android.support:recyclerview-v7:21.0.2' compile 'com.android.support:gridlayout-v7:21+' compile 'com.android.support:cardview-v7:21.0.2' + provided 'com.android.databinding:annotationprocessor:0.1-SNAPSHOT' } diff --git a/tools/data-binding/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/MainActivity.java b/tools/data-binding/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/MainActivity.java index 51b1c9077c34d..02f3d7bc01354 100644 --- a/tools/data-binding/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/MainActivity.java +++ b/tools/data-binding/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/MainActivity.java @@ -1,5 +1,6 @@ package com.android.example.bindingdemo; +import android.binding.Bindable; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; @@ -9,15 +10,14 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import com.android.example.bindingdemo.generated.BR; +import com.android.databinding.library.ChangeListenerRegistry; +import com.android.databinding.library.Observable; +import com.android.databinding.library.OnPropertyChangedListener; import com.android.example.bindingdemo.generated.ListItemBinder; import com.android.example.bindingdemo.generated.MainActivityBinder; import com.android.example.bindingdemo.vo.User; import com.android.example.bindingdemo.vo.Users; import com.android.databinding.library.DataBinder; -import com.android.databinding.library.Observable; -import com.android.databinding.library.ObservableHelper; -import com.android.databinding.library.ObservableListener; import java.util.ArrayList; import java.util.Arrays; @@ -28,13 +28,13 @@ public class MainActivity extends ActionBarActivity implements Observable { UserAdapter tkAdapter; UserAdapter robotAdapter; MainActivityBinder dataBinder; + @Bindable User selected; - ObservableHelper helper; + ChangeListenerRegistry mChangeListeners = new ChangeListenerRegistry(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - helper = new ObservableHelper(this); dataBinder = DataBinder.createBinder(MainActivityBinder.class, this, R.layout.main_activity, null); setContentView(dataBinder.getRoot()); dataBinder.getRobotList().setHasFixedSize(true); @@ -64,7 +64,7 @@ public class MainActivity extends ActionBarActivity implements Observable { return; } this.selected = selected; - helper.fireChange(BR.selected); + mChangeListeners.notifyCallbacks(this, android.binding.BR.selected); } public View.OnClickListener onSave = new View.OnClickListener() { @@ -130,21 +130,20 @@ public class MainActivity extends ActionBarActivity implements Observable { } @Override - public void register(ObservableListener observableListener) { - helper.register(observableListener); + public void addListener(OnPropertyChangedListener onPropertyChangedListener) { + mChangeListeners.add(onPropertyChangedListener); } @Override - public void unRegister(ObservableListener observableListener) { - helper.unRegister(observableListener); + public void removeListener(OnPropertyChangedListener onPropertyChangedListener) { + mChangeListeners.remove(onPropertyChangedListener); } public class UserAdapter extends DataBoundAdapter implements View.OnClickListener, Observable { - List userList = new ArrayList<>(); - ObservableHelper mHelper; + List userList = new ArrayList(); + ChangeListenerRegistry mChangeListeners = new ChangeListenerRegistry(); public UserAdapter(User[] toolkities) { super(R.layout.list_item, ListItemBinder.class); - mHelper = new ObservableHelper(this); userList.addAll(Arrays.asList(toolkities)); } @@ -162,6 +161,7 @@ public class MainActivity extends ActionBarActivity implements Observable { } @Override + @Bindable public int getItemCount() { return userList.size(); } @@ -172,7 +172,7 @@ public class MainActivity extends ActionBarActivity implements Observable { } userList.add(user); notifyItemInserted(userList.size() - 1); - mHelper.fireChange("itemCount"); + mChangeListeners.notifyCallbacks(this, android.binding.BR.itemCount); } public void remove(User user) { @@ -182,7 +182,7 @@ public class MainActivity extends ActionBarActivity implements Observable { } userList.remove(i); notifyItemRemoved(i); - mHelper.fireChange("itemCount"); + mChangeListeners.notifyCallbacks(this, android.binding.BR.itemCount); } @Override @@ -198,13 +198,13 @@ public class MainActivity extends ActionBarActivity implements Observable { } @Override - public void register(ObservableListener observableListener) { - mHelper.register(observableListener); + public void addListener(OnPropertyChangedListener onPropertyChangedListener) { + mChangeListeners.add(onPropertyChangedListener); } @Override - public void unRegister(ObservableListener observableListener) { - mHelper.unRegister(observableListener); + public void removeListener(OnPropertyChangedListener onPropertyChangedListener) { + mChangeListeners.remove(onPropertyChangedListener); } } } diff --git a/tools/data-binding/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/vo/User.java b/tools/data-binding/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/vo/User.java index 091dc5c3ac54e..8ea225de1f6bd 100644 --- a/tools/data-binding/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/vo/User.java +++ b/tools/data-binding/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/vo/User.java @@ -1,17 +1,23 @@ package com.android.example.bindingdemo.vo; +import android.binding.Bindable; import android.graphics.Color; -import com.android.databinding.library.BaseObservable; +import com.android.databinding.library.AbsObservable; import java.util.Objects; -public class User extends BaseObservable { +public class User extends AbsObservable { + @Bindable private String name; + @Bindable private String lastName; + @Bindable private int photoResource = 0; private int favoriteColor = Color.RED; + @Bindable private int group; + public static final int TOOLKITTY = 1; public static final int ROBOT = 2; @@ -27,7 +33,7 @@ public class User extends BaseObservable { return; } this.group = group; - fireChange("group"); + notifyChange(android.binding.BR.group); } public int getGroup() { @@ -43,7 +49,7 @@ public class User extends BaseObservable { return; } this.name = name; - fireChange("name"); + notifyChange(android.binding.BR.name); } public String getLastName() { @@ -55,7 +61,7 @@ public class User extends BaseObservable { return; } this.lastName = lastName; - fireChange("lastName"); + notifyChange(android.binding.BR.lastName); } public int getPhotoResource() { @@ -67,7 +73,7 @@ public class User extends BaseObservable { return; } this.photoResource = photoResource; - fireChange("photoResource"); + notifyChange(android.binding.BR.photoResource); } public int getFavoriteColor() { diff --git a/tools/data-binding/samples/BindingDemo/gradle/wrapper/gradle-wrapper.properties b/tools/data-binding/samples/BindingDemo/gradle/wrapper/gradle-wrapper.properties index ddbd613051deb..1d32c67555698 100644 --- a/tools/data-binding/samples/BindingDemo/gradle/wrapper/gradle-wrapper.properties +++ b/tools/data-binding/samples/BindingDemo/gradle/wrapper/gradle-wrapper.properties @@ -1,22 +1,6 @@ -# -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -#Wed Apr 10 15:27:10 PDT 2013 +#Mon Dec 15 15:24:30 PST 2014 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip diff --git a/tools/data-binding/settings.gradle b/tools/data-binding/settings.gradle index c069a5794bab5..e1f91a6bced84 100644 --- a/tools/data-binding/settings.gradle +++ b/tools/data-binding/settings.gradle @@ -1,4 +1,4 @@ -include ':library' +include ':library', ':annotationprocessor' include ':compiler' include ':gradlePlugin' -include ':grammerBuilder' \ No newline at end of file +include ':grammerBuilder'