preface

It took a lot of brain work to pull Lifecycle out of a single article. So the next thing that comes naturally is the ViewModel, in order to make the series look like a series, so I’m still going to take the ViewModel out separately.

You don’t say separate out, still really a little dry, ma Ma lai lai, not round. What are you talking about? Plate of it…

A little bit into the pit of JetPack: ViewModel

A bit into the pit of JetPack: Lifecycle

A little bit into the pit of JetPack: LiveData

A little bit into the pit JetPack: NetworkBoundResource for actual foreplay

A little bit into the pit JetPack (final chapter) : Actual COMBAT MVVM

The body of the

A, the ViewModel

A new broom sweeps clean. ViewModel is kind of the hub of the JetPack framework, and to be honest, it’s really hard to talk to on its own, it’s more of a ride with LiveData. There has to be some amway here, ViewModel+LiveData really works, maybe even Room is… Float, pull, feel their size is not short; Crazy, crazy, dare to be king in the universe….

Due to the reason of space, we will talk about the ViewModel separately here, and the comprehensive introduction will show its powerful fighting power in the following…

In terms of the ViewModel, it’s pretty simple. From the official description of the ViewModel, the existence of the ViewModel solves two major problems:

1.1. Solve Problem 1

As we all know, when our Activity/Fragment is destroyed and rebuilt for some reason, our member variables become meaningless. Therefore, we often need to restore the data (and usually make sure it is properly serialized) through onSaveInstanceState() and onCreate()/onSaveInstanceState(Bundle). And for large data books, it is a little weak, such as: List, Bitmap…

ViewModel solves this problem.

1.2. Solve Problem 2

Another problem is that activities/fragments often need to perform some asynchronous operations. When it comes to asynchrony, we all know that there is potential for memory leaks. Therefore, we ensure that the Activity/Fragment is cleaned up immediately after the destruction of asynchronous operations to avoid potential memory leaks.

The ViewModel does not automatically solve this problem for us, but instead gives the business the ability to rewrite it via onCleared().

1.3. Usage method

There really isn’t much to say about using the ViewModel. It’s really easy, a simple demo:

class MyViewModel : ViewModel() {
    var name: String = "MDove"
}

// In the Activity
class MyActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?). {
        val model = ViewModelProviders.of(this).get(MyViewModel::class.java)
        // TODO model.name}}Copy the code

All we need to do is declare the variables we want to save and manage in the ViewModel implementation class. Then get the instance via viewModelproviders.of ()/get(). You can use it as you normally would without having to worry about any of the Activity/Fragment rebuilding issues.

Be warned!

The document is here with a big warning: Caution: A ViewModel must never reference a view, Lifecycle, or any class that may hold a reference to the activity context.

Why? From the issues addressed above, it is clear that the ViewModel will have a longer lifetime than the Activity, so if you hold an instance of the Activity, you will inevitably have a memory leak. A: What if there is a business need? Use AndroidViewModel(Application).

1.4 Fragment sharing

Note that the of method requires passing an Activity/Fragment. Because the ViewModel needs to be bound to its lifecycle. Since we can pass an Activity, we can guess: is the ViewModel visible to the Fragment in the Activity?

Yes, exactly. It is common for two or more Framgent framers in an Activity to need to communicate with each other. This common pain point can be addressed by using ViewModel objects. These fragments can share the ViewModel to handle communication issues.

So in the same Activity, different Fragment instances, can be directly through the incoming Activity, get the same ViewModel instance, and then achieve data communication.

It’s really convenient…

Second, the source

If we open the ViewModel source code, we will find…

public abstract class ViewModel {
    @SuppressWarnings("WeakerAccess")
    protected void onCleared(a) {}}Copy the code

It’s an abstract class. Yes, the whole design of the ViewModel is simple. Let’s look at the ViewModelProviders:

@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity, @Nullable Factory factory) {
    Application application = checkApplication(activity);
    if (factory == null) {
        factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
    }
    return new ViewModelProvider(activity.getViewModelStore(), factory);
}
Copy the code

We can see that in instantiating the ViewModelProvider, we need to pass a ViewModelStore, and that ViewModelStore is taken directly from the incoming FragmentActivity. Let’s go inside and take a look:

@NonNull
@Override
public ViewModelStore getViewModelStore(a) {
    if (getApplication() == null) {
        throw new IllegalStateException("Your activity is not yet attached to the "
                + "Application instance. You can't request ViewModel before onCreate call.");
    }
    if (mViewModelStore == null) {
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if(nc ! =null) {
            // Restore the ViewModelStore from NonConfigurationInstances
            mViewModelStore = nc.viewModelStore;
        }
        if (mViewModelStore == null) {
            mViewModelStore = newViewModelStore(); }}return mViewModelStore;
}
Copy the code

As you can see, this ViewModelStore is a variable of mViewModelStore in the FragmentActivity. What is this ViewModelStore? As the name suggests, it is a ViewModel Store.

ViewModelStore is simple, just a Map that will be expanded later in this article.

When I first saw this, I was confused. ViewModel is the only instance that we’re guaranteed to rebuild, but it’s a member variable, so obviously the variable is gone, right? ! . (PS: Of course, this question is because I am stupid…)

How fat dead, little brother?? . Actually, this is fine, let’s take a closer look, this mViewModelStore assignment is done with this line of code:

NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance();
if(nc ! =null) {
    mViewModelStore = nc.viewModelStore;
}
Copy the code

Yes, this is the line of code that ensures that we restore the original mViewModelStore after the rebuild, thus ensuring that our ViewModel is unique.

@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
    ViewModel viewModel = mViewModelStore.get(key);

    if (modelClass.isInstance(viewModel)) {
        //noinspection unchecked
        return (T) viewModel;
    } else {
        //noinspection StatementWithEmptyBody
        if(viewModel ! =null) {
           // TODO: log a warning.
        }
    }

    viewModel = mFactory.create(modelClass);
    mViewModelStore.put(key, viewModel);
    return (T) viewModel;
}
Copy the code

MViewModelStore source code -> ViewModelStore source code, very common Map storage operations

// 
public class ViewModelStore {

    private final HashMap<String, ViewModel> mMap = new HashMap<>();

    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if(oldViewModel ! =null) { oldViewModel.onCleared(); }}final ViewModel get(String key) {
        return mMap.get(key);
    }

    public final void clear(a) {
        for(ViewModel vm : mMap.values()) { vm.onCleared(); } mMap.clear(); }}Copy the code

Three, small summary

There doesn’t seem to be a “new version of the ship” in terms of the use of the ViewModel… More of a help with some of the existing pits. That’s true, but the ViewModel is more about the idea of data-driven, or MVVM.

The ViewModel acts as the hub, taking data from the data source and sending it to LiveData to notify the UI layer to update the UI. Here’s a chart to illustrate the change:

The Google Sample provides a clever design for a Repository: NetworkBoundResource. The whole class has a total of 120+ code, but based on LiveData+ViewModel to help us constraints: from the server to get from the database, the network to get failed, from the database to get… And so on a series of network requests, local requests.

The design and usage of this class will be discussed in the following practical articles. Yes, when you use them, you will love the “game”.

The end of the

That’s it for today’s post, more of a introduction to the ViewModel. After all, for us, I don’t fucking need to know, just tell me how to write. Old man to write code is CTRL + C /v!

Take your time, little by little. Later, I will take out the code that is running in the business and do actual operation analysis. The meal should be eaten mouthful by mouthful, the article should be written one by one…

I am a fresh graduate, recently and friends to maintain a public number, content is we in the transition from fresh graduate to development of this road to step on the pit, as well as our step by step learning records, if interested in friends can pay attention to, together with the ~