ViewDataBinding.java revision 3f73e3149732132c02f5d19aab7b5da429794058
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; 22e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mountimport android.databinding.CallbackRegistry.NotifierCallback; 234c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mountimport android.os.Build.VERSION; 244c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mountimport android.os.Build.VERSION_CODES; 253f73e3149732132c02f5d19aab7b5da429794058Yigit Boyarimport android.os.Handler; 263f73e3149732132c02f5d19aab7b5da429794058Yigit Boyarimport android.os.Looper; 2796e1c821dd446d1ed78f8ae61131550588f60a24George Mountimport android.text.TextUtils; 284c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mountimport android.util.SparseIntArray; 293f73e3149732132c02f5d19aab7b5da429794058Yigit Boyarimport android.view.Choreographer; 30085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarimport android.view.View; 315914aa7da50a90a4c705b5be02a215499d0ad232George Mountimport android.view.View.OnAttachStateChangeListener; 3200da715547ee7d5d38a3b8576090ca427a94daa5George Mountimport android.view.ViewGroup; 33085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 34085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarimport java.lang.ref.WeakReference; 35085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 364c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mountpublic abstract class ViewDataBinding { 374c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 384c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 394c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Instead of directly accessing Build.VERSION.SDK_INT, generated code uses this value so that 404c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * we can test API dependent behavior. 414c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 424c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount static int SDK_INT = VERSION.SDK_INT; 434c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 44e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount private static final int REBIND = 1; 45e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount private static final int HALTED = 2; 46e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount private static final int REBOUND = 3; 47e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 484c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 494c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Prefix for android:tag on Views with binding. The root View and include tags will not have 504c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * android:tag attributes and will use ids instead. 514c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 527ff60c24c6de7ba0c674fe65a82ad4a88dab2e5dGeorge Mount public static final String BINDING_TAG_PREFIX = "binding_"; 534c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 544c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount // The length of BINDING_TAG_PREFIX prevents calling length repeatedly. 5500da715547ee7d5d38a3b8576090ca427a94daa5George Mount private static final int BINDING_NUMBER_START = BINDING_TAG_PREFIX.length(); 5600da715547ee7d5d38a3b8576090ca427a94daa5George Mount 57e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount // ICS (v 14) fixes a leak when using setTag(int, Object) 58e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount private static final boolean USE_TAG_ID = DataBinderMapper.TARGET_MIN_SDK >= 14; 59e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount 603f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar private static final boolean USE_CHOREOGRAPHER = SDK_INT >= 16; 613f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar 624c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 634c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Method object extracted out to attach a listener to a bound Observable object. 644c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 655cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount private static final CreateWeakListener CREATE_PROPERTY_LISTENER = new CreateWeakListener() { 665cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 674c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) { 684c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount return new WeakPropertyListener(viewDataBinding, localFieldId); 695cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 705cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount }; 715cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 724c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 734c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Method object extracted out to attach a listener to a bound ObservableList object. 744c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 755cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount private static final CreateWeakListener CREATE_LIST_LISTENER = new CreateWeakListener() { 765cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 774c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) { 784c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount return new WeakListListener(viewDataBinding, localFieldId); 795cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 805cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount }; 815cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 824c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 834c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Method object extracted out to attach a listener to a bound ObservableMap object. 844c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 855cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount private static final CreateWeakListener CREATE_MAP_LISTENER = new CreateWeakListener() { 865cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 874c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) { 884c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount return new WeakMapListener(viewDataBinding, localFieldId); 895cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 905cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount }; 915cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 92e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount private static final CallbackRegistry.NotifierCallback<OnRebindCallback, ViewDataBinding, Void> 93e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount REBIND_NOTIFIER = new NotifierCallback<OnRebindCallback, ViewDataBinding, Void>() { 94e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount @Override 95e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount public void onNotifyCallback(OnRebindCallback callback, ViewDataBinding sender, int mode, 96e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount Void arg2) { 97e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount switch (mode) { 98e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount case REBIND: 99e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (!callback.onPreBind(sender)) { 100e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount sender.mRebindHalted = true; 101e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 102e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount break; 103e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount case HALTED: 104e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount callback.onCanceled(sender); 105e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount break; 106e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount case REBOUND: 107e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount callback.onBound(sender); 108e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount break; 109e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 110e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 111e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount }; 112e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 1135914aa7da50a90a4c705b5be02a215499d0ad232George Mount private static final OnAttachStateChangeListener ROOT_REATTACHED_LISTENER; 1145914aa7da50a90a4c705b5be02a215499d0ad232George Mount 1155914aa7da50a90a4c705b5be02a215499d0ad232George Mount static { 1165914aa7da50a90a4c705b5be02a215499d0ad232George Mount if (VERSION.SDK_INT < VERSION_CODES.KITKAT) { 1175914aa7da50a90a4c705b5be02a215499d0ad232George Mount ROOT_REATTACHED_LISTENER = null; 1185914aa7da50a90a4c705b5be02a215499d0ad232George Mount } else { 1195914aa7da50a90a4c705b5be02a215499d0ad232George Mount ROOT_REATTACHED_LISTENER = new OnAttachStateChangeListener() { 1205914aa7da50a90a4c705b5be02a215499d0ad232George Mount @TargetApi(VERSION_CODES.KITKAT) 1215914aa7da50a90a4c705b5be02a215499d0ad232George Mount @Override 1225914aa7da50a90a4c705b5be02a215499d0ad232George Mount public void onViewAttachedToWindow(View v) { 1235914aa7da50a90a4c705b5be02a215499d0ad232George Mount // execute the pending bindings. 124e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount final ViewDataBinding binding; 125e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount if (USE_TAG_ID) { 126e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount binding = (ViewDataBinding) v.getTag(R.id.dataBinding); 127e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount } else { 128e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount binding = (ViewDataBinding) v.getTag(); 129e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount } 1303f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar binding.mRebindRunnable.run(); 1315914aa7da50a90a4c705b5be02a215499d0ad232George Mount v.removeOnAttachStateChangeListener(this); 1325914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1335914aa7da50a90a4c705b5be02a215499d0ad232George Mount 1345914aa7da50a90a4c705b5be02a215499d0ad232George Mount @Override 1355914aa7da50a90a4c705b5be02a215499d0ad232George Mount public void onViewDetachedFromWindow(View v) { 1365914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1375914aa7da50a90a4c705b5be02a215499d0ad232George Mount }; 1385914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1395914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1405914aa7da50a90a4c705b5be02a215499d0ad232George Mount 1414c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 1424c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Runnable executed on animation heartbeat to rebind the dirty Views. 1434c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 1443f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar private final Runnable mRebindRunnable = new Runnable() { 145085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar @Override 146085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar public void run() { 147e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount synchronized (this) { 148e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mPendingRebind = false; 149e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 150e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) { 151e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount // Nested so that we don't get a lint warning in IntelliJ 152e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (!mRoot.isAttachedToWindow()) { 153e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount // Don't execute the pending bindings until the View 154e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount // is attached again. 155e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRoot.removeOnAttachStateChangeListener(ROOT_REATTACHED_LISTENER); 156e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRoot.addOnAttachStateChangeListener(ROOT_REATTACHED_LISTENER); 157e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount return; 1585914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1594c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } 160e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount executePendingBindings(); 161085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 162085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar }; 163085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 1644c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 1654c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Flag indicates that there are pending bindings that need to be reevaluated. 1664c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 1674c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private boolean mPendingRebind = false; 1684c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 1694c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 170e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * Indicates that a onPreBind has stopped the executePendingBindings call. 171e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount */ 172e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount private boolean mRebindHalted = false; 173e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 174e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount /** 1754c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * The observed expressions. 1764c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 1774c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private WeakListener[] mLocalFieldObservers; 1784c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 1794c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 1804c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * The root View that this Binding is associated with. 1814c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 1824c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private final View mRoot; 1834c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 184e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount /** 185e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * The collection of OnRebindCallbacks. 186e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount */ 187e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount private CallbackRegistry<OnRebindCallback, ViewDataBinding, Void> mRebindCallbacks; 188e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 189e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount /** 190e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * Flag to prevent reentrant executePendingBinding calls. 191e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount */ 192e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount private boolean mIsExecutingPendingBindings; 193e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 1943f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar // null api < 16 1953f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar private Choreographer mChoreographer; 1963f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar 1973f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar private final Choreographer.FrameCallback mFrameCallback; 1983f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar 1993f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar // null api >= 16 2003f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar private Handler mUIThreadHandler; 2013f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar 2024c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount protected ViewDataBinding(View root, int localFieldCount) { 2035cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount mLocalFieldObservers = new WeakListener[localFieldCount]; 2044c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount this.mRoot = root; 2053f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar if (Looper.myLooper() == null) { 2063f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar throw new IllegalStateException("DataBinding must be created in view's UI Thread"); 2073f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar } 2083f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar if (USE_CHOREOGRAPHER) { 2093f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar mChoreographer = Choreographer.getInstance(); 2103f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar mFrameCallback = new Choreographer.FrameCallback() { 2113f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar @Override 2123f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar public void doFrame(long frameTimeNanos) { 2133f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar mRebindRunnable.run(); 2143f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar } 2153f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar }; 2163f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar } else { 2173f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar mFrameCallback = null; 2183f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar mUIThreadHandler = new Handler(Looper.myLooper()); 2193f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar } 2203f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar requestRebind(); 22196e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 22296e1c821dd446d1ed78f8ae61131550588f60a24George Mount 22396e1c821dd446d1ed78f8ae61131550588f60a24George Mount protected void setRootTag(View view) { 22496e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (USE_TAG_ID) { 22596e1c821dd446d1ed78f8ae61131550588f60a24George Mount view.setTag(R.id.dataBinding, this); 22696e1c821dd446d1ed78f8ae61131550588f60a24George Mount } else { 22796e1c821dd446d1ed78f8ae61131550588f60a24George Mount view.setTag(this); 22896e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 22996e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 23096e1c821dd446d1ed78f8ae61131550588f60a24George Mount 23196e1c821dd446d1ed78f8ae61131550588f60a24George Mount protected void setRootTag(View[] views) { 232e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount if (USE_TAG_ID) { 23396e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (View view : views) { 23496e1c821dd446d1ed78f8ae61131550588f60a24George Mount view.setTag(R.id.dataBinding, this); 23596e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 236e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount } else { 23796e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (View view : views) { 23896e1c821dd446d1ed78f8ae61131550588f60a24George Mount view.setTag(this); 23996e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 240e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount } 2415cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 2425cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 2434c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public static int getBuildSdkInt() { 2444c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount return SDK_INT; 2454c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } 2464c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 2474c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 2484c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Called when an observed object changes. Sets the appropriate dirty flag if applicable. 2494c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * @param localFieldId The index into mLocalFieldObservers that this Object resides in. 2504c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * @param object The object that has changed. 251fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount * @param fieldId The BR ID of the field being changed or _all if 2524c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * no specific field is being notified. 2534c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * @return true if this change should cause a change to the UI. 2544c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 2554c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount protected abstract boolean onFieldChange(int localFieldId, Object object, int fieldId); 2564c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 257e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount /** 258e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * Set a value value in the Binding class. 259e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * <p> 260e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * Typically, the developer will be able to call the subclass's set method directly. For 261e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * example, if there is a variable <code>x</code> in the Binding, a <code>setX</code> method 262e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * will be generated. However, there are times when the specific subclass of ViewDataBinding 263e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * is unknown, so the generated method cannot be discovered without reflection. The 264e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * setVariable call allows the values of variables to be set without reflection. 265e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * 266e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * @param variableId the BR id of the variable to be set. For example, if the variable is 267e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * <code>x</code>, then variableId will be <code>BR.x</code>. 268e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * @param value The new value of the variable to be set. 269e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * @return <code>true</code> if the variable exists in the binding or <code>false</code> 270e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * otherwise. 271e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount */ 272e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount public abstract boolean setVariable(int variableId, Object value); 273e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 274e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount /** 275e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * Add a listener to be called when reevaluating dirty fields. This also allows automatic 276e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * updates to be halted, but does not stop explicit calls to {@link #executePendingBindings()}. 277e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * 278e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * @param listener The listener to add. 279e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount */ 280e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount public void addOnRebindCallback(OnRebindCallback listener) { 281e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (mRebindCallbacks == null) { 282e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRebindCallbacks = new CallbackRegistry<OnRebindCallback, ViewDataBinding, Void>(REBIND_NOTIFIER); 283e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 284e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRebindCallbacks.add(listener); 285e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 286e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 287e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount /** 288e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * Removes a listener that was added in {@link #addOnRebindCallback(OnRebindCallback)}. 289e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * 290e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * @param listener The listener to remove. 291e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount */ 292e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount public void removeOnRebindCallback(OnRebindCallback listener) { 293e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (mRebindCallbacks != null) { 294e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRebindCallbacks.remove(listener); 295e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 296e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 2974c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 2984c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 2994c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Evaluates the pending bindings, updating any Views that have expressions bound to 3004c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * modified variables. This <b>must</b> be run on the UI thread. 3014c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 302e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount public void executePendingBindings() { 303e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (mIsExecutingPendingBindings) { 304e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount requestRebind(); 305e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount return; 306e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 307447971abca811b11b8c1d8e7bfaa294856d03c16George Mount if (!hasPendingBindings()) { 308447971abca811b11b8c1d8e7bfaa294856d03c16George Mount return; 309447971abca811b11b8c1d8e7bfaa294856d03c16George Mount } 310e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mIsExecutingPendingBindings = true; 311e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRebindHalted = false; 312e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (mRebindCallbacks != null) { 313e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRebindCallbacks.notifyCallbacks(this, REBIND, null); 314e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 315e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount // The onRebindListeners will change mPendingHalted 316e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (mRebindHalted) { 317e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRebindCallbacks.notifyCallbacks(this, HALTED, null); 318e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 319e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 320e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (!mRebindHalted) { 321e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount executeBindings(); 322e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (mRebindCallbacks != null) { 323e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRebindCallbacks.notifyCallbacks(this, REBOUND, null); 324e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 325e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 326e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mIsExecutingPendingBindings = false; 327e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 328e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 329e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount void forceExecuteBindings() { 330e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount executeBindings(); 331e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 332e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 333e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount protected abstract void executeBindings(); 3344c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 3354c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 3364c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Used internally to invalidate flags of included layouts. 337447971abca811b11b8c1d8e7bfaa294856d03c16George Mount * @hide 3384c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 3394c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public abstract void invalidateAll(); 3404c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 3414c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 342447971abca811b11b8c1d8e7bfaa294856d03c16George Mount * @return true if any field has changed and the binding should be evaluated. 343447971abca811b11b8c1d8e7bfaa294856d03c16George Mount * @hide 344447971abca811b11b8c1d8e7bfaa294856d03c16George Mount */ 345447971abca811b11b8c1d8e7bfaa294856d03c16George Mount public abstract boolean hasPendingBindings(); 346447971abca811b11b8c1d8e7bfaa294856d03c16George Mount 347447971abca811b11b8c1d8e7bfaa294856d03c16George Mount /** 3484c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Removes binding listeners to expression variables. 3494c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 3504c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public void unbind() { 3515cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount for (WeakListener weakListener : mLocalFieldObservers) { 3525cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (weakListener != null) { 3535cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount weakListener.unregister(); 3545cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 3555cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 356085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 357085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 3584c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount @Override 3594c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount protected void finalize() throws Throwable { 3604c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount unbind(); 3614c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } 3624c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 363ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount static ViewDataBinding getBinding(View v) { 364ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount if (USE_TAG_ID) { 365ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount return (ViewDataBinding) v.getTag(R.id.dataBinding); 366ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount } else { 367ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount final Object tag = v.getTag(); 368ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount if (tag instanceof ViewDataBinding) { 369ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount return (ViewDataBinding) tag; 370ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount } 371ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount } 372ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount return null; 373ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount } 374ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount 3754c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 3764c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Returns the outermost View in the layout file associated with the Binding. 3774c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * @return the outermost View in the layout file associated with the Binding. 3784c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 379085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar public View getRoot() { 380085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return mRoot; 381085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 382085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 383085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) { 384085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar boolean result = onFieldChange(mLocalFieldId, object, fieldId); 385085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (result) { 386085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar requestRebind(); 387085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 388085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 389085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 390085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar protected boolean unregisterFrom(int localFieldId) { 3915cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount WeakListener listener = mLocalFieldObservers[localFieldId]; 392085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (listener != null) { 393085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return listener.unregister(); 394085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 395085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return false; 396085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 397085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 398085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar protected void requestRebind() { 399e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount synchronized (this) { 400e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (mPendingRebind) { 401e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount return; 402e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 403e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mPendingRebind = true; 404085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 4053f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar if (USE_CHOREOGRAPHER) { 4063f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar mChoreographer.postFrameCallback(mFrameCallback); 4074c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } else { 4083f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar mUIThreadHandler.post(mRebindRunnable); 4094c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } 4103f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar 411085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 412085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 413085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar protected Object getObservedField(int localFieldId) { 4145cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount WeakListener listener = mLocalFieldObservers[localFieldId]; 415085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (listener == null) { 416085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return null; 417085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 418085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return listener.getTarget(); 419085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 420085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 4215cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount private boolean updateRegistration(int localFieldId, Object observable, 4225cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount CreateWeakListener listenerCreator) { 423085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (observable == null) { 424085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return unregisterFrom(localFieldId); 425085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 4265cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount WeakListener listener = mLocalFieldObservers[localFieldId]; 427085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (listener == null) { 4285cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount registerTo(localFieldId, observable, listenerCreator); 429085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return true; 430085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 431085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (listener.getTarget() == observable) { 432085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return false;//nothing to do, same object 433085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 434085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar unregisterFrom(localFieldId); 4355cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount registerTo(localFieldId, observable, listenerCreator); 436085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return true; 437085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 438085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 4395cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected boolean updateRegistration(int localFieldId, Observable observable) { 4405cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER); 4415cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 4425cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 4435cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected boolean updateRegistration(int localFieldId, ObservableList observable) { 4445cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return updateRegistration(localFieldId, observable, CREATE_LIST_LISTENER); 4455cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 4465cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 4475cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected boolean updateRegistration(int localFieldId, ObservableMap observable) { 4485cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return updateRegistration(localFieldId, observable, CREATE_MAP_LISTENER); 4495cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 4505cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 4515cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected void registerTo(int localFieldId, Object observable, 4525cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount CreateWeakListener listenerCreator) { 453085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (observable == null) { 454085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return; 455085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 4565cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount WeakListener listener = mLocalFieldObservers[localFieldId]; 457085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (listener == null) { 4585cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount listener = listenerCreator.create(this, localFieldId); 459085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar mLocalFieldObservers[localFieldId] = listener; 460085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 461085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar listener.setTarget(observable); 462085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 463085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 464ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount protected static ViewDataBinding bind(View view, int layoutId) { 465ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount return DataBindingUtil.bind(view, layoutId); 466ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount } 467ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount 4684c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 46996e1c821dd446d1ed78f8ae61131550588f60a24George Mount * Walks the view hierarchy under root and pulls out tagged Views, includes, and views with 47096e1c821dd446d1ed78f8ae61131550588f60a24George Mount * IDs into an Object[] that is returned. This is used to walk the view hierarchy once to find 47196e1c821dd446d1ed78f8ae61131550588f60a24George Mount * all bound and ID'd views. 47296e1c821dd446d1ed78f8ae61131550588f60a24George Mount * 47396e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param root The root of the view hierarchy to walk. 47496e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param numBindings The total number of ID'd views, views with expressions, and includes 47596e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param includes The include layout information, indexed by their container's index. 47696e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param viewsWithIds Indexes of views that don't have tags, but have IDs. 47796e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @return An array of size numBindings containing all Views in the hierarchy that have IDs 47896e1c821dd446d1ed78f8ae61131550588f60a24George Mount * (with elements in viewsWithIds), are tagged containing expressions, or the bindings for 47996e1c821dd446d1ed78f8ae61131550588f60a24George Mount * included layouts. 48096e1c821dd446d1ed78f8ae61131550588f60a24George Mount */ 48196e1c821dd446d1ed78f8ae61131550588f60a24George Mount protected static Object[] mapBindings(View root, int numBindings, 48296e1c821dd446d1ed78f8ae61131550588f60a24George Mount IncludedLayoutIndex[][] includes, SparseIntArray viewsWithIds) { 48396e1c821dd446d1ed78f8ae61131550588f60a24George Mount Object[] bindings = new Object[numBindings]; 48496e1c821dd446d1ed78f8ae61131550588f60a24George Mount mapBindings(root, bindings, includes, viewsWithIds, true); 48596e1c821dd446d1ed78f8ae61131550588f60a24George Mount return bindings; 48696e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 48796e1c821dd446d1ed78f8ae61131550588f60a24George Mount 48896e1c821dd446d1ed78f8ae61131550588f60a24George Mount /** 48996e1c821dd446d1ed78f8ae61131550588f60a24George Mount * Walks the view hierarchy under roots and pulls out tagged Views, includes, and views with 49096e1c821dd446d1ed78f8ae61131550588f60a24George Mount * IDs into an Object[] that is returned. This is used to walk the view hierarchy once to find 49196e1c821dd446d1ed78f8ae61131550588f60a24George Mount * all bound and ID'd views. 4924c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * 49396e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param roots The root Views of the view hierarchy to walk. This is used with merge tags. 49496e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param numBindings The total number of ID'd views, views with expressions, and includes 49596e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param includes The include layout information, indexed by their container's index. 49696e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param viewsWithIds Indexes of views that don't have tags, but have IDs. 49796e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @return An array of size numBindings containing all Views in the hierarchy that have IDs 49896e1c821dd446d1ed78f8ae61131550588f60a24George Mount * (with elements in viewsWithIds), are tagged containing expressions, or the bindings for 49996e1c821dd446d1ed78f8ae61131550588f60a24George Mount * included layouts. 5004c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 50196e1c821dd446d1ed78f8ae61131550588f60a24George Mount protected static Object[] mapBindings(View[] roots, int numBindings, 50296e1c821dd446d1ed78f8ae61131550588f60a24George Mount IncludedLayoutIndex[][] includes, SparseIntArray viewsWithIds) { 50396e1c821dd446d1ed78f8ae61131550588f60a24George Mount Object[] bindings = new Object[numBindings]; 50496e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int i = 0; i < roots.length; i++) { 50596e1c821dd446d1ed78f8ae61131550588f60a24George Mount mapBindings(roots[i], bindings, includes, viewsWithIds, true); 50600da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 50796e1c821dd446d1ed78f8ae61131550588f60a24George Mount return bindings; 50800da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 50900da715547ee7d5d38a3b8576090ca427a94daa5George Mount 51096e1c821dd446d1ed78f8ae61131550588f60a24George Mount private static void mapBindings(View view, Object[] bindings, 51196e1c821dd446d1ed78f8ae61131550588f60a24George Mount IncludedLayoutIndex[][] includes, SparseIntArray viewsWithIds, boolean isRoot) { 51296e1c821dd446d1ed78f8ae61131550588f60a24George Mount final IncludedLayoutIndex[] includedLayoutIndexes; 51396e1c821dd446d1ed78f8ae61131550588f60a24George Mount final String tag = (String) view.getTag(); 51496e1c821dd446d1ed78f8ae61131550588f60a24George Mount boolean isBound = false; 51596e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (isRoot && tag != null && tag.startsWith("layout")) { 51696e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int underscoreIndex = tag.lastIndexOf('_'); 51796e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (underscoreIndex > 0 && isNumeric(tag, underscoreIndex + 1)) { 51896e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int index = parseTagInt(tag, underscoreIndex + 1); 51996e1c821dd446d1ed78f8ae61131550588f60a24George Mount bindings[index] = view; 52096e1c821dd446d1ed78f8ae61131550588f60a24George Mount includedLayoutIndexes = includes == null ? null : includes[index]; 52196e1c821dd446d1ed78f8ae61131550588f60a24George Mount isBound = true; 52296e1c821dd446d1ed78f8ae61131550588f60a24George Mount } else { 52396e1c821dd446d1ed78f8ae61131550588f60a24George Mount includedLayoutIndexes = null; 52496e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 52596e1c821dd446d1ed78f8ae61131550588f60a24George Mount } else if (tag != null && tag.startsWith(BINDING_TAG_PREFIX)) { 52696e1c821dd446d1ed78f8ae61131550588f60a24George Mount int tagIndex = parseTagInt(tag, BINDING_NUMBER_START); 52796e1c821dd446d1ed78f8ae61131550588f60a24George Mount bindings[tagIndex] = view; 52896e1c821dd446d1ed78f8ae61131550588f60a24George Mount isBound = true; 52996e1c821dd446d1ed78f8ae61131550588f60a24George Mount includedLayoutIndexes = includes == null ? null : includes[tagIndex]; 53095d1b38adeb5963ec5337e7dd6177b4bb5a03619George Mount } else { 53196e1c821dd446d1ed78f8ae61131550588f60a24George Mount // Not a bound view 53296e1c821dd446d1ed78f8ae61131550588f60a24George Mount includedLayoutIndexes = null; 53396e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 53496e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (!isBound) { 53596e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int id = view.getId(); 53696e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (id > 0) { 53796e1c821dd446d1ed78f8ae61131550588f60a24George Mount int index; 53896e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (viewsWithIds != null && (index = viewsWithIds.get(id, -1)) >= 0) { 53996e1c821dd446d1ed78f8ae61131550588f60a24George Mount bindings[index] = view; 54096e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 54196e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 54296e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 54396e1c821dd446d1ed78f8ae61131550588f60a24George Mount 54496e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (view instanceof ViewGroup) { 54596e1c821dd446d1ed78f8ae61131550588f60a24George Mount final ViewGroup viewGroup = (ViewGroup) view; 54696e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int count = viewGroup.getChildCount(); 54796e1c821dd446d1ed78f8ae61131550588f60a24George Mount int minInclude = 0; 54896e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int i = 0; i < count; i++) { 54996e1c821dd446d1ed78f8ae61131550588f60a24George Mount final View child = viewGroup.getChildAt(i); 55096e1c821dd446d1ed78f8ae61131550588f60a24George Mount boolean isInclude = false; 55196e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (includedLayoutIndexes != null) { 55296e1c821dd446d1ed78f8ae61131550588f60a24George Mount String childTag = (String) child.getTag(); 55396e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (childTag != null && childTag.endsWith("_0") && 55496e1c821dd446d1ed78f8ae61131550588f60a24George Mount childTag.startsWith("layout") && childTag.indexOf('/') > 0) { 55596e1c821dd446d1ed78f8ae61131550588f60a24George Mount // This *could* be an include. Test against the expected includes. 55696e1c821dd446d1ed78f8ae61131550588f60a24George Mount int includeIndex = findIncludeIndex(childTag, minInclude, 55796e1c821dd446d1ed78f8ae61131550588f60a24George Mount includedLayoutIndexes); 55896e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (includeIndex >= 0) { 55996e1c821dd446d1ed78f8ae61131550588f60a24George Mount isInclude = true; 56096e1c821dd446d1ed78f8ae61131550588f60a24George Mount minInclude = includeIndex + 1; 56196e1c821dd446d1ed78f8ae61131550588f60a24George Mount IncludedLayoutIndex include = includedLayoutIndexes[includeIndex]; 56296e1c821dd446d1ed78f8ae61131550588f60a24George Mount int lastMatchingIndex = findLastMatching(viewGroup, i); 56396e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (lastMatchingIndex == i) { 5649bdb2415487832e88a05c7bd19391b05440b468eGeorge Mount bindings[include.index] = DataBindingUtil.bind(child, 5659bdb2415487832e88a05c7bd19391b05440b468eGeorge Mount include.layoutId); 56696e1c821dd446d1ed78f8ae61131550588f60a24George Mount } else { 56796e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int includeCount = lastMatchingIndex - i + 1; 56896e1c821dd446d1ed78f8ae61131550588f60a24George Mount final View[] included = new View[includeCount]; 56996e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int j = 0; j < includeCount; j++) { 57096e1c821dd446d1ed78f8ae61131550588f60a24George Mount included[j] = viewGroup.getChildAt(i + j); 57196e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 5729bdb2415487832e88a05c7bd19391b05440b468eGeorge Mount bindings[include.index] = DataBindingUtil.bind(included, 5739bdb2415487832e88a05c7bd19391b05440b468eGeorge Mount include.layoutId); 57496e1c821dd446d1ed78f8ae61131550588f60a24George Mount i += includeCount - 1; 57596e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 57696e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 57796e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 57896e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 57996e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (!isInclude) { 58096e1c821dd446d1ed78f8ae61131550588f60a24George Mount mapBindings(child, bindings, includes, viewsWithIds, false); 58196e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 58296e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 5834c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } 58496e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 58596e1c821dd446d1ed78f8ae61131550588f60a24George Mount 58696e1c821dd446d1ed78f8ae61131550588f60a24George Mount private static int findIncludeIndex(String tag, int minInclude, 58796e1c821dd446d1ed78f8ae61131550588f60a24George Mount IncludedLayoutIndex[] layoutIndexes) { 58896e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int slashIndex = tag.indexOf('/'); 58996e1c821dd446d1ed78f8ae61131550588f60a24George Mount final CharSequence layoutName = tag.subSequence(slashIndex + 1, tag.length() - 2); 59096e1c821dd446d1ed78f8ae61131550588f60a24George Mount 59196e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int length = layoutIndexes.length; 59296e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int i = minInclude; i < length; i++) { 59396e1c821dd446d1ed78f8ae61131550588f60a24George Mount final IncludedLayoutIndex layoutIndex = layoutIndexes[i]; 59496e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (TextUtils.equals(layoutName, layoutIndex.layout)) { 59596e1c821dd446d1ed78f8ae61131550588f60a24George Mount return i; 59696e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 59700da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 59896e1c821dd446d1ed78f8ae61131550588f60a24George Mount return -1; 59900da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 60000da715547ee7d5d38a3b8576090ca427a94daa5George Mount 60196e1c821dd446d1ed78f8ae61131550588f60a24George Mount private static int findLastMatching(ViewGroup viewGroup, int firstIncludedIndex) { 60296e1c821dd446d1ed78f8ae61131550588f60a24George Mount final View firstView = viewGroup.getChildAt(firstIncludedIndex); 60396e1c821dd446d1ed78f8ae61131550588f60a24George Mount final String firstViewTag = (String) firstView.getTag(); 60496e1c821dd446d1ed78f8ae61131550588f60a24George Mount final String tagBase = firstViewTag.substring(0, firstViewTag.length() - 1); // don't include the "0" 60596e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int tagSequenceIndex = tagBase.length(); 60696e1c821dd446d1ed78f8ae61131550588f60a24George Mount 60796e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int count = viewGroup.getChildCount(); 60896e1c821dd446d1ed78f8ae61131550588f60a24George Mount int max = firstIncludedIndex; 60996e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int i = firstIncludedIndex + 1; i < count; i++) { 61096e1c821dd446d1ed78f8ae61131550588f60a24George Mount final View view = viewGroup.getChildAt(i); 61196e1c821dd446d1ed78f8ae61131550588f60a24George Mount final String tag = (String) view.getTag(); 61296e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (tag != null && tag.startsWith(tagBase)) { 61396e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (tag.length() == firstViewTag.length() && tag.charAt(tag.length() - 1) == '0') { 61496e1c821dd446d1ed78f8ae61131550588f60a24George Mount return max; // Found another instance of the include 61596e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 61696e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (isNumeric(tag, tagSequenceIndex)) { 61796e1c821dd446d1ed78f8ae61131550588f60a24George Mount max = i; 61896e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 61996e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 62096e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 62196e1c821dd446d1ed78f8ae61131550588f60a24George Mount return max; 62234a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount } 62334a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount 62496e1c821dd446d1ed78f8ae61131550588f60a24George Mount private static boolean isNumeric(String tag, int startIndex) { 62596e1c821dd446d1ed78f8ae61131550588f60a24George Mount int length = tag.length(); 62696e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (length == startIndex) { 62796e1c821dd446d1ed78f8ae61131550588f60a24George Mount return false; // no numerals 62896e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 62996e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int i = startIndex; i < length; i++) { 63096e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (!Character.isDigit(tag.charAt(i))) { 63196e1c821dd446d1ed78f8ae61131550588f60a24George Mount return false; 63295d1b38adeb5963ec5337e7dd6177b4bb5a03619George Mount } 63395d1b38adeb5963ec5337e7dd6177b4bb5a03619George Mount } 63496e1c821dd446d1ed78f8ae61131550588f60a24George Mount return true; 63595d1b38adeb5963ec5337e7dd6177b4bb5a03619George Mount } 63695d1b38adeb5963ec5337e7dd6177b4bb5a03619George Mount 63734a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount /** 63800da715547ee7d5d38a3b8576090ca427a94daa5George Mount * Parse the tag without creating a new String object. This is fast and assumes the 63900da715547ee7d5d38a3b8576090ca427a94daa5George Mount * tag is in the correct format. 64000da715547ee7d5d38a3b8576090ca427a94daa5George Mount * @param str The tag string. 64100da715547ee7d5d38a3b8576090ca427a94daa5George Mount * @return The binding tag number parsed from the tag string. 64200da715547ee7d5d38a3b8576090ca427a94daa5George Mount */ 64396e1c821dd446d1ed78f8ae61131550588f60a24George Mount private static int parseTagInt(String str, int startIndex) { 64400da715547ee7d5d38a3b8576090ca427a94daa5George Mount final int end = str.length(); 64500da715547ee7d5d38a3b8576090ca427a94daa5George Mount int val = 0; 64696e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int i = startIndex; i < end; i++) { 64700da715547ee7d5d38a3b8576090ca427a94daa5George Mount val *= 10; 64800da715547ee7d5d38a3b8576090ca427a94daa5George Mount char c = str.charAt(i); 64900da715547ee7d5d38a3b8576090ca427a94daa5George Mount val += (c - '0'); 65000da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 65100da715547ee7d5d38a3b8576090ca427a94daa5George Mount return val; 65200da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 65300da715547ee7d5d38a3b8576090ca427a94daa5George Mount 6544c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private static abstract class WeakListener<T> { 6554c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private final WeakReference<ViewDataBinding> mBinder; 6565cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected final int mLocalFieldId; 6575cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount private T mTarget; 658085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 6594c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakListener(ViewDataBinding binder, int localFieldId) { 6604c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount mBinder = new WeakReference<ViewDataBinding>(binder); 6615cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount mLocalFieldId = localFieldId; 662085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 663085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 6645cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount public void setTarget(T object) { 6655cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount unregister(); 6665cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount mTarget = object; 6675cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (mTarget != null) { 6685cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount addListener(mTarget); 669085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 670085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 671085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 672085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar public boolean unregister() { 6735cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount boolean unregistered = false; 6745cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (mTarget != null) { 6755cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount removeListener(mTarget); 6765cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount unregistered = true; 677085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 678085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar mTarget = null; 6795cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return unregistered; 680085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 681085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 6825cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount public T getTarget() { 6835cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return mTarget; 684085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 6855cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 6864c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount protected ViewDataBinding getBinder() { 6874c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount ViewDataBinding binder = mBinder.get(); 6885cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (binder == null) { 6895cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount unregister(); // The binder is dead 6905cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 6915cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return binder; 6925cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 6935cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 6945cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected abstract void addListener(T target); 6955cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected abstract void removeListener(T target); 696085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 697085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 6984c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private static class WeakPropertyListener extends WeakListener<Observable> 6995cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount implements OnPropertyChangedListener { 7004c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakPropertyListener(ViewDataBinding binder, int localFieldId) { 7015cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount super(binder, localFieldId); 7025cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7035cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7045cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 7055cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected void addListener(Observable target) { 7065cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount target.addOnPropertyChangedListener(this); 7075cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7085cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7095cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 7105cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected void removeListener(Observable target) { 7115cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount target.removeOnPropertyChangedListener(this); 712085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 713085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 714085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar @Override 715293de28642305ce210e1d2a1cfe0abfa4f737d7aGeorge Mount public void onPropertyChanged(Observable sender, int fieldId) { 7164c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount ViewDataBinding binder = getBinder(); 7175cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (binder == null) { 7185cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return; 7195cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 720085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar Observable obj = getTarget(); 7215cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (obj != sender) { 7225cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return; // notification from the wrong object? 723085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 7245cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount binder.handleFieldChange(mLocalFieldId, sender, fieldId); 725085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 726085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 7275cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7284c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private static class WeakListListener extends WeakListener<ObservableList> 7295cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount implements OnListChangedListener { 7305cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7314c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakListListener(ViewDataBinding binder, int localFieldId) { 7325cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount super(binder, localFieldId); 7335cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7345cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7355cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 7365cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount public void onChanged() { 7374c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount ViewDataBinding binder = getBinder(); 7385cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (binder == null) { 7395cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return; 7405cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7415cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount ObservableList target = getTarget(); 7425cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (target == null) { 7435cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return; // We don't expect any notifications from null targets 7445cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7455cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount binder.handleFieldChange(mLocalFieldId, target, 0); 7465cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7475cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7485cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 7495cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount public void onItemRangeChanged(int positionStart, int itemCount) { 7505cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount onChanged(); 7515cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7525cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7535cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 7545cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount public void onItemRangeInserted(int positionStart, int itemCount) { 7555cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount onChanged(); 7565cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7575cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7585cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 7595cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { 7605cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount onChanged(); 7615cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7625cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7635cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 7645cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount public void onItemRangeRemoved(int positionStart, int itemCount) { 7655cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount onChanged(); 7665cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7675cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7685cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 7695cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected void addListener(ObservableList target) { 7705cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount target.addOnListChangedListener(this); 7715cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7725cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7735cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 7745cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected void removeListener(ObservableList target) { 7755cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount target.removeOnListChangedListener(this); 7765cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7775cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7785cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7794c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private static class WeakMapListener extends WeakListener<ObservableMap> 7805cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount implements OnMapChangedListener { 7814c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakMapListener(ViewDataBinding binder, int localFieldId) { 7825cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount super(binder, localFieldId); 7835cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7845cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7855cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 7865cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected void addListener(ObservableMap target) { 7875cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount target.addOnMapChangedListener(this); 7885cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7895cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7905cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 7915cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected void removeListener(ObservableMap target) { 7925cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount target.removeOnMapChangedListener(this); 7935cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7945cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7955cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 7962c86cdbaf189e2b1774af7f64a2974de9321673fGeorge Mount public void onMapChanged(ObservableMap sender, Object key) { 7974c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount ViewDataBinding binder = getBinder(); 7985cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (binder == null || sender != getTarget()) { 7995cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return; 8005cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 8015cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount binder.handleFieldChange(mLocalFieldId, sender, 0); 8025cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 8035cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 8045cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 8055cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount private interface CreateWeakListener { 8064c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount WeakListener create(ViewDataBinding viewDataBinding, int localFieldId); 8075cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 80896e1c821dd446d1ed78f8ae61131550588f60a24George Mount 80996e1c821dd446d1ed78f8ae61131550588f60a24George Mount protected static class IncludedLayoutIndex { 81096e1c821dd446d1ed78f8ae61131550588f60a24George Mount public final String layout; 81196e1c821dd446d1ed78f8ae61131550588f60a24George Mount public final int index; 81296e1c821dd446d1ed78f8ae61131550588f60a24George Mount public final int layoutId; 81396e1c821dd446d1ed78f8ae61131550588f60a24George Mount 81496e1c821dd446d1ed78f8ae61131550588f60a24George Mount public IncludedLayoutIndex(String layout, int index, int layoutId) { 81596e1c821dd446d1ed78f8ae61131550588f60a24George Mount this.layout = layout; 81696e1c821dd446d1ed78f8ae61131550588f60a24George Mount this.index = index; 81796e1c821dd446d1ed78f8ae61131550588f60a24George Mount this.layoutId = layoutId; 81896e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 81996e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 820085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar} 821