The cooperation between Databinding and LiveData is in-depth

Posted by ktstowell on Tue, 14 Dec 2021 22:15:03 +0100

 Handler handler;

public MainViewModel() {
    input.setValue("test");
    include_string.setValue("include_string");
    handler = new Handler();
}

public void onClick() {
    Random random = new Random();
    input.setValue(random.nextInt(100) + "");
    include_string.setValue(random.nextInt(100) + "");
}

public void onAsyncClick() {
    final Random random = new Random();

    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            input.setValue(random.nextInt(100) + "async");
            include_string.setValue(random.nextInt(100) + "async");
        }
    }, 5000);
}

}

Here are two string,Corresponding to two EditText,One is in the normal interface and the other is include Come in. Two click events, one is normal and the other is asynchronous.

to glance at MainActivity:

public class MainActivity extends AppCompatActivity {
ActivityMainBinding mBinding;
MainViewModel mainViewModel;
String TAG = "TAG";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
    mainViewModel = ViewModelProviders.of(this, new ViewModelProvider.NewInstanceFactory()).get(MainViewModel.class);
    mBinding.setViewModel(mainViewModel);
    mBinding.setLifecycleOwner(this);
    mBinding.input.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            Log.d(TAG, "beforeTextChanged: ");
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            Log.d(TAG, "onTextChanged: ");
        }

        @Override
        public void afterTextChanged(Editable s) {
            if (s != null) {
                Log.d("TAG", "afterTextChanged: " + s.toString());
            } else {
                Log.d("TAG", "afterTextChanged: " + "null");
            }
            Log.d(TAG, "afterTextChanged: " + mainViewModel.input.getValue());
        }
    });
    mBinding.includeView.setLifecycleOwner(this);
    mBinding.includeView.setViewModel(mainViewModel);
}

}

First bind the layout, and then create one`MainViewModel`,Then there will be`ViewModel`Bind to View Up, and then there's the new one API It is also the most important method to give the current`Databinding`Add the owner of the lifecycle, and then I give the owner of the current interface EditText Added a listener. about include Talk later. After running, you will find that the project is running normally and MainViewModel Data changes in, UI Will change.

I'm not very familiar with it before`LiveData`and`Databinding`My friends say, usually,`Databinding`Can notify Ui Data must be inherited from`BaseObsevable`of But not in the above example, so if the notification is made?

Interpretation of original post code
-------

First from`setLifecycleOwner()`Start:

@MainThread
public void setLifecycleOwner(@Nullable LifecycleOwner lifecycleOwner) {
//First judge that the current mlife cycleowner is the same, and then return the same
if (mLifecycleOwner == lifecycleOwner) {
return;
}
//Currently, if there are, but they are inconsistent, remove the previous LifecycleObserver first
if (mLifecycleOwner != null) {
mLifecycleOwner.getLifecycle().removeObserver(mOnStartListener);
}
//Assign new value
mLifecycleOwner = lifecycleOwner;
if (lifecycleOwner != null) {
//Add LifecycleObserver again. If there is a previous one, add the previous one. If not, create a new one.
if (mOnStartListener == null) {
mOnStartListener = new OnStartListener();
}
lifecycleOwner.getLifecycle().addObserver(mOnStartListener);
}
//Set the current lifecycle owner for all registered UI changes that need to respond to listening objects.
for (WeakListener<?> weakListener : mLocalFieldObservers) {
if (weakListener != null) {
weakListener.setLifecycleOwner(lifecycleOwner);
}
}
}

Personal right`Databinding`Not particularly familiar, but the main purpose of this method is to give the current`lifecycleOwner`,Add a lifecycle observer, and then register all that need to respond to it`lifecycleOwner`Come on. to glance at`OnStartListener` This monitor.

public class OnStartListener implements LifecycleObserver {
private OnStartListener() {
}

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void onStart() {
        executePendingBindings();
    }
} 
You can see only one`ON_START`Life cycle events, when the above`lifecycleOwner`yes`ON_START`Will be called when`executePendingBindings()`method;

Here, the original code level is gone. A new method is added to set the current life cycle holder, and then add a receive only method to this holder`ON_START`The life cycle observer of the event, which refreshes the data of the current page when the life cycle is available.

Interpretation of compiled code
-------

Used in the above example`LiveData`Notify View There are two situations:

1.  In the current View When available, update the data and modify it directly UI. 
2.  In the current View If it is not available, update the data and wait View Is available and then modified UI. 

Judgment in the second case Ui Whether it is available, and then invoking the refresh data is the above.`OnStartListener`. 

For the first case, think about how to do it LiveData When the data is modified, it can be notified DataBinding Refresh corresponding UI What about the?

Let's look at one first DataBinding Core functions:

@Override
protected void executeBindings() {
long dirtyFlags = 0;
synchronized(this) {
dirtyFlags = mDirtyFlags;
mDirtyFlags = 0;
}
java.lang.String viewModelInputGetValue = null;
android.arch.lifecycle.MutableLiveData<java.lang.String> viewModelInput = null;
com.example.huangbaole.databindinglivedata.MainViewModel viewModel = mViewModel;

    if ((dirtyFlags & 0xdL) != 0) {



            if (viewModel != null) {
                // read viewModel.input
                viewModelInput = viewModel.input;
            }
            //*******
            updateLiveDataRegistration(0, viewModelInput);


            if (viewModelInput != null) {
                // read viewModel.input.getValue()
                viewModelInputGetValue = viewModelInput.getValue();
            }
    }
    // batch finished
    if ((dirtyFlags & 0xcL) != 0) {
        // api target 1

        this.includeView.setViewModel(viewModel);
    }
    if ((dirtyFlags & 0xdL) != 0) {
        // api target 1

        android.databinding.adapters.TextViewBindingAdapter.setText(this.input, viewModelInputGetValue);
    }
    if ((dirtyFlags & 0x8L) != 0) {
        // api target 1

        android.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.input, (android.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (android.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (android.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, inputandroidTextAttrChanged);
        this.mboundView2.setOnClickListener(mCallback1);
        this.mboundView3.setOnClickListener(mCallback2);
    }
    executeBindingsOn(includeView);
} 
Yes DataBinding Friends of the compiled code should be familiar with this function. The difference is that when you XML The data bound in is LiveData Type, it corresponds to UpDate The method is`updateLiveDataRegistration()`,Take a look at what this method does?

protected boolean updateLiveDataRegistration(int localFieldId, LiveData<?> observable) {
return updateRegistration(localFieldId, observable, CREATE_LIVE_DATA_LISTENER);
}

Internal call`updateRegistration()`Method, which is all that can be notified UI All data types will be called (currently available)`Observable,ObservableList,ObservableMap,LiveData`),The main difference here is`CreateWeakListener`,The types of generated weak reference listeners corresponding to different types are inconsistent. What is used here is`CREATE_LIVE_DATA_LISTENER`Will create a`LiveDataListener`Then get the held weak reference and return.

private boolean updateRegistration(int localFieldId, Object observable,
CreateWeakListener listenerCreator) {
if (observable == null) {
return unregisterFrom(localFieldId);
}
WeakListener listener = mLocalFieldObservers[localFieldId];
if (listener == null) {
//If there is no corresponding listener for the current fieldID, the registered method will be called
registerTo(localFieldId, observable, listenerCreator);
return true;
}
if (listener.getTarget() == observable) {
return false;//nothing to do, same object
}
unregisterFrom(localFieldId);
registerTo(localFieldId, observable, listenerCreator);
return true;
}

  protected void registerTo(int localFieldId, Object observable,
        CreateWeakListener listenerCreator) {

Digression

In more than ten years of working in front-line Internet enterprises, I have guided many peers and younger generations. Help many people learn and grow.

I realize that there are many experiences and knowledge worth sharing with you, and we can also solve many puzzles in IT learning through our ability and experience, so I still insist on sorting and sharing in a variety of ways in the case of busy work. However, due to the limited ways of knowledge dissemination, many programmers can't get the correct materials to learn and improve. Therefore, important advanced Android materials will include user-defined view, performance optimization, the difference between MVC and MVP and MVVM, NDK technology, refined compilation and summary of Ali interview questions, common source code analysis and other learning materials.
CodeChina open source project: Android learning notes summary + mobile architecture Video + big factory interview real questions + project actual combat source code

[Android mind map (skill tree)]

Knowledge system? Here is also the thought brain map of Android advanced learning, for your reference.

Friends in need can go to "like follow + forward" for free!

Android learning notes summary + mobile architecture Video + big factory interview real questions + project actual combat source code]( https://codechina.csdn.net/m0_60958482/android_p7)**

[Android mind map (skill tree)]

Knowledge system? Here is also the thought brain map of Android advanced learning, for your reference.

[external chain picture transferring... (img-afS80mCx-1630926043281)]

Friends in need can go to "like follow + forward" for free!

I hope I can use my strength to help more confused and confused friends and help everyone learn and develop on the IT road~

Topics: Android Design Pattern html