This article has been authorized to be reprinted by guolin_blog, an official wechat account.

This article is mainly on the ViewModel source analysis, it is recommended to read the article on the sample code, the sample code is as follows:

ViewModelDemo

This article uses the source code analysis of Android SDK 29.

define

The Android Framework manages the lifecycle of UI controllers (such as activities and fragments). The Framework may decide to destroy or recreate a UI controller in response to user actions or device events that are completely out of your control.

If the system destroys or recreates a UI controller, any temporary UI-related data you store in it is lost. For example, your application contains a list of users in an Activity, and when the configuration information changes and the Activity is recreated, the new Activity must retrieve the list of users again. For simple data, an Activity can use the onSaveInstanceState() method and recover data from the Bundle in the onCreate() method, but this method only works for small amounts of data that can be serialized and deserialized. Rather than potentially large data user lists or lots of bitmaps.

Another problem is the UI controller often requires asynchronous calls, this may take some time to return to the UI controller need to manage these calls, and ensure the system to clean up after destruction, to avoid potential memory leaks, and this kind of management requires a lot of maintenance, and for the configuration changes to create objects, it is a waste of resource, Because the object may have to re-issue the call it already made.

UI controllers (such as activities and fragments) are mainly used to display UI data, respond to user actions, or handle operating system communication (such as: Permission requests), requiring the UI controller to also be responsible for loading data from the database or network can swell the class, and assigning too much responsibility to the UI controller can cause a single class view to handle all the work of the application itself rather than delegating it to other classes, which can also make testing more difficult.

It would have been simpler and more efficient to separate view data ownership from the UI controller’s logic, so one component was officially introduced: the ViewModel.

A ViewModel is a class that prepares and manages activities or fragments, and handles their communication with the rest of the application (for example, calling business logic classes).

A ViewModel is always created in an Activity or Fragment, and is retained as long as the corresponding Activity or Fragment is active (for example, if it is an Activity, until it finished).

In other words, this means that a ViewModel will not be destroyed due to configuration changes (e.g., rotation), and all new instances will be reconnected to the existing ViewModel.

The purpose of a ViewModel is to retrieve and store information that an Activity or Fragment needs. The Activity or Fragment should be able to observe changes in the ViewModel. This information is usually exposed via LiveData or an Android Data Binding.

Note that the ViewModel’s sole responsibility is to manage the UI’s data. It should not access your view hierarchy or retain references to activities or fragments.

The following image shows the various life cycle states of the Activity as it goes through the screen rotation and then ends, with the ViewModel life cycle displayed next to the associated Activity life cycle:

The sample code

The project adds the following dependencies:

implementation 'androidx. Lifecycle: lifecycle - extensions: 2.2.0 - alpha02'
Copy the code

Since I’m using DataBinding, I add the following code:

dataBinding {
    enabled = true
}
Copy the code

The project structure is as follows:

B: defines a inherited the ViewModel, and realized the observables ObservableViewModel class, to notify the change of control data, also can use LiveData to realize such a function, the code is as follows:

package com.tanjiajun.viewmodeldemo.viewmodel

import androidx.databinding.Observable
import androidx.databinding.PropertyChangeRegistry
import androidx.lifecycle.ViewModel

/** * Created by TanJiaJun on 2019-11-24. */
open class ObservableViewModel : ViewModel(), Observable {

    private val callbacks = PropertyChangeRegistry()

    override fun addOnPropertyChangedCallback(callback: Observable.OnPropertyChangedCallback?). =
        callbacks.add(callback)

    override fun removeOnPropertyChangedCallback(callback: Observable.OnPropertyChangedCallback?). =
        callbacks.remove(callback)

    fun notifyChange(a) =
        callbacks.notifyCallbacks(this.0.null)

    fun notifyPropertyChanged(fieldId: Int) =
        callbacks.notifyCallbacks(this, fieldId, null)}Copy the code

First example: The ViewModel is not destroyed due to configuration changes

Create MainViewModel in MainActivity as follows:

// MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?). {
    super.onCreate(savedInstanceState)
    DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main).also {
        it.viewModel = ViewModelProviders.of(this)[MainViewModel::class.java].apply {
            name = "Tan Ka Chun"
            age = 25
            gender = "Male"
        }
        it.handlers = this}}Copy the code

The interface for the Activity can be rotated to follow the phone’s screen, and there is no property specified by Android :configChanges, which only calls the onConfigurationChanged() method of the Activity when specifying property changes. Instead of being destroyed and rebuilt, the code is as follows:

android:configChanges="orientation|screenSize|keyboardHidden"
Copy the code

When we rotated the screen of the phone, we found that the content of the Activity did not change, as we expected.

The second example is a Fragment that uses the ViewModel shared by the Activity to process data

Define NameViewModel, and inherit ObservableViewModel as I mentioned above, in the following code:

package com.tanjiajun.viewmodeldemo.viewmodel

import androidx.databinding.Bindable
import androidx.databinding.library.baseAdapters.BR

/** * Created by TanJiaJun on 2019-11-24. */
class NameViewModel : ObservableViewModel() {

    @get:Bindable
    var name = ""
        set(value) {
            field = value
            notifyPropertyChanged(BR.name)
        }

}
Copy the code

Use a NameViewModel in the FirstNameFragment with the same NameActivity lifecycle as the following code:

// FirstNameFragment.kt
private var viewModel: NameViewModel? = null

override fun onCreate(savedInstanceState: Bundle?). {
    super.onCreate(savedInstanceState)
    // The retainInstance method is resolved below
    retainInstance = trueviewModel = activity? .let { ViewModelProviders.of(it)[NameViewModel::class.java].apply {
            name = "Tan Ka Chun"}}}override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup? , savedInstanceState:Bundle?).: View? =
    DataBindingUtil.inflate<FragmentFirstNameBinding>(
        inflater,
        R.layout.fragment_first_name,
        container,
        false
    )
        .also {
            // Use the NameViewModel shared by NameActivity
            it.viewModel = viewModel
            it.handlers = this
        }
        .root
Copy the code

The retainInstance method controls recreating the Activity (for example: The onCreate(Bundle) method will not be called because the Fragment is not being recreated. The onCreate(Bundle) method will not be called because the Fragment is not recreated. OnDestroy () will not be called, but the onDetach() method will be called because the Fragment simply detaches from the Activity to which it is attached, The onAttach(Activity) and onActivityCreated(Bundle) methods will still be called.

// SecondNameFragment.kt
override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup? , savedInstanceState:Bundle?).: View? =
    DataBindingUtil.inflate<FragmentSecondNameBinding>(
        inflater,
        R.layout.fragment_second_name,
        container,
        false
    )
        .also { it.handlers = this }
        .root

// Clicking the button changes the name property value in NameViewModel
override fun onChangeNameToAppleClick(view: View){ activity? .let { ViewModelProviders.of(it)[NameViewModel::class.java].name= "apple"}
}
Copy the code

After clicking the SecondFragment button, press the back button to return to the last Fragment. We can see that the name has changed from ** “tan jiajun” to “apple”, where the NameViewModel life cycle is the same as the NameActivity life cycle. That is, both fragments get the same ViewModel**, so we can do this with data attached to multiple fragments of the same Activity.

Source code analysis

Let’s look at the ViewModelProviders class. The code is as follows:

// Create a ViewModelProvider that preserves the ViewModel while the Fragment is active
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment) {
    return of(fragment, null);
}

// Create a ViewModelProvider that preserves the ViewModel while the Activity is active
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
    return of(activity, null);
}

@NonNull
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
    // Check whether the Fragment is attached to the Application
    Application application = checkApplication(checkActivity(fragment));
    // In the above method factory is passed null
    if (factory == null) {
        // Create a singleton AndroidViewModelFactory
        factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
    }
    // Create the ViewModelProvider, which will get the Fragment's ViewModelStore
    return new ViewModelProvider(fragment.getViewModelStore(), factory);
}

@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity, @Nullable Factory factory) {
    // Check whether the Activity is attached to the Application
    Application application = checkApplication(activity);
    // In the above method factory is passed null
    if (factory == null) {
        // Create a singleton AndroidViewModelFactory
        factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
    }
    // Create the ViewModelProvider, which will get the Activity's ViewModelStore
    return new ViewModelProvider(activity.getViewModelStore(), factory);
}
Copy the code

Let’s look at the Activity’s **getViewModelStore()** method, which looks like this:

@NonNull
@Override
public ViewModelStore getViewModelStore(a) {
    // Check whether the Activity is attached to the Application
    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) {
        / / by getLastNonConfigurationInstance () method to get NonConfigurationInstances, the following analysis
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if(nc ! =null) {
            / / from NonConfigurationInstances ViewModelStore recovery
            mViewModelStore = nc.viewModelStore;
        }
        // Create a ViewModelStore object if it is empty
        if (mViewModelStore == null) {
            mViewModelStore = newViewModelStore(); }}return mViewModelStore;
}
Copy the code

Based on the analysis of getLastNonConfigurationInstances () method, we look at the onRetainNonConfigurationInstance () method, it is a return null in Activity class, We can find the Activity subclass ComponentActivity and see that it overrides this method as follows:

// ComponentActivity.java
/ / NonConfigurationInstances is a static class final, there are two variables: the custom and viewModelStore
static final class NonConfigurationInstances {
    Object custom;
    ViewModelStore viewModelStore;
}

@Override
@Nullable
public final Object onRetainNonConfigurationInstance(a) {
    / / onRetainCustomNonConfigurationInstance () method has been deprecated
    Object custom = onRetainCustomNonConfigurationInstance();

    ViewModelStore viewModelStore = mViewModelStore;
    if (viewModelStore == null) {
        // If viewModelStore is null, no one called getViewModelStore(), so let's see if viewModelStore exists in our last NonConfigurationInstance
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if(nc ! =null) {
            / / and if so, they took ViewModelStore from NonConfigurationInstancesviewModelStore = nc.viewModelStore; }}if (viewModelStore == null && custom == null) {
        / / if ViewModelStore or null and custom is null, no NonConfigurationInstances
        return null;
    }

    / / if you have any custom ViewModelStore or, creates NonConfigurationInstances object, and carries on the assignment
    NonConfigurationInstances nci = new NonConfigurationInstances();
    nci.custom = custom;
    nci.viewModelStore = viewModelStore;
    return nci;
}
Copy the code

OnRetainNonConfigurationInstance () method is in an Activity is destroyed because of the configuration change when invoked, will create a new instance at this moment, it will be in onStop () and onDestroy () method calls between, Here we can return an object, or even the Activity instance can also, then we can in the new instance of the Activity by * * getLastNonConfigurationInstance () method to retrieve the * *, to get what we want.

We also used the onSaveInstanceState method before calling this method to retrieve the state of each instance of the Activity before it is terminated so that the state can be restored in the onCreate or onRestoreInstanceState methods. Both methods pass in the Bundle object that we wanted to keep. Note that you also need to set the ID of your View, because it holds the current focused View by ID. In Android P, this method is called after onStop(). In previous versions, This method will be called before onStop(), and there is no guarantee that it will be called before or after onPause(), which by default holds temporary information about the Activity’s view-level state, such as: Text in EditText and scrollbar position in ListView or RecyclerView.

The method and onRetainNonConfigurationInstance onSaveInstanceState () method and what’s the difference? For one thing, the Bundle is saved to the Bundle, which has type and size limits and also serializes and deserializes data in the main thread, while the Bundle is saved to the Object, which has no type or size limits.

We continue to look at the source code, from the above analysis, will create ViewModelStore object, we look at the ViewModelStore source code, the code is as follows:

public class ViewModelStore {

    // Create a HashMap object with key String and value ViewModel
    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);
    }

    Set<String> keys(a) {
        return new HashSet<>(mMap.keySet());
    }

    // Clears the internal storage and notifies all viewModels stored in the HashMap that they are no longer in use
    public final void clear(a) {
        for(ViewModel vm : mMap.values()) { vm.clear(); } mMap.clear(); }}Copy the code

It holds the ViewModel via HashMap, and when we go back to the ViewModelProviders of method above, we can see that it creates the ViewModelProvider object. Look at its constructor:

// ViewModelProvider.java
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
    mFactory = factory;
    mViewModelStore = store;
}
Copy the code

The constructor takes two arguments. The first is ViewModelStore, which holds the ViewModel. The second argument is Factory, which is used to instantiate the factories of multiple ViewModels.

In our sample code, we call the Get method of the ViewModelProvider and pass in the Class object of the ViewModel we created.

// ViewModelProvider.java
private static final String DEFAULT_KEY =
        "androidx.lifecycle.ViewModelProvider.DefaultKey";

@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
    // Get the specification name of the underlying Class defined by the Java language specification of the ViewModel's Class object
    String canonicalName = modelClass.getCanonicalName();
    if (canonicalName == null) {
        throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
    }
    // Call the following get method, passing in the string DEFAULT_KEY: the canonical name of modelClass and the Class object for ViewModel
    return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}

@SuppressWarnings("unchecked")
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
    // Get the ViewModel from the HashMap in ViewModelStore by key
    ViewModel viewModel = mViewModelStore.get(key);

    // Determine whether the ViewModel obtained from the ViewModelStore is an instance of the Class object, i.e. whether the desired ViewModel exists in the ViewModelStore
    if (modelClass.isInstance(viewModel)) {
        // Return the corresponding ViewModel if there is one
        return (T) viewModel;
    } else {
        //noinspection StatementWithEmptyBody
        if(viewModel ! =null) {
            // TODO: log a warning.}}// If not, create the ViewModel
    if (mFactory instanceof KeyedFactory) {
        viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
    } else {
        // mFactory is a subclass of The NewInstanceFactory implementation class AndroidViewModelFactory
        viewModel = (mFactory).create(modelClass);
    }
    // Store the created ViewModel in the ViewModelStore
    mViewModelStore.put(key, viewModel);
    / / return the ViewModel
    return (T) viewModel;
}
Copy the code

Let’s look at the create method on AndroidViewModelFactory. The code is as follows:

// The static internal class AndroidViewModelFactory in ViewModelProvider
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
    // Determine whether the class or interface represented by AndroidViewModel is the same as the class or interface represented by modelClass, or whether it is its superclass or superinterface
    if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
        //noinspection TryWithIdenticalCatches
        try {
            // Create the ViewModel object
            return modelClass.getConstructor(Application.class).newInstance(mApplication);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException("Cannot create an instance of " + modelClass, e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Cannot create an instance of " + modelClass, e);
        } catch (InstantiationException e) {
            throw new RuntimeException("Cannot create an instance of " + modelClass, e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException("Cannot create an instance of "+ modelClass, e); }}// According to our sample code, the modelClass we pass in is not AndroidViewModel, nor is it a superclass or superinterface, so the following logic is executed
    return super.create(modelClass);
}
Copy the code

You can’t pass in any object that has a Context reference, which will leak memory. AndroidViewModel can be used if you need to use it.

The create method of its parent class, NewInstanceFactory, is then called as follows:

@SuppressWarnings("ClassNewInstance")
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
    //noinspection TryWithIdenticalCatches
    try {
        // Create a new instance of a class represented by a modelClass object
        return modelClass.newInstance();
    } catch (InstantiationException e) {
        throw new RuntimeException("Cannot create an instance of " + modelClass, e);
    } catch (IllegalAccessException e) {
        throw new RuntimeException("Cannot create an instance of "+ modelClass, e); }}Copy the code

**getViewModelStore()** Fragment = getViewModelStore()

// Fragment.java
@NonNull
@Override
public ViewModelStore getViewModelStore(a) {
    // Check whether the Fragment has been separated from the Activity
    if (mFragmentManager == null) {
        throw new IllegalStateException("Can't access ViewModels from detached fragment");
    }
    return mFragmentManager.getViewModelStore(this);
}
Copy the code

The FragmentManagerImpl getViewModelStore method is called as follows:

// FragmentManagerImpl.java
@NonNull
ViewModelStore getViewModelStore(@NonNull Fragment f) {
    return mNonConfig.getViewModelStore(f);
}
Copy the code

The member variable mNonConfig is a reference to FragmentManagerVIewModel. Let’s look at the FragmentManagerVIewModel getViewModelStore method as follows:

// FragmentManagerViewModel.java
@NonNull
ViewModelStore getViewModelStore(@NonNull Fragment f) {
    ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
    if (viewModelStore == null) {
        viewModelStore = new ViewModelStore();
        mViewModelStores.put(f.mWho, viewModelStore);
    }
    return viewModelStore;
}
Copy the code

The member variable mViewModelStores is a reference to a HashMap whose key is String and value is ViewModelStore. It follows the Fragment lifecycle. Retrieves ViewModelStore from the HashMap according to the internal unique name of Frament, if empty, creates a new ViewModelStore object and places it in mViewModelStores, then returns the object; If it is not empty, return the ViewModelStore you just fetched from the HashMap.

At this point, the ViewModel is created and the source code is analyzed. Then we see when the ViewModel is destroyed. When we analyze the ViewModelStore source code above, we see that there is a clear method, This method is used to clear the internal storage and inform all viewModels stored in the HashMap that they are no longer in use, if the ViewModel follows the Activity’s lifecycle. It calls this method in the following code:

public ComponentActivity(a) {
    // Omit some code
    getLifecycle().addObserver(new LifecycleEventObserver() {
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
            // Determine whether the destroy state of the Activity is received
            if (event == Lifecycle.Event.ON_DESTROY) {
                // If received, determine whether destroy was caused by a configuration change
                if(! isChangingConfigurations()) {// If not, call the ViewModelStore clear methodgetViewModelStore().clear(); }}}});// Omit some code
}
Copy the code

If the ViewModel follows the Fragment’s life cycle, it calls this method in code like this:

// FragmentManagerViewModel.java
void clearNonConfigState(@NonNull Fragment f) {
    if (FragmentManagerImpl.DEBUG) {
        Log.d(FragmentManagerImpl.TAG, "Clearing non-config state for " + f);
    }
    // Clear and delete the Fragment subconfiguration state
    FragmentManagerViewModel childNonConfig = mChildNonConfigs.get(f.mWho);
    if(childNonConfig ! =null) {
        childNonConfig.onCleared();
        mChildNonConfigs.remove(f.mWho);
    }
    // Clear and delete the Fragment ViewModelStore
    ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
    if(viewModelStore ! =null) { viewModelStore.clear(); mViewModelStores.remove(f.mWho); }}Copy the code

Call the clearNonConfigState method in the following code:

// FragmentManagerImpl.java
@SuppressWarnings("ReferenceEquality")
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
                 boolean keepActive) {
    // Omit some code
    if (f.mState <= newState) {
        // Omit some code
    } else if (f.mState > newState) {
        switch (f.mState) {
            // Omit some code
            case Fragment.CREATED:
                if (newState < Fragment.CREATED) {
                    // Omit some code
                    if(f.getAnimatingAway() ! =null|| f.getAnimator() ! =null) {
                        // Omit some code
                    } else {
                        if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
                        booleanbeingRemoved = f.mRemoving && ! f.isInBackStack();// Determine whether the Fragment is removing without putting it on the back stack, or whether FragmentManagerViewModel should be destroyed
                        if (beingRemoved || mNonConfig.shouldDestroy(f)) {
                            boolean shouldClear;
                            // Determine if mHost is an instance of ViewModelStoreOwner
                            if (mHost instanceof ViewModelStoreOwner) {
                                // If yes, shouldClear is whether FragmentManagerViewModel is cleared
                                shouldClear = mNonConfig.isCleared();
                            } else if (mHost.getContext() instanceofActivity) { Activity activity = (Activity) mHost.getContext(); shouldClear = ! activity.isChangingConfigurations(); }else {
                                shouldClear = true;
                            }
                            // Remove the ViewModel according to the value of beingRemoved or shouldClear
                            if (beingRemoved || shouldClear) {
                                // If so, call the clearNonConfigState method
                                mNonConfig.clearNonConfigState(f);
                            }
                            // Execute the Fragment onDestroy() method
                            f.performDestroy();
                            dispatchOnFragmentDestroyed(f, false);
                        } else {
                            f.mState = Fragment.INITIALIZING;
                        }
                        // Omit some code}}}}// Omit some code
}
Copy the code

At this point, the ViewModel destruction source code analysis is done.

OnSaveInstanceState and ViewModel

OnSaveInstanceState is a lifecycle callback method that holds a small amount of UI-related data in two states:

  • Application processes were terminated in the background due to memory limitations.
  • Configuration changes.

OnSaveInstanceState is not designed to store large data like bitmaps, but rather small, UI-specific data that can be serialized and deserialized, as mentioned above.

The ViewModel has the following benefits:

  • Viewmodels can be architturally better, separating UI code from data, making code more accountable, modular, and easier to test.
  • Viewmodels can store larger, more complex data with unlimited data types, and can even store Activity instances.

Note that the ViewModel can only be preserved in the event of destruction caused by a configuration change, not in the event of a terminated process, which means that the ViewModel will be destroyed when the application process terminates in the background due to memory limitations.

So it’s best to combine the two to deal with saving and restoring UI state, and to persist data locally if you want to keep it from getting lost.

digression

If the application does not need to update resources during a particular configuration change, and you need to avoid restarting the Activity due to performance limitations, you can prevent the system from restarting the Activity by declaring that the Activity handles the configuration change itself.

By in the AndroidManifest file, we can find the corresponding element of * *, add the android: configChanges attribute, the declare multiple configuration values, can be separated by | * * character of its.

Android officially advises against using this method for most applications, as it may make it harder to use alternate resources.

It has the following attributes:

  • Density: Display density changes. For example, the user may have specified a different display ratio, or different displays are active. ** Please note: ** is a new configuration at API level 24.

  • FontScale: The font scaling factor has changed, for example: the user has selected a new global size.

  • Keyboard: Indicates that the keyboard type is changed, for example, an external keyboard is inserted.

  • KeyboardHidden: The keyboard accessibility is changed. For example, the user displays a hard keyboard.

  • LayoutDirection: the layoutDirection is changed, for example, from left to right (LTR) to right to left (RTL). ** Please note: ** is a new configuration in API level 17.

  • Locale: The language area changes. For example, the user selects a new display language for the text.

  • MCC: THE IMSI mobile device country/area code (MCC) has changed. For example, a SIM has been detected and the MCC has been updated.

  • MNC: IMSI Mobile Device Network code (MNC) has changed, for example: SIM detected and MNC updated.

  • Navigation: Navigation type (trackball/arrow keys) changed. (This usually doesn’t happen.)

  • Orientation: The screen orientation changes, for example, the user rotates the device. Note: If the application is for Android 3.2 (API level 13) or higher, you should also declare the screenSize configuration, as this configuration also changes when the device switches between landscape and portrait.

  • ScreenLayout: changes to the screenLayout, e.g. different displays may now be active.

  • ScreenSize: the current available screenSize has changed. This value represents the change in the currently available size relative to the current aspect ratio, and changes when the user switches between landscape and portrait. ** Please note: ** is a new configuration in API level 13.

  • SmallestScreenSize: The physical screen size is changed. This value represents a size change independent of direction, so it only changes if the actual physical screen size changes, such as switching to an external display. A change to this configuration corresponds to a change in the smallestWidth configuration. ** Please note: ** is a new configuration in API level 13.

  • Touchscreen: the touchscreen is changed. (This usually doesn’t happen.)

  • UiMode: The interface mode has changed, for example, the user has placed the device in the desktop or car dock, or the night mode has changed. For more information about the different interface modes, see UiModeManager. ** Please note: ** is a new configuration in API level 8.

All of these configuration changes can affect the value of the resource seen by the application, so when the **onConfigurationChanged()** method is called, it is often necessary to retrieve all resources again (including view layout, drawable objects, and so on) to properly handle the changes.

My GitHub: TanJiaJunBeyond

Common Android Framework: Common Android framework

My nuggets: Tan Jiajun

My simple book: Tan Jiajun

My CSDN: Tan Jiajun