Added Bindable annotation processor.

Change-Id: I17d4109f9d974d46474b9ac1fba4d303f232b097
This commit is contained in:
George Mount
2014-12-16 09:35:35 -08:00
parent fea204447b
commit 4e84d3dea3
15 changed files with 713 additions and 180 deletions

124
KDataBinder/.idea/uiDesigner.xml generated Normal file
View File

@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

View File

@@ -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'
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);}
}

View File

@@ -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.
*
* <p>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.</p>
*
* <p>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, <code>A</code> should be some kind of containing structure that
* the subclass may reuse between notifications.</p>
*
* @param <C> The callback type.
* @param <T> The notification sender type. Typically this is the containing class.
*/
public class CallbackRegistry<C, T> implements Cloneable {
private static final String TAG = "CallbackRegistry";
/** An ordered collection of listeners waiting to be notified. */
private List<C> mCallbacks = new ArrayList<C>();
/**
* 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<C, T> mNotifier;
/**
* Creates an EventRegistry that notifies the event with notifier.
* @param notifier The class to use to notify events.
*/
public CallbackRegistry(NotifierCallback<C, T> 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 <code>removed</code>.
*
* @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)}.
*
* <p>Recursion is used to avoid allocating temporary state on the heap.</p>
*
* @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<C> copyListeners() {
ArrayList<C> callbacks = new ArrayList<C>(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<C, T> clone() {
CallbackRegistry<C, T> clone = null;
try {
clone = (CallbackRegistry<C, T>) super.clone();
clone.mFirst64Removed = 0;
clone.mRemainderRemoved = null;
clone.mNotificationLevel = 0;
clone.mCallbacks = new ArrayList<C>();
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 <C> The callback type.
* @param <T> The notification sender type. Typically this is the containing class.
*/
public abstract static class NotifierCallback<C, T> {
/**
* 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);
}
}

View File

@@ -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<OnPropertyChangedListener, Observable> {
private static final CallbackRegistry.NotifierCallback<OnPropertyChangedListener, Observable> NOTIFIER_CALLBACK = new CallbackRegistry.NotifierCallback<OnPropertyChangedListener, Observable>() {
@Override
public void onNotifyCallback(OnPropertyChangedListener callback, Observable sender,
int arg) {
callback.onPropertyChanged(arg);
}
};
public ChangeListenerRegistry() {
super(NOTIFIER_CALLBACK);
}
}

View File

@@ -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);
}

View File

@@ -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<ObservableListener> mListeners;
public ObservableHelper(Observable owner) {
this.owner = owner;
}
private synchronized CopyOnWriteArraySet<ObservableListener> 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<ObservableListener> 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<ObservableListener> listeners = getListeners(false);
if (listener != null) {
listeners.remove(listener);
}
}
}

View File

@@ -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);
}

View File

@@ -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<Observable> 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 ?

View File

@@ -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'
}

View File

@@ -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<ListItemBinder> implements View.OnClickListener, Observable {
List<User> userList = new ArrayList<>();
ObservableHelper mHelper;
List<User> userList = new ArrayList<User>();
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);
}
}
}

View File

@@ -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() {

View File

@@ -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

View File

@@ -1,4 +1,4 @@
include ':library'
include ':library', ':annotationprocessor'
include ':compiler'
include ':gradlePlugin'
include ':grammerBuilder'
include ':grammerBuilder'