ViewDataBinding.java revision 7ff60c24c6de7ba0c674fe65a82ad4a88dab2e5d
13d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar/* 23d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * Copyright (C) 2014 The Android Open Source Project 33d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * 43d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 53d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * you may not use this file except in compliance with the License. 63d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * You may obtain a copy of the License at 73d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * 83d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 93d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * 103d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * Unless required by applicable law or agreed to in writing, software 113d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 123d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * See the License for the specific language governing permissions and 143d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * limitations under the License. 153d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar */ 163d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar 17fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountpackage android.databinding; 18fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount 19e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mountimport com.android.databinding.library.R; 20e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount 215914aa7da50a90a4c705b5be02a215499d0ad232George Mountimport android.annotation.TargetApi; 22e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mountimport android.os.Build; 234c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mountimport android.os.Build.VERSION; 244c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mountimport android.os.Build.VERSION_CODES; 2596e1c821dd446d1ed78f8ae61131550588f60a24George Mountimport android.text.TextUtils; 26e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mountimport android.util.Log; 274c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mountimport android.util.SparseIntArray; 28085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarimport android.view.View; 295914aa7da50a90a4c705b5be02a215499d0ad232George Mountimport android.view.View.OnAttachStateChangeListener; 3000da715547ee7d5d38a3b8576090ca427a94daa5George Mountimport android.view.ViewGroup; 31085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 32085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarimport java.lang.ref.WeakReference; 33085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 344c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mountpublic abstract class ViewDataBinding { 354c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 364c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 374c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Instead of directly accessing Build.VERSION.SDK_INT, generated code uses this value so that 384c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * we can test API dependent behavior. 394c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 404c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount static int SDK_INT = VERSION.SDK_INT; 414c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 424c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 434c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Prefix for android:tag on Views with binding. The root View and include tags will not have 444c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * android:tag attributes and will use ids instead. 454c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 467ff60c24c6de7ba0c674fe65a82ad4a88dab2e5dGeorge Mount public static final String BINDING_TAG_PREFIX = "binding_"; 474c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 484c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount // The length of BINDING_TAG_PREFIX prevents calling length repeatedly. 4900da715547ee7d5d38a3b8576090ca427a94daa5George Mount private static final int BINDING_NUMBER_START = BINDING_TAG_PREFIX.length(); 5000da715547ee7d5d38a3b8576090ca427a94daa5George Mount 51e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount // ICS (v 14) fixes a leak when using setTag(int, Object) 52e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount private static final boolean USE_TAG_ID = DataBinderMapper.TARGET_MIN_SDK >= 14; 53e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount 544c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 554c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Method object extracted out to attach a listener to a bound Observable object. 564c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 575cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount private static final CreateWeakListener CREATE_PROPERTY_LISTENER = new CreateWeakListener() { 585cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 594c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) { 604c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount return new WeakPropertyListener(viewDataBinding, localFieldId); 615cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 625cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount }; 635cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 644c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 654c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Method object extracted out to attach a listener to a bound ObservableList object. 664c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 675cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount private static final CreateWeakListener CREATE_LIST_LISTENER = new CreateWeakListener() { 685cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 694c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) { 704c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount return new WeakListListener(viewDataBinding, localFieldId); 715cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 725cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount }; 735cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 744c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 754c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Method object extracted out to attach a listener to a bound ObservableMap object. 764c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 775cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount private static final CreateWeakListener CREATE_MAP_LISTENER = new CreateWeakListener() { 785cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 794c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) { 804c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount return new WeakMapListener(viewDataBinding, localFieldId); 815cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 825cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount }; 835cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 845914aa7da50a90a4c705b5be02a215499d0ad232George Mount private static final OnAttachStateChangeListener ROOT_REATTACHED_LISTENER; 855914aa7da50a90a4c705b5be02a215499d0ad232George Mount 865914aa7da50a90a4c705b5be02a215499d0ad232George Mount static { 875914aa7da50a90a4c705b5be02a215499d0ad232George Mount if (VERSION.SDK_INT < VERSION_CODES.KITKAT) { 885914aa7da50a90a4c705b5be02a215499d0ad232George Mount ROOT_REATTACHED_LISTENER = null; 895914aa7da50a90a4c705b5be02a215499d0ad232George Mount } else { 905914aa7da50a90a4c705b5be02a215499d0ad232George Mount ROOT_REATTACHED_LISTENER = new OnAttachStateChangeListener() { 915914aa7da50a90a4c705b5be02a215499d0ad232George Mount @TargetApi(VERSION_CODES.KITKAT) 925914aa7da50a90a4c705b5be02a215499d0ad232George Mount @Override 935914aa7da50a90a4c705b5be02a215499d0ad232George Mount public void onViewAttachedToWindow(View v) { 945914aa7da50a90a4c705b5be02a215499d0ad232George Mount // execute the pending bindings. 95e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount final ViewDataBinding binding; 96e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount if (USE_TAG_ID) { 97e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount binding = (ViewDataBinding) v.getTag(R.id.dataBinding); 98e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount } else { 99e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount binding = (ViewDataBinding) v.getTag(); 100e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount } 1015914aa7da50a90a4c705b5be02a215499d0ad232George Mount v.post(binding.mRebindRunnable); 1025914aa7da50a90a4c705b5be02a215499d0ad232George Mount v.removeOnAttachStateChangeListener(this); 1035914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1045914aa7da50a90a4c705b5be02a215499d0ad232George Mount 1055914aa7da50a90a4c705b5be02a215499d0ad232George Mount @Override 1065914aa7da50a90a4c705b5be02a215499d0ad232George Mount public void onViewDetachedFromWindow(View v) { 1075914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1085914aa7da50a90a4c705b5be02a215499d0ad232George Mount }; 1095914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1105914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1115914aa7da50a90a4c705b5be02a215499d0ad232George Mount 1124c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 1134c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Runnable executed on animation heartbeat to rebind the dirty Views. 1144c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 115085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar private Runnable mRebindRunnable = new Runnable() { 116085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar @Override 117085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar public void run() { 1184c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount if (mPendingRebind) { 1195914aa7da50a90a4c705b5be02a215499d0ad232George Mount boolean rebind = true; 1205914aa7da50a90a4c705b5be02a215499d0ad232George Mount if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) { 1215914aa7da50a90a4c705b5be02a215499d0ad232George Mount rebind = mRoot.isAttachedToWindow(); 1225914aa7da50a90a4c705b5be02a215499d0ad232George Mount if (!rebind) { 1235914aa7da50a90a4c705b5be02a215499d0ad232George Mount // Don't execute the pending bindings until the View 1245914aa7da50a90a4c705b5be02a215499d0ad232George Mount // is attached again. 1255914aa7da50a90a4c705b5be02a215499d0ad232George Mount mRoot.addOnAttachStateChangeListener(ROOT_REATTACHED_LISTENER); 1265914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1275914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1285914aa7da50a90a4c705b5be02a215499d0ad232George Mount if (rebind) { 1295914aa7da50a90a4c705b5be02a215499d0ad232George Mount mPendingRebind = false; 1305914aa7da50a90a4c705b5be02a215499d0ad232George Mount executePendingBindings(); 1315914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1324c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } 133085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 134085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar }; 135085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 1364c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 1374c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Flag indicates that there are pending bindings that need to be reevaluated. 1384c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 1394c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private boolean mPendingRebind = false; 1404c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 1414c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 1424c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * The observed expressions. 1434c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 1444c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private WeakListener[] mLocalFieldObservers; 1454c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 1464c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 1474c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * The root View that this Binding is associated with. 1484c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 1494c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private final View mRoot; 1504c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 1514c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount protected ViewDataBinding(View root, int localFieldCount) { 1525cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount mLocalFieldObservers = new WeakListener[localFieldCount]; 1534c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount this.mRoot = root; 15496e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 15596e1c821dd446d1ed78f8ae61131550588f60a24George Mount 15696e1c821dd446d1ed78f8ae61131550588f60a24George Mount protected void setRootTag(View view) { 15796e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (USE_TAG_ID) { 15896e1c821dd446d1ed78f8ae61131550588f60a24George Mount view.setTag(R.id.dataBinding, this); 15996e1c821dd446d1ed78f8ae61131550588f60a24George Mount } else { 16096e1c821dd446d1ed78f8ae61131550588f60a24George Mount view.setTag(this); 16196e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 16296e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 16396e1c821dd446d1ed78f8ae61131550588f60a24George Mount 16496e1c821dd446d1ed78f8ae61131550588f60a24George Mount protected void setRootTag(View[] views) { 165e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount if (USE_TAG_ID) { 16696e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (View view : views) { 16796e1c821dd446d1ed78f8ae61131550588f60a24George Mount view.setTag(R.id.dataBinding, this); 16896e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 169e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount } else { 17096e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (View view : views) { 17196e1c821dd446d1ed78f8ae61131550588f60a24George Mount view.setTag(this); 17296e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 173e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount } 1745cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 1755cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 1764c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public static int getBuildSdkInt() { 1774c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount return SDK_INT; 1784c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } 1794c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 1804c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 1814c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Called when an observed object changes. Sets the appropriate dirty flag if applicable. 1824c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * @param localFieldId The index into mLocalFieldObservers that this Object resides in. 1834c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * @param object The object that has changed. 184fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount * @param fieldId The BR ID of the field being changed or _all if 1854c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * no specific field is being notified. 1864c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * @return true if this change should cause a change to the UI. 1874c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 1884c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount protected abstract boolean onFieldChange(int localFieldId, Object object, int fieldId); 1894c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 1904c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public abstract boolean setVariable(int variableId, Object variable); 1914c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 1924c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 1934c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Evaluates the pending bindings, updating any Views that have expressions bound to 1944c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * modified variables. This <b>must</b> be run on the UI thread. 1954c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 1964c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public abstract void executePendingBindings(); 1974c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 1984c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 1994c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Used internally to invalidate flags of included layouts. 2004c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 2014c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public abstract void invalidateAll(); 2024c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 2034c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 2044c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Removes binding listeners to expression variables. 2054c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 2064c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public void unbind() { 2075cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount for (WeakListener weakListener : mLocalFieldObservers) { 2085cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (weakListener != null) { 2095cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount weakListener.unregister(); 2105cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 2115cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 212085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 213085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 2144c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount @Override 2154c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount protected void finalize() throws Throwable { 2164c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount unbind(); 2174c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } 2184c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 2194c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 2204c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Returns the outermost View in the layout file associated with the Binding. 2214c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * @return the outermost View in the layout file associated with the Binding. 2224c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 223085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar public View getRoot() { 224085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return mRoot; 225085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 226085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 227085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) { 228085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar boolean result = onFieldChange(mLocalFieldId, object, fieldId); 229085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (result) { 230085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar requestRebind(); 231085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 232085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 233085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 234085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar protected boolean unregisterFrom(int localFieldId) { 2355cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount WeakListener listener = mLocalFieldObservers[localFieldId]; 236085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (listener != null) { 237085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return listener.unregister(); 238085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 239085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return false; 240085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 241085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 242085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar protected void requestRebind() { 243085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (mPendingRebind) { 244085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return; 245085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 246085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar mPendingRebind = true; 2474c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) { 2484c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount mRoot.postOnAnimation(mRebindRunnable); 2494c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } else { 2504c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount mRoot.post(mRebindRunnable); 2514c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } 252085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 253085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 254085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar protected Object getObservedField(int localFieldId) { 2555cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount WeakListener listener = mLocalFieldObservers[localFieldId]; 256085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (listener == null) { 257085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return null; 258085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 259085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return listener.getTarget(); 260085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 261085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 2625cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount private boolean updateRegistration(int localFieldId, Object observable, 2635cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount CreateWeakListener listenerCreator) { 264085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (observable == null) { 265085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return unregisterFrom(localFieldId); 266085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 2675cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount WeakListener listener = mLocalFieldObservers[localFieldId]; 268085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (listener == null) { 2695cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount registerTo(localFieldId, observable, listenerCreator); 270085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return true; 271085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 272085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (listener.getTarget() == observable) { 273085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return false;//nothing to do, same object 274085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 275085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar unregisterFrom(localFieldId); 2765cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount registerTo(localFieldId, observable, listenerCreator); 277085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return true; 278085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 279085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 2805cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected boolean updateRegistration(int localFieldId, Observable observable) { 2815cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER); 2825cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 2835cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 2845cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected boolean updateRegistration(int localFieldId, ObservableList observable) { 2855cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return updateRegistration(localFieldId, observable, CREATE_LIST_LISTENER); 2865cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 2875cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 2885cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected boolean updateRegistration(int localFieldId, ObservableMap observable) { 2895cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return updateRegistration(localFieldId, observable, CREATE_MAP_LISTENER); 2905cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 2915cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 2925cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected void registerTo(int localFieldId, Object observable, 2935cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount CreateWeakListener listenerCreator) { 294085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (observable == null) { 295085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return; 296085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 2975cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount WeakListener listener = mLocalFieldObservers[localFieldId]; 298085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (listener == null) { 2995cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount listener = listenerCreator.create(this, localFieldId); 300085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar mLocalFieldObservers[localFieldId] = listener; 301085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 302085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar listener.setTarget(observable); 303085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 304085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 3054c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 30696e1c821dd446d1ed78f8ae61131550588f60a24George Mount * Walks the view hierarchy under root and pulls out tagged Views, includes, and views with 30796e1c821dd446d1ed78f8ae61131550588f60a24George Mount * IDs into an Object[] that is returned. This is used to walk the view hierarchy once to find 30896e1c821dd446d1ed78f8ae61131550588f60a24George Mount * all bound and ID'd views. 30996e1c821dd446d1ed78f8ae61131550588f60a24George Mount * 31096e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param root The root of the view hierarchy to walk. 31196e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param numBindings The total number of ID'd views, views with expressions, and includes 31296e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param includes The include layout information, indexed by their container's index. 31396e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param viewsWithIds Indexes of views that don't have tags, but have IDs. 31496e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @return An array of size numBindings containing all Views in the hierarchy that have IDs 31596e1c821dd446d1ed78f8ae61131550588f60a24George Mount * (with elements in viewsWithIds), are tagged containing expressions, or the bindings for 31696e1c821dd446d1ed78f8ae61131550588f60a24George Mount * included layouts. 31796e1c821dd446d1ed78f8ae61131550588f60a24George Mount */ 31896e1c821dd446d1ed78f8ae61131550588f60a24George Mount protected static Object[] mapBindings(View root, int numBindings, 31996e1c821dd446d1ed78f8ae61131550588f60a24George Mount IncludedLayoutIndex[][] includes, SparseIntArray viewsWithIds) { 32096e1c821dd446d1ed78f8ae61131550588f60a24George Mount Object[] bindings = new Object[numBindings]; 32196e1c821dd446d1ed78f8ae61131550588f60a24George Mount mapBindings(root, bindings, includes, viewsWithIds, true); 32296e1c821dd446d1ed78f8ae61131550588f60a24George Mount return bindings; 32396e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 32496e1c821dd446d1ed78f8ae61131550588f60a24George Mount 32596e1c821dd446d1ed78f8ae61131550588f60a24George Mount /** 32696e1c821dd446d1ed78f8ae61131550588f60a24George Mount * Walks the view hierarchy under roots and pulls out tagged Views, includes, and views with 32796e1c821dd446d1ed78f8ae61131550588f60a24George Mount * IDs into an Object[] that is returned. This is used to walk the view hierarchy once to find 32896e1c821dd446d1ed78f8ae61131550588f60a24George Mount * all bound and ID'd views. 3294c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * 33096e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param roots The root Views of the view hierarchy to walk. This is used with merge tags. 33196e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param numBindings The total number of ID'd views, views with expressions, and includes 33296e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param includes The include layout information, indexed by their container's index. 33396e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param viewsWithIds Indexes of views that don't have tags, but have IDs. 33496e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @return An array of size numBindings containing all Views in the hierarchy that have IDs 33596e1c821dd446d1ed78f8ae61131550588f60a24George Mount * (with elements in viewsWithIds), are tagged containing expressions, or the bindings for 33696e1c821dd446d1ed78f8ae61131550588f60a24George Mount * included layouts. 3374c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 33896e1c821dd446d1ed78f8ae61131550588f60a24George Mount protected static Object[] mapBindings(View[] roots, int numBindings, 33996e1c821dd446d1ed78f8ae61131550588f60a24George Mount IncludedLayoutIndex[][] includes, SparseIntArray viewsWithIds) { 34096e1c821dd446d1ed78f8ae61131550588f60a24George Mount Object[] bindings = new Object[numBindings]; 34196e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int i = 0; i < roots.length; i++) { 34296e1c821dd446d1ed78f8ae61131550588f60a24George Mount mapBindings(roots[i], bindings, includes, viewsWithIds, true); 34300da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 34496e1c821dd446d1ed78f8ae61131550588f60a24George Mount return bindings; 34500da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 34600da715547ee7d5d38a3b8576090ca427a94daa5George Mount 34796e1c821dd446d1ed78f8ae61131550588f60a24George Mount private static void mapBindings(View view, Object[] bindings, 34896e1c821dd446d1ed78f8ae61131550588f60a24George Mount IncludedLayoutIndex[][] includes, SparseIntArray viewsWithIds, boolean isRoot) { 34996e1c821dd446d1ed78f8ae61131550588f60a24George Mount final IncludedLayoutIndex[] includedLayoutIndexes; 35096e1c821dd446d1ed78f8ae61131550588f60a24George Mount final String tag = (String) view.getTag(); 35196e1c821dd446d1ed78f8ae61131550588f60a24George Mount boolean isBound = false; 35296e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (isRoot && tag != null && tag.startsWith("layout")) { 35396e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int underscoreIndex = tag.lastIndexOf('_'); 35496e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (underscoreIndex > 0 && isNumeric(tag, underscoreIndex + 1)) { 35596e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int index = parseTagInt(tag, underscoreIndex + 1); 35696e1c821dd446d1ed78f8ae61131550588f60a24George Mount bindings[index] = view; 35796e1c821dd446d1ed78f8ae61131550588f60a24George Mount includedLayoutIndexes = includes == null ? null : includes[index]; 35896e1c821dd446d1ed78f8ae61131550588f60a24George Mount isBound = true; 35996e1c821dd446d1ed78f8ae61131550588f60a24George Mount } else { 36096e1c821dd446d1ed78f8ae61131550588f60a24George Mount includedLayoutIndexes = null; 36196e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 36296e1c821dd446d1ed78f8ae61131550588f60a24George Mount } else if (tag != null && tag.startsWith(BINDING_TAG_PREFIX)) { 36396e1c821dd446d1ed78f8ae61131550588f60a24George Mount int tagIndex = parseTagInt(tag, BINDING_NUMBER_START); 36496e1c821dd446d1ed78f8ae61131550588f60a24George Mount bindings[tagIndex] = view; 36596e1c821dd446d1ed78f8ae61131550588f60a24George Mount isBound = true; 36696e1c821dd446d1ed78f8ae61131550588f60a24George Mount includedLayoutIndexes = includes == null ? null : includes[tagIndex]; 36795d1b38adeb5963ec5337e7dd6177b4bb5a03619George Mount } else { 36896e1c821dd446d1ed78f8ae61131550588f60a24George Mount // Not a bound view 36996e1c821dd446d1ed78f8ae61131550588f60a24George Mount includedLayoutIndexes = null; 37096e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 37196e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (!isBound) { 37296e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int id = view.getId(); 37396e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (id > 0) { 37496e1c821dd446d1ed78f8ae61131550588f60a24George Mount int index; 37596e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (viewsWithIds != null && (index = viewsWithIds.get(id, -1)) >= 0) { 37696e1c821dd446d1ed78f8ae61131550588f60a24George Mount bindings[index] = view; 37796e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 37896e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 37996e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 38096e1c821dd446d1ed78f8ae61131550588f60a24George Mount 38196e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (view instanceof ViewGroup) { 38296e1c821dd446d1ed78f8ae61131550588f60a24George Mount final ViewGroup viewGroup = (ViewGroup) view; 38396e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int count = viewGroup.getChildCount(); 38496e1c821dd446d1ed78f8ae61131550588f60a24George Mount int minInclude = 0; 38596e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int i = 0; i < count; i++) { 38696e1c821dd446d1ed78f8ae61131550588f60a24George Mount final View child = viewGroup.getChildAt(i); 38796e1c821dd446d1ed78f8ae61131550588f60a24George Mount boolean isInclude = false; 38896e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (includedLayoutIndexes != null) { 38996e1c821dd446d1ed78f8ae61131550588f60a24George Mount String childTag = (String) child.getTag(); 39096e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (childTag != null && childTag.endsWith("_0") && 39196e1c821dd446d1ed78f8ae61131550588f60a24George Mount childTag.startsWith("layout") && childTag.indexOf('/') > 0) { 39296e1c821dd446d1ed78f8ae61131550588f60a24George Mount Log.d("ViewDataBinding", "Found potential include: " + childTag); 39396e1c821dd446d1ed78f8ae61131550588f60a24George Mount // This *could* be an include. Test against the expected includes. 39496e1c821dd446d1ed78f8ae61131550588f60a24George Mount int includeIndex = findIncludeIndex(childTag, minInclude, 39596e1c821dd446d1ed78f8ae61131550588f60a24George Mount includedLayoutIndexes); 39696e1c821dd446d1ed78f8ae61131550588f60a24George Mount Log.d("ViewDataBinding", "found index: " + includeIndex); 39796e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (includeIndex >= 0) { 39896e1c821dd446d1ed78f8ae61131550588f60a24George Mount isInclude = true; 39996e1c821dd446d1ed78f8ae61131550588f60a24George Mount minInclude = includeIndex + 1; 40096e1c821dd446d1ed78f8ae61131550588f60a24George Mount IncludedLayoutIndex include = includedLayoutIndexes[includeIndex]; 40196e1c821dd446d1ed78f8ae61131550588f60a24George Mount int lastMatchingIndex = findLastMatching(viewGroup, i); 40296e1c821dd446d1ed78f8ae61131550588f60a24George Mount Log.d("ViewDataBinding", "include index: " + include.index + ", first match = " + i + ", last match = " + lastMatchingIndex); 40396e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (lastMatchingIndex == i) { 40496e1c821dd446d1ed78f8ae61131550588f60a24George Mount bindings[include.index] = DataBindingUtil.bindTo(child, include.layoutId); 40596e1c821dd446d1ed78f8ae61131550588f60a24George Mount } else { 40696e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int includeCount = lastMatchingIndex - i + 1; 40796e1c821dd446d1ed78f8ae61131550588f60a24George Mount final View[] included = new View[includeCount]; 40896e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int j = 0; j < includeCount; j++) { 40996e1c821dd446d1ed78f8ae61131550588f60a24George Mount included[j] = viewGroup.getChildAt(i + j); 41096e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 41196e1c821dd446d1ed78f8ae61131550588f60a24George Mount bindings[include.index] = DataBindingUtil.bindTo(included, include.layoutId); 41296e1c821dd446d1ed78f8ae61131550588f60a24George Mount i += includeCount - 1; 41396e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 41496e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 41596e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 41696e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 41796e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (!isInclude) { 41896e1c821dd446d1ed78f8ae61131550588f60a24George Mount mapBindings(child, bindings, includes, viewsWithIds, false); 41996e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 42096e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 4214c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } 42296e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 42396e1c821dd446d1ed78f8ae61131550588f60a24George Mount 42496e1c821dd446d1ed78f8ae61131550588f60a24George Mount private static int findIncludeIndex(String tag, int minInclude, 42596e1c821dd446d1ed78f8ae61131550588f60a24George Mount IncludedLayoutIndex[] layoutIndexes) { 42696e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int slashIndex = tag.indexOf('/'); 42796e1c821dd446d1ed78f8ae61131550588f60a24George Mount final CharSequence layoutName = tag.subSequence(slashIndex + 1, tag.length() - 2); 42896e1c821dd446d1ed78f8ae61131550588f60a24George Mount 42996e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int length = layoutIndexes.length; 43096e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int i = minInclude; i < length; i++) { 43196e1c821dd446d1ed78f8ae61131550588f60a24George Mount final IncludedLayoutIndex layoutIndex = layoutIndexes[i]; 43296e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (TextUtils.equals(layoutName, layoutIndex.layout)) { 43396e1c821dd446d1ed78f8ae61131550588f60a24George Mount return i; 43496e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 43500da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 43696e1c821dd446d1ed78f8ae61131550588f60a24George Mount return -1; 43700da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 43800da715547ee7d5d38a3b8576090ca427a94daa5George Mount 43996e1c821dd446d1ed78f8ae61131550588f60a24George Mount private static int findLastMatching(ViewGroup viewGroup, int firstIncludedIndex) { 44096e1c821dd446d1ed78f8ae61131550588f60a24George Mount final View firstView = viewGroup.getChildAt(firstIncludedIndex); 44196e1c821dd446d1ed78f8ae61131550588f60a24George Mount final String firstViewTag = (String) firstView.getTag(); 44296e1c821dd446d1ed78f8ae61131550588f60a24George Mount final String tagBase = firstViewTag.substring(0, firstViewTag.length() - 1); // don't include the "0" 44396e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int tagSequenceIndex = tagBase.length(); 44496e1c821dd446d1ed78f8ae61131550588f60a24George Mount 44596e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int count = viewGroup.getChildCount(); 44696e1c821dd446d1ed78f8ae61131550588f60a24George Mount int max = firstIncludedIndex; 44796e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int i = firstIncludedIndex + 1; i < count; i++) { 44896e1c821dd446d1ed78f8ae61131550588f60a24George Mount final View view = viewGroup.getChildAt(i); 44996e1c821dd446d1ed78f8ae61131550588f60a24George Mount final String tag = (String) view.getTag(); 45096e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (tag != null && tag.startsWith(tagBase)) { 45196e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (tag.length() == firstViewTag.length() && tag.charAt(tag.length() - 1) == '0') { 45296e1c821dd446d1ed78f8ae61131550588f60a24George Mount return max; // Found another instance of the include 45396e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 45496e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (isNumeric(tag, tagSequenceIndex)) { 45596e1c821dd446d1ed78f8ae61131550588f60a24George Mount max = i; 45696e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 45796e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 45896e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 45996e1c821dd446d1ed78f8ae61131550588f60a24George Mount return max; 46034a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount } 46134a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount 46296e1c821dd446d1ed78f8ae61131550588f60a24George Mount private static boolean isNumeric(String tag, int startIndex) { 46396e1c821dd446d1ed78f8ae61131550588f60a24George Mount int length = tag.length(); 46496e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (length == startIndex) { 46596e1c821dd446d1ed78f8ae61131550588f60a24George Mount return false; // no numerals 46696e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 46796e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int i = startIndex; i < length; i++) { 46896e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (!Character.isDigit(tag.charAt(i))) { 46996e1c821dd446d1ed78f8ae61131550588f60a24George Mount return false; 47095d1b38adeb5963ec5337e7dd6177b4bb5a03619George Mount } 47195d1b38adeb5963ec5337e7dd6177b4bb5a03619George Mount } 47296e1c821dd446d1ed78f8ae61131550588f60a24George Mount return true; 47395d1b38adeb5963ec5337e7dd6177b4bb5a03619George Mount } 47495d1b38adeb5963ec5337e7dd6177b4bb5a03619George Mount 47534a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount /** 47600da715547ee7d5d38a3b8576090ca427a94daa5George Mount * Parse the tag without creating a new String object. This is fast and assumes the 47700da715547ee7d5d38a3b8576090ca427a94daa5George Mount * tag is in the correct format. 47800da715547ee7d5d38a3b8576090ca427a94daa5George Mount * @param str The tag string. 47900da715547ee7d5d38a3b8576090ca427a94daa5George Mount * @return The binding tag number parsed from the tag string. 48000da715547ee7d5d38a3b8576090ca427a94daa5George Mount */ 48196e1c821dd446d1ed78f8ae61131550588f60a24George Mount private static int parseTagInt(String str, int startIndex) { 48200da715547ee7d5d38a3b8576090ca427a94daa5George Mount final int end = str.length(); 48300da715547ee7d5d38a3b8576090ca427a94daa5George Mount int val = 0; 48496e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int i = startIndex; i < end; i++) { 48500da715547ee7d5d38a3b8576090ca427a94daa5George Mount val *= 10; 48600da715547ee7d5d38a3b8576090ca427a94daa5George Mount char c = str.charAt(i); 48700da715547ee7d5d38a3b8576090ca427a94daa5George Mount val += (c - '0'); 48800da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 48900da715547ee7d5d38a3b8576090ca427a94daa5George Mount return val; 49000da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 49100da715547ee7d5d38a3b8576090ca427a94daa5George Mount 4924c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private static abstract class WeakListener<T> { 4934c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private final WeakReference<ViewDataBinding> mBinder; 4945cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected final int mLocalFieldId; 4955cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount private T mTarget; 496085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 4974c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakListener(ViewDataBinding binder, int localFieldId) { 4984c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount mBinder = new WeakReference<ViewDataBinding>(binder); 4995cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount mLocalFieldId = localFieldId; 500085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 501085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 5025cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount public void setTarget(T object) { 5035cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount unregister(); 5045cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount mTarget = object; 5055cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (mTarget != null) { 5065cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount addListener(mTarget); 507085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 508085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 509085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 510085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar public boolean unregister() { 5115cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount boolean unregistered = false; 5125cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (mTarget != null) { 5135cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount removeListener(mTarget); 5145cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount unregistered = true; 515085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 516085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar mTarget = null; 5175cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return unregistered; 518085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 519085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 5205cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount public T getTarget() { 5215cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return mTarget; 522085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 5235cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 5244c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount protected ViewDataBinding getBinder() { 5254c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount ViewDataBinding binder = mBinder.get(); 5265cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (binder == null) { 5275cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount unregister(); // The binder is dead 5285cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 5295cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return binder; 5305cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 5315cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 5325cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected abstract void addListener(T target); 5335cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected abstract void removeListener(T target); 534085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 535085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 5364c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private static class WeakPropertyListener extends WeakListener<Observable> 5375cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount implements OnPropertyChangedListener { 5384c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakPropertyListener(ViewDataBinding binder, int localFieldId) { 5395cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount super(binder, localFieldId); 5405cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 5415cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 5425cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 5435cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected void addListener(Observable target) { 5445cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount target.addOnPropertyChangedListener(this); 5455cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 5465cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 5475cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 5485cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected void removeListener(Observable target) { 5495cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount target.removeOnPropertyChangedListener(this); 550085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 551085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 552085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar @Override 553293de28642305ce210e1d2a1cfe0abfa4f737d7aGeorge Mount public void onPropertyChanged(Observable sender, int fieldId) { 5544c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount ViewDataBinding binder = getBinder(); 5555cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (binder == null) { 5565cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return; 5575cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 558085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar Observable obj = getTarget(); 5595cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (obj != sender) { 5605cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return; // notification from the wrong object? 561085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 5625cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount binder.handleFieldChange(mLocalFieldId, sender, fieldId); 563085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 564085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 5655cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 5664c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private static class WeakListListener extends WeakListener<ObservableList> 5675cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount implements OnListChangedListener { 5685cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 5694c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakListListener(ViewDataBinding binder, int localFieldId) { 5705cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount super(binder, localFieldId); 5715cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 5725cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 5735cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 5745cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount public void onChanged() { 5754c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount ViewDataBinding binder = getBinder(); 5765cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (binder == null) { 5775cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return; 5785cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 5795cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount ObservableList target = getTarget(); 5805cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (target == null) { 5815cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return; // We don't expect any notifications from null targets 5825cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 5835cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount binder.handleFieldChange(mLocalFieldId, target, 0); 5845cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 5855cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 5865cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 5875cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount public void onItemRangeChanged(int positionStart, int itemCount) { 5885cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount onChanged(); 5895cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 5905cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 5915cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 5925cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount public void onItemRangeInserted(int positionStart, int itemCount) { 5935cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount onChanged(); 5945cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 5955cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 5965cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 5975cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { 5985cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount onChanged(); 5995cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 6005cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 6015cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 6025cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount public void onItemRangeRemoved(int positionStart, int itemCount) { 6035cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount onChanged(); 6045cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 6055cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 6065cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 6075cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected void addListener(ObservableList target) { 6085cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount target.addOnListChangedListener(this); 6095cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 6105cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 6115cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 6125cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected void removeListener(ObservableList target) { 6135cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount target.removeOnListChangedListener(this); 6145cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 6155cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 6165cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 6174c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private static class WeakMapListener extends WeakListener<ObservableMap> 6185cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount implements OnMapChangedListener { 6194c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakMapListener(ViewDataBinding binder, int localFieldId) { 6205cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount super(binder, localFieldId); 6215cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 6225cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 6235cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 6245cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected void addListener(ObservableMap target) { 6255cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount target.addOnMapChangedListener(this); 6265cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 6275cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 6285cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 6295cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected void removeListener(ObservableMap target) { 6305cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount target.removeOnMapChangedListener(this); 6315cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 6325cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 6335cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 6342c86cdbaf189e2b1774af7f64a2974de9321673fGeorge Mount public void onMapChanged(ObservableMap sender, Object key) { 6354c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount ViewDataBinding binder = getBinder(); 6365cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (binder == null || sender != getTarget()) { 6375cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return; 6385cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 6395cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount binder.handleFieldChange(mLocalFieldId, sender, 0); 6405cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 6415cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 6425cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 6435cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount private interface CreateWeakListener { 6444c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount WeakListener create(ViewDataBinding viewDataBinding, int localFieldId); 6455cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 64696e1c821dd446d1ed78f8ae61131550588f60a24George Mount 64796e1c821dd446d1ed78f8ae61131550588f60a24George Mount protected static class IncludedLayoutIndex { 64896e1c821dd446d1ed78f8ae61131550588f60a24George Mount public final String layout; 64996e1c821dd446d1ed78f8ae61131550588f60a24George Mount public final int index; 65096e1c821dd446d1ed78f8ae61131550588f60a24George Mount public final int layoutId; 65196e1c821dd446d1ed78f8ae61131550588f60a24George Mount 65296e1c821dd446d1ed78f8ae61131550588f60a24George Mount public IncludedLayoutIndex(String layout, int index, int layoutId) { 65396e1c821dd446d1ed78f8ae61131550588f60a24George Mount this.layout = layout; 65496e1c821dd446d1ed78f8ae61131550588f60a24George Mount this.index = index; 65596e1c821dd446d1ed78f8ae61131550588f60a24George Mount this.layoutId = layoutId; 65696e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 65796e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 658085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar} 659