ViewDataBinding.java revision d6527ee28cc3aa05818799af8def9593346f91bc
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) { 68722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount return new WeakPropertyListener(viewDataBinding, localFieldId).getListener(); 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) { 78722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount return new WeakListListener(viewDataBinding, localFieldId).getListener(); 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) { 88722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount return new WeakMapListener(viewDataBinding, localFieldId).getListener(); 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. 1244d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount final ViewDataBinding binding = getBinding(v); 1253f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar binding.mRebindRunnable.run(); 1265914aa7da50a90a4c705b5be02a215499d0ad232George Mount v.removeOnAttachStateChangeListener(this); 1275914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1285914aa7da50a90a4c705b5be02a215499d0ad232George Mount 1295914aa7da50a90a4c705b5be02a215499d0ad232George Mount @Override 1305914aa7da50a90a4c705b5be02a215499d0ad232George Mount public void onViewDetachedFromWindow(View v) { 1315914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1325914aa7da50a90a4c705b5be02a215499d0ad232George Mount }; 1335914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1345914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1355914aa7da50a90a4c705b5be02a215499d0ad232George Mount 1364c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 1374c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Runnable executed on animation heartbeat to rebind the dirty Views. 1384c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 1393f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar private final Runnable mRebindRunnable = new Runnable() { 140085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar @Override 141085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar public void run() { 142e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount synchronized (this) { 143e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mPendingRebind = false; 144e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 145e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) { 146e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount // Nested so that we don't get a lint warning in IntelliJ 147e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (!mRoot.isAttachedToWindow()) { 148e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount // Don't execute the pending bindings until the View 149e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount // is attached again. 150e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRoot.removeOnAttachStateChangeListener(ROOT_REATTACHED_LISTENER); 151e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRoot.addOnAttachStateChangeListener(ROOT_REATTACHED_LISTENER); 152e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount return; 1535914aa7da50a90a4c705b5be02a215499d0ad232George Mount } 1544c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } 155e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount executePendingBindings(); 156085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 157085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar }; 158085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 1594c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 1604c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Flag indicates that there are pending bindings that need to be reevaluated. 1614c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 1624c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private boolean mPendingRebind = false; 1634c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 1644c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 165e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * Indicates that a onPreBind has stopped the executePendingBindings call. 166e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount */ 167e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount private boolean mRebindHalted = false; 168e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 169e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount /** 1704c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * The observed expressions. 1714c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 1724c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private WeakListener[] mLocalFieldObservers; 1734c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 1744c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 1754c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * The root View that this Binding is associated with. 1764c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 1774c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount private final View mRoot; 1784c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 179e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount /** 180e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * The collection of OnRebindCallbacks. 181e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount */ 182e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount private CallbackRegistry<OnRebindCallback, ViewDataBinding, Void> mRebindCallbacks; 183e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 184e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount /** 185e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * Flag to prevent reentrant executePendingBinding calls. 186e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount */ 187e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount private boolean mIsExecutingPendingBindings; 188e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 1893f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar // null api < 16 1903f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar private Choreographer mChoreographer; 1913f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar 1923f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar private final Choreographer.FrameCallback mFrameCallback; 1933f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar 1943f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar // null api >= 16 1953f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar private Handler mUIThreadHandler; 1963f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar 1974c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount protected ViewDataBinding(View root, int localFieldCount) { 1985cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount mLocalFieldObservers = new WeakListener[localFieldCount]; 1994c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount this.mRoot = root; 2003f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar if (Looper.myLooper() == null) { 2013f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar throw new IllegalStateException("DataBinding must be created in view's UI Thread"); 2023f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar } 2033f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar if (USE_CHOREOGRAPHER) { 2043f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar mChoreographer = Choreographer.getInstance(); 2053f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar mFrameCallback = new Choreographer.FrameCallback() { 2063f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar @Override 2073f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar public void doFrame(long frameTimeNanos) { 2083f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar mRebindRunnable.run(); 2093f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar } 2103f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar }; 2113f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar } else { 2123f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar mFrameCallback = null; 2133f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar mUIThreadHandler = new Handler(Looper.myLooper()); 2143f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar } 21596e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 21696e1c821dd446d1ed78f8ae61131550588f60a24George Mount 21796e1c821dd446d1ed78f8ae61131550588f60a24George Mount protected void setRootTag(View view) { 21896e1c821dd446d1ed78f8ae61131550588f60a24George Mount if (USE_TAG_ID) { 21996e1c821dd446d1ed78f8ae61131550588f60a24George Mount view.setTag(R.id.dataBinding, this); 22096e1c821dd446d1ed78f8ae61131550588f60a24George Mount } else { 22196e1c821dd446d1ed78f8ae61131550588f60a24George Mount view.setTag(this); 22296e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 22396e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 22496e1c821dd446d1ed78f8ae61131550588f60a24George Mount 22596e1c821dd446d1ed78f8ae61131550588f60a24George Mount protected void setRootTag(View[] views) { 226e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount if (USE_TAG_ID) { 22796e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (View view : views) { 22896e1c821dd446d1ed78f8ae61131550588f60a24George Mount view.setTag(R.id.dataBinding, this); 22996e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 230e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount } else { 23196e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (View view : views) { 23296e1c821dd446d1ed78f8ae61131550588f60a24George Mount view.setTag(this); 23396e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 234e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount } 2355cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 2365cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 2374c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public static int getBuildSdkInt() { 2384c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount return SDK_INT; 2394c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } 2404c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 2414c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 2424c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Called when an observed object changes. Sets the appropriate dirty flag if applicable. 2434c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * @param localFieldId The index into mLocalFieldObservers that this Object resides in. 2444c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * @param object The object that has changed. 245fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount * @param fieldId The BR ID of the field being changed or _all if 2464c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * no specific field is being notified. 2474c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * @return true if this change should cause a change to the UI. 2484c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 2494c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount protected abstract boolean onFieldChange(int localFieldId, Object object, int fieldId); 2504c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 251e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount /** 252e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * Set a value value in the Binding class. 253e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * <p> 254e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * Typically, the developer will be able to call the subclass's set method directly. For 255e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * example, if there is a variable <code>x</code> in the Binding, a <code>setX</code> method 256e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * will be generated. However, there are times when the specific subclass of ViewDataBinding 257e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * is unknown, so the generated method cannot be discovered without reflection. The 258e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * setVariable call allows the values of variables to be set without reflection. 259e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * 260e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * @param variableId the BR id of the variable to be set. For example, if the variable is 261e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * <code>x</code>, then variableId will be <code>BR.x</code>. 262e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * @param value The new value of the variable to be set. 263e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * @return <code>true</code> if the variable exists in the binding or <code>false</code> 264e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * otherwise. 265e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount */ 266e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount public abstract boolean setVariable(int variableId, Object value); 267e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 268e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount /** 269e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * Add a listener to be called when reevaluating dirty fields. This also allows automatic 270e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * updates to be halted, but does not stop explicit calls to {@link #executePendingBindings()}. 271e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * 272e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * @param listener The listener to add. 273e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount */ 274e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount public void addOnRebindCallback(OnRebindCallback listener) { 275e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (mRebindCallbacks == null) { 276e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRebindCallbacks = new CallbackRegistry<OnRebindCallback, ViewDataBinding, Void>(REBIND_NOTIFIER); 277e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 278e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRebindCallbacks.add(listener); 279e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 280e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 281e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount /** 282e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * Removes a listener that was added in {@link #addOnRebindCallback(OnRebindCallback)}. 283e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * 284e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount * @param listener The listener to remove. 285e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount */ 286e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount public void removeOnRebindCallback(OnRebindCallback listener) { 287e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (mRebindCallbacks != null) { 288e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRebindCallbacks.remove(listener); 289e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 290e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 2914c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 2924c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 2934c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Evaluates the pending bindings, updating any Views that have expressions bound to 2944c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * modified variables. This <b>must</b> be run on the UI thread. 2954c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 296e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount public void executePendingBindings() { 297e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (mIsExecutingPendingBindings) { 298e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount requestRebind(); 299e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount return; 300e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 301447971abca811b11b8c1d8e7bfaa294856d03c16George Mount if (!hasPendingBindings()) { 302447971abca811b11b8c1d8e7bfaa294856d03c16George Mount return; 303447971abca811b11b8c1d8e7bfaa294856d03c16George Mount } 304e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mIsExecutingPendingBindings = true; 305e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRebindHalted = false; 306e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (mRebindCallbacks != null) { 307e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRebindCallbacks.notifyCallbacks(this, REBIND, null); 308e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 309e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount // The onRebindListeners will change mPendingHalted 310e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (mRebindHalted) { 311e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRebindCallbacks.notifyCallbacks(this, HALTED, null); 312e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 313e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 314e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (!mRebindHalted) { 315e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount executeBindings(); 316e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (mRebindCallbacks != null) { 317e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mRebindCallbacks.notifyCallbacks(this, REBOUND, null); 318e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 319e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 320e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mIsExecutingPendingBindings = false; 321e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 322e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 323e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount void forceExecuteBindings() { 324e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount executeBindings(); 325e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 326e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount 327e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount protected abstract void executeBindings(); 3284c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 3294c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 3302f64c44e4fa296cf658ca986c095eab62f82a31dYigit Boyar * Invalidates all binding expressions and requests a new rebind to refresh UI. 3314c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 3324c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public abstract void invalidateAll(); 3334c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 3344c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 3352f64c44e4fa296cf658ca986c095eab62f82a31dYigit Boyar * Returns whether the UI needs to be refresh to represent the current data. 3362f64c44e4fa296cf658ca986c095eab62f82a31dYigit Boyar * 337447971abca811b11b8c1d8e7bfaa294856d03c16George Mount * @return true if any field has changed and the binding should be evaluated. 338447971abca811b11b8c1d8e7bfaa294856d03c16George Mount */ 339447971abca811b11b8c1d8e7bfaa294856d03c16George Mount public abstract boolean hasPendingBindings(); 340447971abca811b11b8c1d8e7bfaa294856d03c16George Mount 341447971abca811b11b8c1d8e7bfaa294856d03c16George Mount /** 3424c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Removes binding listeners to expression variables. 3434c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 3444c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public void unbind() { 3455cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount for (WeakListener weakListener : mLocalFieldObservers) { 3465cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (weakListener != null) { 3475cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount weakListener.unregister(); 3485cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 3495cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 350085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 351085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 3524c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount @Override 3534c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount protected void finalize() throws Throwable { 3544c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount unbind(); 3554c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } 3564c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount 357ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount static ViewDataBinding getBinding(View v) { 3584d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount if (v != null) { 3594d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount if (USE_TAG_ID) { 3604d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount return (ViewDataBinding) v.getTag(R.id.dataBinding); 3614d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount } else { 3624d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount final Object tag = v.getTag(); 3634d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount if (tag instanceof ViewDataBinding) { 3644d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount return (ViewDataBinding) tag; 3654d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount } 366ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount } 367ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount } 368ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount return null; 369ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount } 370ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount 3714c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 3724c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * Returns the outermost View in the layout file associated with the Binding. 3734c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * @return the outermost View in the layout file associated with the Binding. 3744c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 375085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar public View getRoot() { 376085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return mRoot; 377085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 378085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 379085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) { 380085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar boolean result = onFieldChange(mLocalFieldId, object, fieldId); 381085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (result) { 382085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar requestRebind(); 383085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 384085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 385085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 386085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar protected boolean unregisterFrom(int localFieldId) { 3875cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount WeakListener listener = mLocalFieldObservers[localFieldId]; 388085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (listener != null) { 389085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return listener.unregister(); 390085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 391085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return false; 392085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 393085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 394085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar protected void requestRebind() { 395e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount synchronized (this) { 396e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount if (mPendingRebind) { 397e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount return; 398e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount } 399e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount mPendingRebind = true; 400085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 4013f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar if (USE_CHOREOGRAPHER) { 4023f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar mChoreographer.postFrameCallback(mFrameCallback); 4034c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } else { 4043f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar mUIThreadHandler.post(mRebindRunnable); 4054c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount } 4063f73e3149732132c02f5d19aab7b5da429794058Yigit Boyar 407085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 408085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 409085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar protected Object getObservedField(int localFieldId) { 4105cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount WeakListener listener = mLocalFieldObservers[localFieldId]; 411085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (listener == null) { 412085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return null; 413085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 414085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return listener.getTarget(); 415085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 416085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 4175cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount private boolean updateRegistration(int localFieldId, Object observable, 4185cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount CreateWeakListener listenerCreator) { 419085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (observable == null) { 420085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return unregisterFrom(localFieldId); 421085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 4225cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount WeakListener listener = mLocalFieldObservers[localFieldId]; 423085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (listener == null) { 4245cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount registerTo(localFieldId, observable, listenerCreator); 425085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return true; 426085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 427085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (listener.getTarget() == observable) { 428085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return false;//nothing to do, same object 429085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 430085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar unregisterFrom(localFieldId); 4315cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount registerTo(localFieldId, observable, listenerCreator); 432085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return true; 433085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 434085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 4355cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected boolean updateRegistration(int localFieldId, Observable observable) { 4365cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER); 4375cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 4385cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 4395cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected boolean updateRegistration(int localFieldId, ObservableList observable) { 4405cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return updateRegistration(localFieldId, observable, CREATE_LIST_LISTENER); 4415cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 4425cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 4435cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected boolean updateRegistration(int localFieldId, ObservableMap observable) { 4445cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return updateRegistration(localFieldId, observable, CREATE_MAP_LISTENER); 4455cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 4465cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 4475cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected void registerTo(int localFieldId, Object observable, 4485cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount CreateWeakListener listenerCreator) { 449085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (observable == null) { 450085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return; 451085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 4525cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount WeakListener listener = mLocalFieldObservers[localFieldId]; 453085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (listener == null) { 4545cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount listener = listenerCreator.create(this, localFieldId); 455085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar mLocalFieldObservers[localFieldId] = listener; 456085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 457085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar listener.setTarget(observable); 458085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 459085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 460ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount protected static ViewDataBinding bind(View view, int layoutId) { 461ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount return DataBindingUtil.bind(view, layoutId); 462ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount } 463ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount 4644c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount /** 46596e1c821dd446d1ed78f8ae61131550588f60a24George Mount * Walks the view hierarchy under root and pulls out tagged Views, includes, and views with 46696e1c821dd446d1ed78f8ae61131550588f60a24George Mount * IDs into an Object[] that is returned. This is used to walk the view hierarchy once to find 46796e1c821dd446d1ed78f8ae61131550588f60a24George Mount * all bound and ID'd views. 46896e1c821dd446d1ed78f8ae61131550588f60a24George Mount * 46996e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param root The root of the view hierarchy to walk. 47096e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param numBindings The total number of ID'd views, views with expressions, and includes 47196e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param includes The include layout information, indexed by their container's index. 47296e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param viewsWithIds Indexes of views that don't have tags, but have IDs. 47396e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @return An array of size numBindings containing all Views in the hierarchy that have IDs 47496e1c821dd446d1ed78f8ae61131550588f60a24George Mount * (with elements in viewsWithIds), are tagged containing expressions, or the bindings for 47596e1c821dd446d1ed78f8ae61131550588f60a24George Mount * included layouts. 47696e1c821dd446d1ed78f8ae61131550588f60a24George Mount */ 47796e1c821dd446d1ed78f8ae61131550588f60a24George Mount protected static Object[] mapBindings(View root, int numBindings, 47896e1c821dd446d1ed78f8ae61131550588f60a24George Mount IncludedLayoutIndex[][] includes, SparseIntArray viewsWithIds) { 47996e1c821dd446d1ed78f8ae61131550588f60a24George Mount Object[] bindings = new Object[numBindings]; 48096e1c821dd446d1ed78f8ae61131550588f60a24George Mount mapBindings(root, bindings, includes, viewsWithIds, true); 48196e1c821dd446d1ed78f8ae61131550588f60a24George Mount return bindings; 48296e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 48396e1c821dd446d1ed78f8ae61131550588f60a24George Mount 48496e1c821dd446d1ed78f8ae61131550588f60a24George Mount /** 48596e1c821dd446d1ed78f8ae61131550588f60a24George Mount * Walks the view hierarchy under roots and pulls out tagged Views, includes, and views with 48696e1c821dd446d1ed78f8ae61131550588f60a24George Mount * IDs into an Object[] that is returned. This is used to walk the view hierarchy once to find 48796e1c821dd446d1ed78f8ae61131550588f60a24George Mount * all bound and ID'd views. 4884c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount * 48996e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param roots The root Views of the view hierarchy to walk. This is used with merge tags. 49096e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param numBindings The total number of ID'd views, views with expressions, and includes 49196e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param includes The include layout information, indexed by their container's index. 49296e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @param viewsWithIds Indexes of views that don't have tags, but have IDs. 49396e1c821dd446d1ed78f8ae61131550588f60a24George Mount * @return An array of size numBindings containing all Views in the hierarchy that have IDs 49496e1c821dd446d1ed78f8ae61131550588f60a24George Mount * (with elements in viewsWithIds), are tagged containing expressions, or the bindings for 49596e1c821dd446d1ed78f8ae61131550588f60a24George Mount * included layouts. 4964c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount */ 49796e1c821dd446d1ed78f8ae61131550588f60a24George Mount protected static Object[] mapBindings(View[] roots, int numBindings, 49896e1c821dd446d1ed78f8ae61131550588f60a24George Mount IncludedLayoutIndex[][] includes, SparseIntArray viewsWithIds) { 49996e1c821dd446d1ed78f8ae61131550588f60a24George Mount Object[] bindings = new Object[numBindings]; 50096e1c821dd446d1ed78f8ae61131550588f60a24George Mount for (int i = 0; i < roots.length; i++) { 50196e1c821dd446d1ed78f8ae61131550588f60a24George Mount mapBindings(roots[i], bindings, includes, viewsWithIds, true); 50200da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 50396e1c821dd446d1ed78f8ae61131550588f60a24George Mount return bindings; 50400da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 50500da715547ee7d5d38a3b8576090ca427a94daa5George Mount 50696e1c821dd446d1ed78f8ae61131550588f60a24George Mount private static void mapBindings(View view, Object[] bindings, 50796e1c821dd446d1ed78f8ae61131550588f60a24George Mount IncludedLayoutIndex[][] includes, SparseIntArray viewsWithIds, boolean isRoot) { 50896e1c821dd446d1ed78f8ae61131550588f60a24George Mount final IncludedLayoutIndex[] includedLayoutIndexes; 509d6527ee28cc3aa05818799af8def9593346f91bcGeorge Mount final ViewDataBinding existingBinding = getBinding(view); 510d6527ee28cc3aa05818799af8def9593346f91bcGeorge Mount if (existingBinding != null) { 5114d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount return; 5124d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount } 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 654722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount private interface ObservableReference<T> { 655722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount WeakListener<T> getListener(); 656722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount void addListener(T target); 657722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount void removeListener(T target); 658722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount } 659722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount 660722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount private static class WeakListener<T> extends WeakReference<ViewDataBinding> { 661722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount private final ObservableReference<T> mObservable; 6625cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount protected final int mLocalFieldId; 6635cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount private T mTarget; 664085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 665722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public WeakListener(ViewDataBinding binder, int localFieldId, 666722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount ObservableReference<T> observable) { 667722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount super(binder); 6685cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount mLocalFieldId = localFieldId; 669722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount mObservable = observable; 670085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 671085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 6725cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount public void setTarget(T object) { 6735cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount unregister(); 6745cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount mTarget = object; 6755cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (mTarget != null) { 676722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount mObservable.addListener(mTarget); 677085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 678085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 679085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 680085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar public boolean unregister() { 6815cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount boolean unregistered = false; 6825cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (mTarget != null) { 683722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount mObservable.removeListener(mTarget); 6845cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount unregistered = true; 685085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 686085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar mTarget = null; 6875cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return unregistered; 688085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 689085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 6905cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount public T getTarget() { 6915cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return mTarget; 692085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 6935cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 6944c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount protected ViewDataBinding getBinder() { 695722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount ViewDataBinding binder = get(); 6965cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (binder == null) { 6975cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount unregister(); // The binder is dead 6985cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 6995cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return binder; 7005cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 701085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 702085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 703722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback 704722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount implements ObservableReference<Observable> { 705722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount final WeakListener<Observable> mListener; 706722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount 7074c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakPropertyListener(ViewDataBinding binder, int localFieldId) { 708722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount mListener = new WeakListener<Observable>(binder, localFieldId, this); 7095cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7105cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7115cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 712722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public WeakListener<Observable> getListener() { 713722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount return mListener; 7145cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7155cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7165cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 717722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void addListener(Observable target) { 718722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount target.addOnPropertyChangedCallback(this); 719085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 720085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 721085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar @Override 722722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void removeListener(Observable target) { 723722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount target.removeOnPropertyChangedCallback(this); 724722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount } 725722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount 726722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount @Override 727722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void onPropertyChanged(Observable sender, int propertyId) { 728722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount ViewDataBinding binder = mListener.getBinder(); 7295cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (binder == null) { 7305cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return; 7315cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 732722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount Observable obj = mListener.getTarget(); 7335cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount if (obj != sender) { 7345cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return; // notification from the wrong object? 735085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 736722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount binder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId); 737085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 738085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 7395cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 740722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount private static class WeakListListener extends ObservableList.OnListChangedCallback 741722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount implements ObservableReference<ObservableList> { 742722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount final WeakListener<ObservableList> mListener; 7435cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7444c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakListListener(ViewDataBinding binder, int localFieldId) { 745722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount mListener = new WeakListener<ObservableList>(binder, localFieldId, this); 7465cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7475cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7485cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 749722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public WeakListener<ObservableList> getListener() { 750722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount return mListener; 7515cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7525cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7535cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 754722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void addListener(ObservableList target) { 755722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount target.addOnListChangedCallback(this); 7565cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7575cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7585cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 759722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void removeListener(ObservableList target) { 760722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount target.removeOnListChangedCallback(this); 7615cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7625cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7635cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 764722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void onChanged(ObservableList sender) { 765722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount ViewDataBinding binder = mListener.getBinder(); 766722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount if (binder == null) { 767722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount return; 768722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount } 769722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount ObservableList target = mListener.getTarget(); 770722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount if (target != sender) { 771722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount return; // We expect notifications only from sender 772722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount } 773722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount binder.handleFieldChange(mListener.mLocalFieldId, target, 0); 7745cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7755cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7765cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 777722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void onItemRangeChanged(ObservableList sender, int positionStart, int itemCount) { 778722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount onChanged(sender); 7795cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7805cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7815cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 782722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void onItemRangeInserted(ObservableList sender, int positionStart, int itemCount) { 783722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount onChanged(sender); 7845cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7855cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 7865cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 787722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void onItemRangeMoved(ObservableList sender, int fromPosition, int toPosition, 788722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount int itemCount) { 789722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount onChanged(sender); 790722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount } 791722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount 792722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount @Override 793722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void onItemRangeRemoved(ObservableList sender, int positionStart, int itemCount) { 794722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount onChanged(sender); 7955cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7965cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 7975cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 798722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount private static class WeakMapListener extends ObservableMap.OnMapChangedCallback 799722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount implements ObservableReference<ObservableMap> { 800722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount final WeakListener<ObservableMap> mListener; 801722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount 8024c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount public WeakMapListener(ViewDataBinding binder, int localFieldId) { 803722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount mListener = new WeakListener<ObservableMap>(binder, localFieldId, this); 804722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount } 805722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount 806722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount @Override 807722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public WeakListener<ObservableMap> getListener() { 808722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount return mListener; 8095cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 8105cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 8115cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 812722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void addListener(ObservableMap target) { 813722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount target.addOnMapChangedCallback(this); 8145cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 8155cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 8165cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 817722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount public void removeListener(ObservableMap target) { 818722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount target.removeOnMapChangedCallback(this); 8195cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 8205cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 8215cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount @Override 8222c86cdbaf189e2b1774af7f64a2974de9321673fGeorge Mount public void onMapChanged(ObservableMap sender, Object key) { 823722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount ViewDataBinding binder = mListener.getBinder(); 824722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount if (binder == null || sender != mListener.getTarget()) { 8255cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount return; 8265cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 827722fe711207a37783dfa7142284b0ebe5bd503fbGeorge Mount binder.handleFieldChange(mListener.mLocalFieldId, sender, 0); 8285cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 8295cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 8305cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount 8315cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount private interface CreateWeakListener { 8324c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount WeakListener create(ViewDataBinding viewDataBinding, int localFieldId); 8335cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount } 83496e1c821dd446d1ed78f8ae61131550588f60a24George Mount 83596e1c821dd446d1ed78f8ae61131550588f60a24George Mount protected static class IncludedLayoutIndex { 83696e1c821dd446d1ed78f8ae61131550588f60a24George Mount public final String layout; 83796e1c821dd446d1ed78f8ae61131550588f60a24George Mount public final int index; 83896e1c821dd446d1ed78f8ae61131550588f60a24George Mount public final int layoutId; 83996e1c821dd446d1ed78f8ae61131550588f60a24George Mount 84096e1c821dd446d1ed78f8ae61131550588f60a24George Mount public IncludedLayoutIndex(String layout, int index, int layoutId) { 84196e1c821dd446d1ed78f8ae61131550588f60a24George Mount this.layout = layout; 84296e1c821dd446d1ed78f8ae61131550588f60a24George Mount this.index = index; 84396e1c821dd446d1ed78f8ae61131550588f60a24George Mount this.layoutId = layoutId; 84496e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 84596e1c821dd446d1ed78f8ae61131550588f60a24George Mount } 846085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar} 847