ViewDataBinding.java revision 4d4979490e1fa374c0d7f3599fed0a9e83a579d0
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; 284d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mountimport android.util.Log; 294c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mountimport android.util.SparseIntArray; 303f73e3149732132c02f5d19aab7b5da429794058Yigit Boyarimport android.view.Choreographer; 31085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarimport android.view.View; 325914aa7da50a90a4c705b5be02a215499d0ad232George Mountimport android.view.View.OnAttachStateChangeListener; 3300da715547ee7d5d38a3b8576090ca427a94daa5George Mountimport android.view.ViewGroup; 34085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 35085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarimport java.lang.ref.WeakReference; 36085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 374c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mountpublic abstract class ViewDataBinding { 384d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount private final static String TAG = "ViewDataBinding"; 394c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 404c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 414c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Instead of directly accessing Build.VERSION.SDK_INT, generated code uses this value so that 424c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * we can test API dependent behavior. 434c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 444c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount static int SDK_INT = VERSION.SDK_INT; 454c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 46e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount private static final int REBIND = 1; 47e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount private static final int HALTED = 2; 48e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount private static final int REBOUND = 3; 49e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 504c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 514c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Prefix for android:tag on Views with binding. The root View and include tags will not have 524c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * android:tag attributes and will use ids instead. 534c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 547ff60c24c6de7ba0c674fe65a82ad4a88dab2e5dGeorge Mount public static final String BINDING_TAG_PREFIX = "binding_"; 554c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 564c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount // The length of BINDING_TAG_PREFIX prevents calling length repeatedly. 5700da715547ee7d5d38a3b8576090ca427a94daa5George Mount private static final int BINDING_NUMBER_START = BINDING_TAG_PREFIX.length(); 5800da715547ee7d5d38a3b8576090ca427a94daa5George Mount 59e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount // ICS (v 14) fixes a leak when using setTag(int, Object) 60e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount private static final boolean USE_TAG_ID = DataBinderMapper.TARGET_MIN_SDK >= 14; 61e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount 623f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar private static final boolean USE_CHOREOGRAPHER = SDK_INT >= 16; 633f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar 644c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 654c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Method object extracted out to attach a listener to a bound Observable object. 664c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 675cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount private static final CreateWeakListener CREATE_PROPERTY_LISTENER = new CreateWeakListener() { 685cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 694c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) { 70722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount return new WeakPropertyListener(viewDataBinding, localFieldId).getListener(); 715cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 725cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount }; 735cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 744c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 754c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Method object extracted out to attach a listener to a bound ObservableList object. 764c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 775cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount private static final CreateWeakListener CREATE_LIST_LISTENER = new CreateWeakListener() { 785cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 794c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) { 80722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount return new WeakListListener(viewDataBinding, localFieldId).getListener(); 815cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 825cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount }; 835cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 844c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 854c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Method object extracted out to attach a listener to a bound ObservableMap object. 864c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 875cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount private static final CreateWeakListener CREATE_MAP_LISTENER = new CreateWeakListener() { 885cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 894c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) { 90722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount return new WeakMapListener(viewDataBinding, localFieldId).getListener(); 915cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 925cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount }; 935cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 94e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount private static final CallbackRegistry.NotifierCallback<OnRebindCallback, ViewDataBinding, Void> 95e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount REBIND_NOTIFIER = new NotifierCallback<OnRebindCallback, ViewDataBinding, Void>() { 96e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount @Override 97e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount public void onNotifyCallback(OnRebindCallback callback, ViewDataBinding sender, int mode, 98e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount Void arg2) { 99e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount switch (mode) { 100e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount case REBIND: 101e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (!callback.onPreBind(sender)) { 102e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount sender.mRebindHalted = true; 103e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 104e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount break; 105e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount case HALTED: 106e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount callback.onCanceled(sender); 107e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount break; 108e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount case REBOUND: 109e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount callback.onBound(sender); 110e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount break; 111e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 112e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 113e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount }; 114e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 1155914aa7da50a90a4c705b5be02a215499d0ad232George Mount private static final OnAttachStateChangeListener ROOT_REATTACHED_LISTENER; 1165914aa7da50a90a4c705b5be02a215499d0ad232George Mount 1175914aa7da50a90a4c705b5be02a215499d0ad232George Mount static { 1185914aa7da50a90a4c705b5be02a215499d0ad232George Mount if (VERSION.SDK_INT < VERSION_CODES.KITKAT) { 1195914aa7da50a90a4c705b5be02a215499d0ad232George Mount ROOT_REATTACHED_LISTENER = null; 1205914aa7da50a90a4c705b5be02a215499d0ad232George Mount } else { 1215914aa7da50a90a4c705b5be02a215499d0ad232George Mount ROOT_REATTACHED_LISTENER = new OnAttachStateChangeListener() { 1225914aa7da50a90a4c705b5be02a215499d0ad232George Mount @TargetApi(VERSION_CODES.KITKAT) 1235914aa7da50a90a4c705b5be02a215499d0ad232George Mount @Override 1245914aa7da50a90a4c705b5be02a215499d0ad232George Mount public void onViewAttachedToWindow(View v) { 1255914aa7da50a90a4c705b5be02a215499d0ad232George Mount // execute the pending bindings. 1264d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount final ViewDataBinding binding = getBinding(v); 1273f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar binding.mRebindRunnable.run(); 1285914aa7da50a90a4c705b5be02a215499d0ad232George Mount v.removeOnAttachStateChangeListener(this); 1295914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1305914aa7da50a90a4c705b5be02a215499d0ad232George Mount 1315914aa7da50a90a4c705b5be02a215499d0ad232George Mount @Override 1325914aa7da50a90a4c705b5be02a215499d0ad232George Mount public void onViewDetachedFromWindow(View v) { 1335914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1345914aa7da50a90a4c705b5be02a215499d0ad232George Mount }; 1355914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1365914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1375914aa7da50a90a4c705b5be02a215499d0ad232George Mount 1384c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 1394c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Runnable executed on animation heartbeat to rebind the dirty Views. 1404c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 1413f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar private final Runnable mRebindRunnable = new Runnable() { 142085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar @Override 143085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar public void run() { 144e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount synchronized (this) { 145e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mPendingRebind = false; 146e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 147e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) { 148e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount // Nested so that we don't get a lint warning in IntelliJ 149e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (!mRoot.isAttachedToWindow()) { 150e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount // Don't execute the pending bindings until the View 151e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount // is attached again. 152e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRoot.removeOnAttachStateChangeListener(ROOT_REATTACHED_LISTENER); 153e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRoot.addOnAttachStateChangeListener(ROOT_REATTACHED_LISTENER); 154e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount return; 1555914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1564c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } 157e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount executePendingBindings(); 158085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 159085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar }; 160085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 1614c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 1624c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Flag indicates that there are pending bindings that need to be reevaluated. 1634c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 1644c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private boolean mPendingRebind = false; 1654c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 1664c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 167e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * Indicates that a onPreBind has stopped the executePendingBindings call. 168e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount */ 169e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount private boolean mRebindHalted = false; 170e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 171e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount /** 1724c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * The observed expressions. 1734c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 1744c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private WeakListener[] mLocalFieldObservers; 1754c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 1764c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 1774c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * The root View that this Binding is associated with. 1784c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 1794c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private final View mRoot; 1804c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 181e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount /** 182e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * The collection of OnRebindCallbacks. 183e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount */ 184e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount private CallbackRegistry<OnRebindCallback, ViewDataBinding, Void> mRebindCallbacks; 185e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 186e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount /** 187e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * Flag to prevent reentrant executePendingBinding calls. 188e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount */ 189e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount private boolean mIsExecutingPendingBindings; 190e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 1913f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar // null api < 16 1923f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar private Choreographer mChoreographer; 1933f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar 1943f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar private final Choreographer.FrameCallback mFrameCallback; 1953f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar 1963f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar // null api >= 16 1973f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar private Handler mUIThreadHandler; 1983f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar 1994c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount protected ViewDataBinding(View root, int localFieldCount) { 2005cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount mLocalFieldObservers = new WeakListener[localFieldCount]; 2014c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount this.mRoot = root; 2023f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar if (Looper.myLooper() == null) { 2033f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar throw new IllegalStateException("DataBinding must be created in view's UI Thread"); 2043f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar } 2053f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar if (USE_CHOREOGRAPHER) { 2063f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar mChoreographer = Choreographer.getInstance(); 2073f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar mFrameCallback = new Choreographer.FrameCallback() { 2083f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar @Override 2093f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar public void doFrame(long frameTimeNanos) { 2103f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar mRebindRunnable.run(); 2113f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar } 2123f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar }; 2133f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar } else { 2143f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar mFrameCallback = null; 2153f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar mUIThreadHandler = new Handler(Looper.myLooper()); 2163f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar } 2173f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar requestRebind(); 21896e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 21996e1c821dd446d1ed78f8ae61131550588f60a24George Mount 22096e1c821dd446d1ed78f8ae61131550588f60a24George Mount protected void setRootTag(View view) { 22196e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (USE_TAG_ID) { 22296e1c821dd446d1ed78f8ae61131550588f60a24George Mount view.setTag(R.id.dataBinding, this); 22396e1c821dd446d1ed78f8ae61131550588f60a24George Mount } else { 22496e1c821dd446d1ed78f8ae61131550588f60a24George Mount view.setTag(this); 22596e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 22696e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 22796e1c821dd446d1ed78f8ae61131550588f60a24George Mount 22896e1c821dd446d1ed78f8ae61131550588f60a24George Mount protected void setRootTag(View[] views) { 229e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount if (USE_TAG_ID) { 23096e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (View view : views) { 23196e1c821dd446d1ed78f8ae61131550588f60a24George Mount view.setTag(R.id.dataBinding, this); 23296e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 233e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount } else { 23496e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (View view : views) { 23596e1c821dd446d1ed78f8ae61131550588f60a24George Mount view.setTag(this); 23696e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 237e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount } 2385cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 2395cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 2404c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public static int getBuildSdkInt() { 2414c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount return SDK_INT; 2424c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } 2434c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 2444c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 2454c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Called when an observed object changes. Sets the appropriate dirty flag if applicable. 2464c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * @param localFieldId The index into mLocalFieldObservers that this Object resides in. 2474c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * @param object The object that has changed. 248fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount * @param fieldId The BR ID of the field being changed or _all if 2494c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * no specific field is being notified. 2504c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * @return true if this change should cause a change to the UI. 2514c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 2524c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount protected abstract boolean onFieldChange(int localFieldId, Object object, int fieldId); 2534c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 254e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount /** 255e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * Set a value value in the Binding class. 256e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * <p> 257e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * Typically, the developer will be able to call the subclass's set method directly. For 258e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * example, if there is a variable <code>x</code> in the Binding, a <code>setX</code> method 259e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * will be generated. However, there are times when the specific subclass of ViewDataBinding 260e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * is unknown, so the generated method cannot be discovered without reflection. The 261e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * setVariable call allows the values of variables to be set without reflection. 262e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * 263e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * @param variableId the BR id of the variable to be set. For example, if the variable is 264e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * <code>x</code>, then variableId will be <code>BR.x</code>. 265e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * @param value The new value of the variable to be set. 266e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * @return <code>true</code> if the variable exists in the binding or <code>false</code> 267e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * otherwise. 268e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount */ 269e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount public abstract boolean setVariable(int variableId, Object value); 270e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 271e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount /** 272e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * Add a listener to be called when reevaluating dirty fields. This also allows automatic 273e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * updates to be halted, but does not stop explicit calls to {@link #executePendingBindings()}. 274e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * 275e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * @param listener The listener to add. 276e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount */ 277e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount public void addOnRebindCallback(OnRebindCallback listener) { 278e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (mRebindCallbacks == null) { 279e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRebindCallbacks = new CallbackRegistry<OnRebindCallback, ViewDataBinding, Void>(REBIND_NOTIFIER); 280e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 281e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRebindCallbacks.add(listener); 282e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 283e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 284e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount /** 285e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * Removes a listener that was added in {@link #addOnRebindCallback(OnRebindCallback)}. 286e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * 287e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * @param listener The listener to remove. 288e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount */ 289e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount public void removeOnRebindCallback(OnRebindCallback listener) { 290e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (mRebindCallbacks != null) { 291e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRebindCallbacks.remove(listener); 292e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 293e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 2944c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 2954c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 2964c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Evaluates the pending bindings, updating any Views that have expressions bound to 2974c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * modified variables. This <b>must</b> be run on the UI thread. 2984c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 299e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount public void executePendingBindings() { 300e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (mIsExecutingPendingBindings) { 301e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount requestRebind(); 302e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount return; 303e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 304447971abca811b11b8c1d8e7bfaa294856d03c16George Mount if (!hasPendingBindings()) { 305447971abca811b11b8c1d8e7bfaa294856d03c16George Mount return; 306447971abca811b11b8c1d8e7bfaa294856d03c16George Mount } 307e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mIsExecutingPendingBindings = true; 308e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRebindHalted = false; 309e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (mRebindCallbacks != null) { 310e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRebindCallbacks.notifyCallbacks(this, REBIND, null); 311e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 312e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount // The onRebindListeners will change mPendingHalted 313e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (mRebindHalted) { 314e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRebindCallbacks.notifyCallbacks(this, HALTED, null); 315e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 316e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 317e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (!mRebindHalted) { 318e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount executeBindings(); 319e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (mRebindCallbacks != null) { 320e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRebindCallbacks.notifyCallbacks(this, REBOUND, null); 321e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 322e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 323e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mIsExecutingPendingBindings = false; 324e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 325e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 326e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount void forceExecuteBindings() { 327e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount executeBindings(); 328e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 329e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 330e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount protected abstract void executeBindings(); 3314c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 3324c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 3334c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Used internally to invalidate flags of included layouts. 334447971abca811b11b8c1d8e7bfaa294856d03c16George Mount * @hide 3354c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 3364c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public abstract void invalidateAll(); 3374c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 3384c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 339447971abca811b11b8c1d8e7bfaa294856d03c16George Mount * @return true if any field has changed and the binding should be evaluated. 340447971abca811b11b8c1d8e7bfaa294856d03c16George Mount * @hide 341447971abca811b11b8c1d8e7bfaa294856d03c16George Mount */ 342447971abca811b11b8c1d8e7bfaa294856d03c16George Mount public abstract boolean hasPendingBindings(); 343447971abca811b11b8c1d8e7bfaa294856d03c16George Mount 344447971abca811b11b8c1d8e7bfaa294856d03c16George Mount /** 3454c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Removes binding listeners to expression variables. 3464c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 3474c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public void unbind() { 3485cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount for (WeakListener weakListener : mLocalFieldObservers) { 3495cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (weakListener != null) { 3505cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount weakListener.unregister(); 3515cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 3525cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 353085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 354085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 3554c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount @Override 3564c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount protected void finalize() throws Throwable { 3574c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount unbind(); 3584c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } 3594c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 360ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount static ViewDataBinding getBinding(View v) { 3614d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount if (v != null) { 3624d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount if (USE_TAG_ID) { 3634d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount return (ViewDataBinding) v.getTag(R.id.dataBinding); 3644d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount } else { 3654d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount final Object tag = v.getTag(); 3664d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount if (tag instanceof ViewDataBinding) { 3674d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount return (ViewDataBinding) tag; 3684d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount } 369ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount } 370ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount } 371ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount return null; 372ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount } 373ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount 3744c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 3754c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Returns the outermost View in the layout file associated with the Binding. 3764c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * @return the outermost View in the layout file associated with the Binding. 3774c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 378085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar public View getRoot() { 379085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return mRoot; 380085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 381085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 382085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) { 383085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar boolean result = onFieldChange(mLocalFieldId, object, fieldId); 384085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (result) { 385085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar requestRebind(); 386085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 387085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 388085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 389085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar protected boolean unregisterFrom(int localFieldId) { 3905cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount WeakListener listener = mLocalFieldObservers[localFieldId]; 391085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (listener != null) { 392085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return listener.unregister(); 393085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 394085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return false; 395085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 396085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 397085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar protected void requestRebind() { 398e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount synchronized (this) { 399e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (mPendingRebind) { 400e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount return; 401e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 402e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mPendingRebind = true; 403085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 4043f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar if (USE_CHOREOGRAPHER) { 4053f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar mChoreographer.postFrameCallback(mFrameCallback); 4064c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } else { 4073f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar mUIThreadHandler.post(mRebindRunnable); 4084c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } 4093f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar 410085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 411085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 412085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar protected Object getObservedField(int localFieldId) { 4135cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount WeakListener listener = mLocalFieldObservers[localFieldId]; 414085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (listener == null) { 415085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return null; 416085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 417085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return listener.getTarget(); 418085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 419085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 4205cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount private boolean updateRegistration(int localFieldId, Object observable, 4215cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount CreateWeakListener listenerCreator) { 422085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (observable == null) { 423085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return unregisterFrom(localFieldId); 424085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 4255cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount WeakListener listener = mLocalFieldObservers[localFieldId]; 426085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (listener == null) { 4275cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount registerTo(localFieldId, observable, listenerCreator); 428085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return true; 429085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 430085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (listener.getTarget() == observable) { 431085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return false;//nothing to do, same object 432085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 433085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar unregisterFrom(localFieldId); 4345cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount registerTo(localFieldId, observable, listenerCreator); 435085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return true; 436085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 437085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 4385cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected boolean updateRegistration(int localFieldId, Observable observable) { 4395cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER); 4405cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 4415cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 4425cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected boolean updateRegistration(int localFieldId, ObservableList observable) { 4435cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return updateRegistration(localFieldId, observable, CREATE_LIST_LISTENER); 4445cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 4455cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 4465cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected boolean updateRegistration(int localFieldId, ObservableMap observable) { 4475cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return updateRegistration(localFieldId, observable, CREATE_MAP_LISTENER); 4485cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 4495cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 4505cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected void registerTo(int localFieldId, Object observable, 4515cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount CreateWeakListener listenerCreator) { 452085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (observable == null) { 453085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return; 454085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 4555cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount WeakListener listener = mLocalFieldObservers[localFieldId]; 456085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (listener == null) { 4575cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount listener = listenerCreator.create(this, localFieldId); 458085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar mLocalFieldObservers[localFieldId] = listener; 459085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 460085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar listener.setTarget(observable); 461085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 462085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 463ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount protected static ViewDataBinding bind(View view, int layoutId) { 464ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount return DataBindingUtil.bind(view, layoutId); 465ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount } 466ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount 4674c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 46896e1c821dd446d1ed78f8ae61131550588f60a24George Mount * Walks the view hierarchy under root and pulls out tagged Views, includes, and views with 46996e1c821dd446d1ed78f8ae61131550588f60a24George Mount * IDs into an Object[] that is returned. This is used to walk the view hierarchy once to find 47096e1c821dd446d1ed78f8ae61131550588f60a24George Mount * all bound and ID'd views. 47196e1c821dd446d1ed78f8ae61131550588f60a24George Mount * 47296e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param root The root of the view hierarchy to walk. 47396e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param numBindings The total number of ID'd views, views with expressions, and includes 47496e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param includes The include layout information, indexed by their container's index. 47596e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param viewsWithIds Indexes of views that don't have tags, but have IDs. 47696e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @return An array of size numBindings containing all Views in the hierarchy that have IDs 47796e1c821dd446d1ed78f8ae61131550588f60a24George Mount * (with elements in viewsWithIds), are tagged containing expressions, or the bindings for 47896e1c821dd446d1ed78f8ae61131550588f60a24George Mount * included layouts. 47996e1c821dd446d1ed78f8ae61131550588f60a24George Mount */ 48096e1c821dd446d1ed78f8ae61131550588f60a24George Mount protected static Object[] mapBindings(View root, int numBindings, 48196e1c821dd446d1ed78f8ae61131550588f60a24George Mount IncludedLayoutIndex[][] includes, SparseIntArray viewsWithIds) { 48296e1c821dd446d1ed78f8ae61131550588f60a24George Mount Object[] bindings = new Object[numBindings]; 48396e1c821dd446d1ed78f8ae61131550588f60a24George Mount mapBindings(root, bindings, includes, viewsWithIds, true); 48496e1c821dd446d1ed78f8ae61131550588f60a24George Mount return bindings; 48596e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 48696e1c821dd446d1ed78f8ae61131550588f60a24George Mount 48796e1c821dd446d1ed78f8ae61131550588f60a24George Mount /** 48896e1c821dd446d1ed78f8ae61131550588f60a24George Mount * Walks the view hierarchy under roots and pulls out tagged Views, includes, and views with 48996e1c821dd446d1ed78f8ae61131550588f60a24George Mount * IDs into an Object[] that is returned. This is used to walk the view hierarchy once to find 49096e1c821dd446d1ed78f8ae61131550588f60a24George Mount * all bound and ID'd views. 4914c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * 49296e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param roots The root Views of the view hierarchy to walk. This is used with merge tags. 49396e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param numBindings The total number of ID'd views, views with expressions, and includes 49496e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param includes The include layout information, indexed by their container's index. 49596e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param viewsWithIds Indexes of views that don't have tags, but have IDs. 49696e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @return An array of size numBindings containing all Views in the hierarchy that have IDs 49796e1c821dd446d1ed78f8ae61131550588f60a24George Mount * (with elements in viewsWithIds), are tagged containing expressions, or the bindings for 49896e1c821dd446d1ed78f8ae61131550588f60a24George Mount * included layouts. 4994c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 50096e1c821dd446d1ed78f8ae61131550588f60a24George Mount protected static Object[] mapBindings(View[] roots, int numBindings, 50196e1c821dd446d1ed78f8ae61131550588f60a24George Mount IncludedLayoutIndex[][] includes, SparseIntArray viewsWithIds) { 50296e1c821dd446d1ed78f8ae61131550588f60a24George Mount Object[] bindings = new Object[numBindings]; 50396e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int i = 0; i < roots.length; i++) { 50496e1c821dd446d1ed78f8ae61131550588f60a24George Mount mapBindings(roots[i], bindings, includes, viewsWithIds, true); 50500da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 50696e1c821dd446d1ed78f8ae61131550588f60a24George Mount return bindings; 50700da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 50800da715547ee7d5d38a3b8576090ca427a94daa5George Mount 5094d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount protected static void validateFragmentBinding(ViewDataBinding binding, String fieldName) { 5104d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount if (binding == null) { 5114d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount Log.e(TAG, "The fragment " + fieldName + " has not generated a bound view. " + 5124d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount "Use DataBindingUtil.inflate, the generated Binding class's inflate method, " + 5134d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount "or the generated Binding class's bind method to ensure a bound view from " + 5144d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount "the fragment's onCreateView method."); 5154d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount } 5164d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount } 5174d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount 51896e1c821dd446d1ed78f8ae61131550588f60a24George Mount private static void mapBindings(View view, Object[] bindings, 51996e1c821dd446d1ed78f8ae61131550588f60a24George Mount IncludedLayoutIndex[][] includes, SparseIntArray viewsWithIds, boolean isRoot) { 52096e1c821dd446d1ed78f8ae61131550588f60a24George Mount final IncludedLayoutIndex[] includedLayoutIndexes; 5214d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount final ViewDataBinding fragmentBinding = getBinding(view); 5224d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount if (fragmentBinding != null) { 5234d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount // Must be a fragment 5244d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount final int fragmentId = view.getId(); 5254d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount final int index = (viewsWithIds == null) ? 0 : viewsWithIds.get(fragmentId); 5264d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount if (fragmentId > 0) { 5274d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount bindings[index] = view; 5284d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount } else { 5294d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount // A fragment without an ID doesn't have any binding expressions 5304d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount // nor can it be accessed. We can just ignore it. 5314d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount } 5324d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount return; 5334d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount } 53496e1c821dd446d1ed78f8ae61131550588f60a24George Mount final String tag = (String) view.getTag(); 53596e1c821dd446d1ed78f8ae61131550588f60a24George Mount boolean isBound = false; 53696e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (isRoot && tag != null && tag.startsWith("layout")) { 53796e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int underscoreIndex = tag.lastIndexOf('_'); 53896e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (underscoreIndex > 0 && isNumeric(tag, underscoreIndex + 1)) { 53996e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int index = parseTagInt(tag, underscoreIndex + 1); 54096e1c821dd446d1ed78f8ae61131550588f60a24George Mount bindings[index] = view; 54196e1c821dd446d1ed78f8ae61131550588f60a24George Mount includedLayoutIndexes = includes == null ? null : includes[index]; 54296e1c821dd446d1ed78f8ae61131550588f60a24George Mount isBound = true; 54396e1c821dd446d1ed78f8ae61131550588f60a24George Mount } else { 54496e1c821dd446d1ed78f8ae61131550588f60a24George Mount includedLayoutIndexes = null; 54596e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 54696e1c821dd446d1ed78f8ae61131550588f60a24George Mount } else if (tag != null && tag.startsWith(BINDING_TAG_PREFIX)) { 54796e1c821dd446d1ed78f8ae61131550588f60a24George Mount int tagIndex = parseTagInt(tag, BINDING_NUMBER_START); 54896e1c821dd446d1ed78f8ae61131550588f60a24George Mount bindings[tagIndex] = view; 54996e1c821dd446d1ed78f8ae61131550588f60a24George Mount isBound = true; 55096e1c821dd446d1ed78f8ae61131550588f60a24George Mount includedLayoutIndexes = includes == null ? null : includes[tagIndex]; 55195d1b38adeb5963ec5337e7dd6177b4bb5a03619George Mount } else { 55296e1c821dd446d1ed78f8ae61131550588f60a24George Mount // Not a bound view 55396e1c821dd446d1ed78f8ae61131550588f60a24George Mount includedLayoutIndexes = null; 55496e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 55596e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (!isBound) { 55696e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int id = view.getId(); 55796e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (id > 0) { 55896e1c821dd446d1ed78f8ae61131550588f60a24George Mount int index; 55996e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (viewsWithIds != null && (index = viewsWithIds.get(id, -1)) >= 0) { 56096e1c821dd446d1ed78f8ae61131550588f60a24George Mount bindings[index] = view; 56196e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 56296e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 56396e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 56496e1c821dd446d1ed78f8ae61131550588f60a24George Mount 56596e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (view instanceof ViewGroup) { 56696e1c821dd446d1ed78f8ae61131550588f60a24George Mount final ViewGroup viewGroup = (ViewGroup) view; 56796e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int count = viewGroup.getChildCount(); 56896e1c821dd446d1ed78f8ae61131550588f60a24George Mount int minInclude = 0; 56996e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int i = 0; i < count; i++) { 57096e1c821dd446d1ed78f8ae61131550588f60a24George Mount final View child = viewGroup.getChildAt(i); 57196e1c821dd446d1ed78f8ae61131550588f60a24George Mount boolean isInclude = false; 57296e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (includedLayoutIndexes != null) { 57396e1c821dd446d1ed78f8ae61131550588f60a24George Mount String childTag = (String) child.getTag(); 57496e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (childTag != null && childTag.endsWith("_0") && 57596e1c821dd446d1ed78f8ae61131550588f60a24George Mount childTag.startsWith("layout") && childTag.indexOf('/') > 0) { 57696e1c821dd446d1ed78f8ae61131550588f60a24George Mount // This *could* be an include. Test against the expected includes. 57796e1c821dd446d1ed78f8ae61131550588f60a24George Mount int includeIndex = findIncludeIndex(childTag, minInclude, 57896e1c821dd446d1ed78f8ae61131550588f60a24George Mount includedLayoutIndexes); 57996e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (includeIndex >= 0) { 58096e1c821dd446d1ed78f8ae61131550588f60a24George Mount isInclude = true; 58196e1c821dd446d1ed78f8ae61131550588f60a24George Mount minInclude = includeIndex + 1; 58296e1c821dd446d1ed78f8ae61131550588f60a24George Mount IncludedLayoutIndex include = includedLayoutIndexes[includeIndex]; 58396e1c821dd446d1ed78f8ae61131550588f60a24George Mount int lastMatchingIndex = findLastMatching(viewGroup, i); 58496e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (lastMatchingIndex == i) { 5859bdb2415487832e88a05c7bd19391b05440b468eGeorge Mount bindings[include.index] = DataBindingUtil.bind(child, 5869bdb2415487832e88a05c7bd19391b05440b468eGeorge Mount include.layoutId); 58796e1c821dd446d1ed78f8ae61131550588f60a24George Mount } else { 58896e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int includeCount = lastMatchingIndex - i + 1; 58996e1c821dd446d1ed78f8ae61131550588f60a24George Mount final View[] included = new View[includeCount]; 59096e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int j = 0; j < includeCount; j++) { 59196e1c821dd446d1ed78f8ae61131550588f60a24George Mount included[j] = viewGroup.getChildAt(i + j); 59296e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 5939bdb2415487832e88a05c7bd19391b05440b468eGeorge Mount bindings[include.index] = DataBindingUtil.bind(included, 5949bdb2415487832e88a05c7bd19391b05440b468eGeorge Mount include.layoutId); 59596e1c821dd446d1ed78f8ae61131550588f60a24George Mount i += includeCount - 1; 59696e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 59796e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 59896e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 59996e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 60096e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (!isInclude) { 60196e1c821dd446d1ed78f8ae61131550588f60a24George Mount mapBindings(child, bindings, includes, viewsWithIds, false); 60296e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 60396e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 6044c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } 60596e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 60696e1c821dd446d1ed78f8ae61131550588f60a24George Mount 60796e1c821dd446d1ed78f8ae61131550588f60a24George Mount private static int findIncludeIndex(String tag, int minInclude, 60896e1c821dd446d1ed78f8ae61131550588f60a24George Mount IncludedLayoutIndex[] layoutIndexes) { 60996e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int slashIndex = tag.indexOf('/'); 61096e1c821dd446d1ed78f8ae61131550588f60a24George Mount final CharSequence layoutName = tag.subSequence(slashIndex + 1, tag.length() - 2); 61196e1c821dd446d1ed78f8ae61131550588f60a24George Mount 61296e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int length = layoutIndexes.length; 61396e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int i = minInclude; i < length; i++) { 61496e1c821dd446d1ed78f8ae61131550588f60a24George Mount final IncludedLayoutIndex layoutIndex = layoutIndexes[i]; 61596e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (TextUtils.equals(layoutName, layoutIndex.layout)) { 61696e1c821dd446d1ed78f8ae61131550588f60a24George Mount return i; 61796e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 61800da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 61996e1c821dd446d1ed78f8ae61131550588f60a24George Mount return -1; 62000da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 62100da715547ee7d5d38a3b8576090ca427a94daa5George Mount 62296e1c821dd446d1ed78f8ae61131550588f60a24George Mount private static int findLastMatching(ViewGroup viewGroup, int firstIncludedIndex) { 62396e1c821dd446d1ed78f8ae61131550588f60a24George Mount final View firstView = viewGroup.getChildAt(firstIncludedIndex); 62496e1c821dd446d1ed78f8ae61131550588f60a24George Mount final String firstViewTag = (String) firstView.getTag(); 62596e1c821dd446d1ed78f8ae61131550588f60a24George Mount final String tagBase = firstViewTag.substring(0, firstViewTag.length() - 1); // don't include the "0" 62696e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int tagSequenceIndex = tagBase.length(); 62796e1c821dd446d1ed78f8ae61131550588f60a24George Mount 62896e1c821dd446d1ed78f8ae61131550588f60a24George Mount final int count = viewGroup.getChildCount(); 62996e1c821dd446d1ed78f8ae61131550588f60a24George Mount int max = firstIncludedIndex; 63096e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int i = firstIncludedIndex + 1; i < count; i++) { 63196e1c821dd446d1ed78f8ae61131550588f60a24George Mount final View view = viewGroup.getChildAt(i); 63296e1c821dd446d1ed78f8ae61131550588f60a24George Mount final String tag = (String) view.getTag(); 63396e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (tag != null && tag.startsWith(tagBase)) { 63496e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (tag.length() == firstViewTag.length() && tag.charAt(tag.length() - 1) == '0') { 63596e1c821dd446d1ed78f8ae61131550588f60a24George Mount return max; // Found another instance of the include 63696e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 63796e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (isNumeric(tag, tagSequenceIndex)) { 63896e1c821dd446d1ed78f8ae61131550588f60a24George Mount max = i; 63996e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 64096e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 64196e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 64296e1c821dd446d1ed78f8ae61131550588f60a24George Mount return max; 64334a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount } 64434a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount 64596e1c821dd446d1ed78f8ae61131550588f60a24George Mount private static boolean isNumeric(String tag, int startIndex) { 64696e1c821dd446d1ed78f8ae61131550588f60a24George Mount int length = tag.length(); 64796e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (length == startIndex) { 64896e1c821dd446d1ed78f8ae61131550588f60a24George Mount return false; // no numerals 64996e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 65096e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int i = startIndex; i < length; i++) { 65196e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (!Character.isDigit(tag.charAt(i))) { 65296e1c821dd446d1ed78f8ae61131550588f60a24George Mount return false; 65395d1b38adeb5963ec5337e7dd6177b4bb5a03619George Mount } 65495d1b38adeb5963ec5337e7dd6177b4bb5a03619George Mount } 65596e1c821dd446d1ed78f8ae61131550588f60a24George Mount return true; 65695d1b38adeb5963ec5337e7dd6177b4bb5a03619George Mount } 65795d1b38adeb5963ec5337e7dd6177b4bb5a03619George Mount 65834a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount /** 65900da715547ee7d5d38a3b8576090ca427a94daa5George Mount * Parse the tag without creating a new String object. This is fast and assumes the 66000da715547ee7d5d38a3b8576090ca427a94daa5George Mount * tag is in the correct format. 66100da715547ee7d5d38a3b8576090ca427a94daa5George Mount * @param str The tag string. 66200da715547ee7d5d38a3b8576090ca427a94daa5George Mount * @return The binding tag number parsed from the tag string. 66300da715547ee7d5d38a3b8576090ca427a94daa5George Mount */ 66496e1c821dd446d1ed78f8ae61131550588f60a24George Mount private static int parseTagInt(String str, int startIndex) { 66500da715547ee7d5d38a3b8576090ca427a94daa5George Mount final int end = str.length(); 66600da715547ee7d5d38a3b8576090ca427a94daa5George Mount int val = 0; 66796e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int i = startIndex; i < end; i++) { 66800da715547ee7d5d38a3b8576090ca427a94daa5George Mount val *= 10; 66900da715547ee7d5d38a3b8576090ca427a94daa5George Mount char c = str.charAt(i); 67000da715547ee7d5d38a3b8576090ca427a94daa5George Mount val += (c - '0'); 67100da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 67200da715547ee7d5d38a3b8576090ca427a94daa5George Mount return val; 67300da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 67400da715547ee7d5d38a3b8576090ca427a94daa5George Mount 675722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount private interface ObservableReference<T> { 676722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount WeakListener<T> getListener(); 677722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount void addListener(T target); 678722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount void removeListener(T target); 679722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount } 680722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount 681722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount private static class WeakListener<T> extends WeakReference<ViewDataBinding> { 682722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount private final ObservableReference<T> mObservable; 6835cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected final int mLocalFieldId; 6845cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount private T mTarget; 685085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 686722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public WeakListener(ViewDataBinding binder, int localFieldId, 687722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount ObservableReference<T> observable) { 688722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount super(binder); 6895cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount mLocalFieldId = localFieldId; 690722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount mObservable = observable; 691085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 692085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 6935cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount public void setTarget(T object) { 6945cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount unregister(); 6955cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount mTarget = object; 6965cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (mTarget != null) { 697722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount mObservable.addListener(mTarget); 698085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 699085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 700085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 701085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar public boolean unregister() { 7025cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount boolean unregistered = false; 7035cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (mTarget != null) { 704722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount mObservable.removeListener(mTarget); 7055cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount unregistered = true; 706085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 707085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar mTarget = null; 7085cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return unregistered; 709085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 710085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 7115cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount public T getTarget() { 7125cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return mTarget; 713085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 7145cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7154c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount protected ViewDataBinding getBinder() { 716722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount ViewDataBinding binder = get(); 7175cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (binder == null) { 7185cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount unregister(); // The binder is dead 7195cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7205cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return binder; 7215cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 722085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 723085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 724722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback 725722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount implements ObservableReference<Observable> { 726722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount final WeakListener<Observable> mListener; 727722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount 7284c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakPropertyListener(ViewDataBinding binder, int localFieldId) { 729722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount mListener = new WeakListener<Observable>(binder, localFieldId, this); 7305cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7315cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7325cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 733722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public WeakListener<Observable> getListener() { 734722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount return mListener; 7355cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7365cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7375cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 738722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void addListener(Observable target) { 739722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount target.addOnPropertyChangedCallback(this); 740085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 741085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 742085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar @Override 743722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void removeListener(Observable target) { 744722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount target.removeOnPropertyChangedCallback(this); 745722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount } 746722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount 747722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount @Override 748722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void onPropertyChanged(Observable sender, int propertyId) { 749722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount ViewDataBinding binder = mListener.getBinder(); 7505cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (binder == null) { 7515cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return; 7525cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 753722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount Observable obj = mListener.getTarget(); 7545cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (obj != sender) { 7555cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return; // notification from the wrong object? 756085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 757722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount binder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId); 758085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 759085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 7605cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 761722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount private static class WeakListListener extends ObservableList.OnListChangedCallback 762722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount implements ObservableReference<ObservableList> { 763722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount final WeakListener<ObservableList> mListener; 7645cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7654c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakListListener(ViewDataBinding binder, int localFieldId) { 766722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount mListener = new WeakListener<ObservableList>(binder, localFieldId, this); 7675cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7685cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7695cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 770722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public WeakListener<ObservableList> getListener() { 771722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount return mListener; 7725cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7735cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7745cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 775722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void addListener(ObservableList target) { 776722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount target.addOnListChangedCallback(this); 7775cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7785cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7795cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 780722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void removeListener(ObservableList target) { 781722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount target.removeOnListChangedCallback(this); 7825cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7835cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7845cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 785722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void onChanged(ObservableList sender) { 786722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount ViewDataBinding binder = mListener.getBinder(); 787722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount if (binder == null) { 788722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount return; 789722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount } 790722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount ObservableList target = mListener.getTarget(); 791722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount if (target != sender) { 792722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount return; // We expect notifications only from sender 793722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount } 794722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount binder.handleFieldChange(mListener.mLocalFieldId, target, 0); 7955cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7965cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7975cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 798722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void onItemRangeChanged(ObservableList sender, int positionStart, int itemCount) { 799722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount onChanged(sender); 8005cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 8015cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 8025cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 803722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void onItemRangeInserted(ObservableList sender, int positionStart, int itemCount) { 804722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount onChanged(sender); 8055cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 8065cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 8075cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 808722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void onItemRangeMoved(ObservableList sender, int fromPosition, int toPosition, 809722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount int itemCount) { 810722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount onChanged(sender); 811722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount } 812722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount 813722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount @Override 814722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void onItemRangeRemoved(ObservableList sender, int positionStart, int itemCount) { 815722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount onChanged(sender); 8165cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 8175cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 8185cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 819722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount private static class WeakMapListener extends ObservableMap.OnMapChangedCallback 820722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount implements ObservableReference<ObservableMap> { 821722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount final WeakListener<ObservableMap> mListener; 822722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount 8234c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakMapListener(ViewDataBinding binder, int localFieldId) { 824722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount mListener = new WeakListener<ObservableMap>(binder, localFieldId, this); 825722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount } 826722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount 827722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount @Override 828722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public WeakListener<ObservableMap> getListener() { 829722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount return mListener; 8305cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 8315cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 8325cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 833722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void addListener(ObservableMap target) { 834722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount target.addOnMapChangedCallback(this); 8355cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 8365cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 8375cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 838722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void removeListener(ObservableMap target) { 839722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount target.removeOnMapChangedCallback(this); 8405cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 8415cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 8425cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 8432c86cdbaf189e2b1774af7f64a2974de9321673fGeorge Mount public void onMapChanged(ObservableMap sender, Object key) { 844722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount ViewDataBinding binder = mListener.getBinder(); 845722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount if (binder == null || sender != mListener.getTarget()) { 8465cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return; 8475cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 848722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount binder.handleFieldChange(mListener.mLocalFieldId, sender, 0); 8495cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 8505cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 8515cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 8525cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount private interface CreateWeakListener { 8534c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount WeakListener create(ViewDataBinding viewDataBinding, int localFieldId); 8545cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 85596e1c821dd446d1ed78f8ae61131550588f60a24George Mount 85696e1c821dd446d1ed78f8ae61131550588f60a24George Mount protected static class IncludedLayoutIndex { 85796e1c821dd446d1ed78f8ae61131550588f60a24George Mount public final String layout; 85896e1c821dd446d1ed78f8ae61131550588f60a24George Mount public final int index; 85996e1c821dd446d1ed78f8ae61131550588f60a24George Mount public final int layoutId; 86096e1c821dd446d1ed78f8ae61131550588f60a24George Mount 86196e1c821dd446d1ed78f8ae61131550588f60a24George Mount public IncludedLayoutIndex(String layout, int index, int layoutId) { 86296e1c821dd446d1ed78f8ae61131550588f60a24George Mount this.layout = layout; 86396e1c821dd446d1ed78f8ae61131550588f60a24George Mount this.index = index; 86496e1c821dd446d1ed78f8ae61131550588f60a24George Mount this.layoutId = layoutId; 86596e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 86696e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 867085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar} 868