ViewModel source code parsing
Source code version:
- The ViewModel: 2.4.0
- Android: 31
- Androidx. Activity: the activity: 1.4.0
- Androidx. Fragments: fragments: 1.4.0
Will use: Lifecycle
Navigation:
- Jetpack-lifecycle source code parsing
- Jetpack-livedata source code parsing
- Jetpack-viewmodel source code
- See more articles here: home page
use
Declare the ViewModel
class MyViewModel : ViewModel() {
override fun onCleared(a) {
super.onCleared()
}
}
Copy the code
Access to the ViewModel
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?). {
/ / get the ViewModel
val model = ViewModelProvider(this).get(MyViewModel::class.java)
// observe
model.getUsers().observe(this, Observer<List<User>>{ users ->
// update UI}}})Copy the code
ViewModel lifecycle
The source code
Declare the ViewModel
The ViewModel class
public abstract class ViewModel {
// Tag collection
@Nullable
private final Map<String, Object> mBagOfTags = new HashMap<>();
// Whether the flag is cleared
private volatile boolean mCleared = false;
// Called when the ViewModel is cleared
protected void onCleared(a) {}@MainThread
final void clear(a) {
mCleared = true;
if(mBagOfTags ! =null) {
synchronized (mBagOfTags) {
for (Object value : mBagOfTags.values()) {
// see comment for the similar call in setTagIfAbsent
closeWithRuntimeException(value);
}
}
}
onCleared();
}
// Add data key and value. If the value of key already exists, return the existing value, otherwise add a new value.
// If the ViewModel is cleared, the value returned is Closeable and is released by calling close. That is, the ViewModel has been cleared and a new one is added.
@SuppressWarnings("unchecked")
<T> T setTagIfAbsent(String key, T newValue) {
T previous;
synchronized (mBagOfTags) {
previous = (T) mBagOfTags.get(key);
if (previous == null) {
mBagOfTags.put(key, newValue);
}
}
T result = previous == null ? newValue : previous;
if (mCleared) {
closeWithRuntimeException(result);
}
return result;
}
// Get the added data
<T> T getTag(String key) {
if (mBagOfTags == null) {
return null;
}
synchronized (mBagOfTags) {
return(T) mBagOfTags.get(key); }}private static void closeWithRuntimeException(Object obj) {
if (obj instanceof Closeable) {
// Is a subclass of Closeable, close is called.
try {
((Closeable) obj).close();
} catch (IOException e) {
throw newRuntimeException(e); }}}}Copy the code
When the ViewModel is cleared, the Tag is cleared and the onCleared method is called to notify the ViewModel that it has been cleared.
Access to the ViewModel
use
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?). {
/ / get the ViewModel
val model = ViewModelProvider(this).get(MyViewModel::class.java)
// observe
model.getUsers().observe(this, Observer<List<User>>{ users ->
// update UI}}})Copy the code
To get a ViewModel, we need to create the ViewModelProvider, and then call its GET method to get it. Let’s first look at how the ViewModelProvider object is created, and then look at how the GET method is obtained.
ViewModelProvider constructor
ViewModelProvider constructor
public open class ViewModelProvider(
private val store: ViewModelStore,
private val factory: Factory
) {
public constructor(
owner: ViewModelStoreOwner
) : this(owner.viewModelStore, defaultFactory(owner))
public constructor(owner: ViewModelStoreOwner, factory: Factory) : this(
owner.viewModelStore,
factory
)
}
Copy the code
ViewModelProvider for ViewModel provider, create it needs ViewModelStore and ViewModelProvider. Factory, and ViewModelStore can obtain from ViewModelStoreOwner, Let’s look at each of these classes.
ViewModelStore
ViewModelStore class
public class ViewModelStore {
/ / the ViewModel collection
private final HashMap<String, ViewModel> mMap = new HashMap<>();
TestViewModel
// Save the ViewModel. If the key already exists, the value is overwritten, and the previous ViewModel calls the onCleared logic.
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.put(key, viewModel);
if(oldViewModel ! =null) { oldViewModel.onCleared(); }}/ / get the ViewModel
final ViewModel get(String key) {
return mMap.get(key);
}
// Get all keys
Set<String> keys(a) {
return new HashSet<>(mMap.keySet());
}
// Clear up internal stores and inform ViewModels that they are no longer in use.
public final void clear(a) {
for(ViewModel vm : mMap.values()) { vm.clear(); } mMap.clear(); }}Copy the code
The ViewModelProvider is a ViewModel store that stores or retrieves viewModels, implemented using HashMap. Its clear method clears the internal stores and notifies ViewModels that they are no longer in use.
ViewModelStoreOwner
ViewModelStoreOwner class
public interface ViewModelStoreOwner {
@NonNull
ViewModelStore getViewModelStore(a);
}
Copy the code
ViewModelStoreOwner is the owner of ViewModelStore, which can be obtained by subclasses of ViewModelStore. Both activities and fragments on androidx already implement ViewModelStoreOwner. Let’s look at the implementation.
Activity
Androidx.activity.Com ponentActivity class
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
ContextAware.LifecycleOwner.ViewModelStoreOwner.HasDefaultViewModelProviderFactory.SavedStateRegistryOwner.OnBackPressedDispatcherOwner.ActivityResultRegistryOwner.ActivityResultCaller {
private ViewModelStore mViewModelStore;
@NonNull
@Override
public ViewModelStore getViewModelStore(a) {
if (getApplication() == null) {
// The ViewModel cannot be obtained before the onCreate call
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
/ / make sure ViewModelStore
ensureViewModelStore();
/ / return ViewModelStore
return mViewModelStore;
}
@SuppressWarnings("WeakerAccess") /* synthetic access */
void ensureViewModelStore(a) {
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if(nc ! =null) {
/ / to recover from NonConfigurationInstances ViewModelStore
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
// if mViewModelStore is empty, it will be created.
mViewModelStore = newViewModelStore(); }}}}Copy the code
Get ViewModelStore androidx Activity, recover from NonConfigurationInstances ViewModelStore (first to ensure the Activity after reconstruction can get ViewModelStore before, How does the ViewModel remain unchanged? , if no, create it.
Description:
androidx
Activity
Not in theonCreate
callbeforeTo obtainViewModel
.
Fragment
Androidx. Fragments. App. The fragments
public class Fragment implements ComponentCallbacks.OnCreateContextMenuListener.LifecycleOwner.ViewModelStoreOwner.HasDefaultViewModelProviderFactory.SavedStateRegistryOwner.ActivityResultCaller {
@NonNull
@Override
public ViewModelStore getViewModelStore(a) {
if (mFragmentManager == null) {
Detached ViewModels cannot be accessed from the detached Fragment
throw new IllegalStateException("Can't access ViewModels from detached fragment");
}
if (getMinimumMaxLifecycleState() == Lifecycle.State.INITIALIZED.ordinal()) {
// When using setMaxLifecycle(INITIALIZED), getViewModelStore() is not supported before the Fragment reaches onCreate()
throw new IllegalStateException("Calling getViewModelStore() before a Fragment "
+ "reaches onCreate() when using setMaxLifecycle(INITIALIZED) is not "
+ "supported");
}
return mFragmentManager.getViewModelStore(this); }}Copy the code
FragmentManager –> getViewModelStore method
@NonNull
ViewModelStore getViewModelStore(@NonNull Fragment f) {
return mNonConfig.getViewModelStore(f);
}
Copy the code
FragmentManagerViewModel –> getViewModelStore method
@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
FragmentManagerViewModel AndroidX Fragment retrievalViewModelStore androidX Fragment retrievalViewModelStore How does the ViewModel remain unchanged? , and then get it from its mViewModelStores, and if not, create it.
Description:
androidx
Fragment
Not in theonDetach
callafterTo obtainViewModel
.
ViewModelProvider.Factory
ViewModelProvider. Factory class
public interface Factory {
// Create a new instance of the given ViewModel Class.
@NonNull
<T extends ViewModel> T create(@NonNull Class<T> modelClass);
}
Copy the code
ViewModelProvider. Factory for the ViewModel creation Factory, the Factory through the ViewModel class class, create ViewModel instance. Let’s look at its subclasses KeyedFactory, NewInstanceFactory, and AndroidViewModelFactory.
ViewModelProvider.KeyedFactory
ViewModelProvider. KeyedFactory class
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public abstract class KeyedFactory : OnRequeryFactory(), Factory {
public abstract fun <T : ViewModel> create(
key: String,
modelClass: Class<T>): T
override fun <T : ViewModel> create(modelClass: Class<T>): T {
throw UnsupportedOperationException(
"create(String, Class
) must be called on implementations of KeyedFactory")}}Copy the code
KeyedFactory is an abstract subclass of Factory that overrides create(Class
) method, and the KeyedFactory subclass must override the create(Class
) method and should call its create(String, Class
) method.
ViewModelProvider.NewInstanceFactory
ViewModelProvider. NewInstanceFactory class
public open class NewInstanceFactory : Factory {
@Suppress("DocumentExceptions")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return try {
// Get the instance by reflection
modelClass.newInstance()
} catch (e: InstantiationException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
} catch (e: IllegalAccessException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
}
}
public companion object {
private var sInstance: NewInstanceFactory? = null
/ / the singleton NewInstanceFactory
@JvmStatic
public val instance: NewInstanceFactory
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
get() {
if (sInstance == null) {
sInstance = NewInstanceFactory()
}
returnsInstance!! }}}Copy the code
NewInstanceFactory is a subclass of Factory that implements create(Class
) method to create an instance of ViewModel through the class of the ViewModel class.
Description:
- use
NewInstanceFactory
To create theViewModel
There must beNo argumentsandNot privateThe construction method of.
- Can be handled as follows
ViewModel
:
class MyViewModel : ViewModel()
NewInstanceFactory.instance
Is a global singletonNewInstanceFactory
, prevents each factory creation and optimizes performance.
ViewModelProvider.AndroidViewModelFactory
ViewModelProvider. AndroidViewModelFactory class
public open class AndroidViewModelFactory(
private val application: Application
) : NewInstanceFactory() {
@Suppress("DocumentExceptions")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {
try {
// This ViewModel is a subclass of AndroidViewModel, passed to Application and created.
modelClass.getConstructor(Application::class.java).newInstance(application)
} catch (e: NoSuchMethodException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
} catch (e: IllegalAccessException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
} catch (e: InstantiationException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
} catch (e: InvocationTargetException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
}
} else super.create(modelClass) // Otherwise, reflection creation of the parent class is performed.
}
public companion object {
// Get the default factory, owner's if owner has a default factory, otherwise NewInstanceFactory (created by reflection).
internal fun defaultFactory(owner: ViewModelStoreOwner): Factory =
if (owner is HasDefaultViewModelProviderFactory)
owner.defaultViewModelProviderFactory else instance
// Get the default Key
internal const val DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey"
private var sInstance: AndroidViewModelFactory? = null
/ / the singleton AndroidViewModelFactory
@JvmStatic
public fun getInstance(application: Application): AndroidViewModelFactory {
if (sInstance == null) {
sInstance = AndroidViewModelFactory(application)
}
returnsInstance!! }}}Copy the code
AndroidViewModelFactory is a subclass of NewInstanceFactory that overrides create(Class
< span style = “box-sizing: border-box; color: RGB (74, 74, 74); line-height: 22px; font-size: 14px! Important; word-wrap: inherit! Important;”
Description:
- use
AndroidViewModelFactory
Create if thisViewModel
isAndroidViewModel
Subclass, must haveA referenceAnd isApplication
andNot private(can not be without parameters); Otherwise there has to beNo argumentsandNot privateConstructor of the.
- Can be handled as follows
ViewModel
:
class MyViewModel : ViewModel()
class MyViewModel(application: Application) : AndroidViewModel(application)
AndroidViewModelFactory.getInstance
Is a global singletonAndroidViewModelFactory
, prevents each factory creation and optimizes performance.
DefaultFactory method to obtain the default factory, if ViewModelStoreOwner subclass also realized HasDefaultViewModelProviderFactory, are provided with the factory, Otherwise, use the NewInstanceFactory factory (create a no-argument ViewModel).
HasDefaultViewModelProviderFactory
HasDefaultViewModelProviderFactory class
public interface HasDefaultViewModelProviderFactory {
// Get the default Factory
@NonNull
ViewModelProvider.Factory getDefaultViewModelProviderFactory(a);
}
Copy the code
HasDefaultViewModelProviderFactory tag can get to the default Factory. Has achieved HasDefaultViewModelProviderFactory androidx Activity and fragments, let’s have a look at their specific implementation respectively.
Activity
Androidx.activity.Com ponentActivity class
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
ContextAware,
LifecycleOwner,
ViewModelStoreOwner,
HasDefaultViewModelProviderFactory,
SavedStateRegistryOwner,
OnBackPressedDispatcherOwner,
ActivityResultRegistryOwner,
ActivityResultCaller {
private ViewModelProvider.Factory mDefaultFactory;
@NonNull
@Override
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
if (getApplication() == null) {
// The ViewModel cannot be obtained before the onCreate call
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
if (mDefaultFactory == null) {
/ / the default factory is empty, is to create SavedStateViewModelFactory, the Application, the current page of the incoming parameters, passed to the constructor.
mDefaultFactory = new SavedStateViewModelFactory(
getApplication(),
this, getIntent() ! =null ? getIntent().getExtras() : null);
}
returnmDefaultFactory; }}Copy the code
Fragment
Androidx. Fragments. App. The fragments
public class Fragment implements ComponentCallbacks.OnCreateContextMenuListener.LifecycleOwner.ViewModelStoreOwner.HasDefaultViewModelProviderFactory.SavedStateRegistryOwner.ActivityResultCaller {
ViewModelProvider.Factory mDefaultFactory;
@NonNull
@Override
public ViewModelProvider.Factory getDefaultViewModelProviderFactory(a) {
if (mFragmentManager == null) {
Detached ViewModels cannot be accessed from the detached Fragment
throw new IllegalStateException("Can't access ViewModels from detached fragment");
}
if (mDefaultFactory == null) {
/ / the default factory is empty, is to create SavedStateViewModelFactory, the Application, the current page of the incoming parameters, passed to the constructor.
Application application = null;
Context appContext = requireContext().getApplicationContext();
while (appContext instanceof ContextWrapper) {
if (appContext instanceof Application) {
application = (Application) appContext;
break;
}
appContext = ((ContextWrapper) appContext).getBaseContext();
}
if (application == null && FragmentManager.isLoggingEnabled(Log.DEBUG)) {
Log.d(FragmentManager.TAG, "Could not find Application instance from "
+ "Context " + requireContext().getApplicationContext() + ", you will "
+ "not be able to use AndroidViewModel with the default "
+ "ViewModelProvider.Factory");
}
/ / create SavedStateViewModelFactory
mDefaultFactory = new SavedStateViewModelFactory(
application,
this,
getArguments());
}
returnmDefaultFactory; }}Copy the code
Androidx Activity and the realization of the fragments of the same, SavedStateViewModelFactory is created and the Application, the current page of the incoming parameters, passed to the constructor, Let’s take a look at SavedStateViewModelFactory.
SavedStateViewModelFactory
SavedStateViewModelFactory class
public final class SavedStateViewModelFactory extends ViewModelProvider.KeyedFactory {
private final Application mApplication;
private final ViewModelProvider.Factory mFactory;
private final Bundle mDefaultArgs;
private final Lifecycle mLifecycle;
private final SavedStateRegistry mSavedStateRegistry;
// constructor, no default arguments passed
public SavedStateViewModelFactory(@Nullable Application application,
@NonNull SavedStateRegistryOwner owner) {
this(application, owner, null);
}
// the constructor passes the default arguments
@SuppressLint("LambdaLast")
public SavedStateViewModelFactory(@Nullable Application application,
@NonNull SavedStateRegistryOwner owner,
@Nullable Bundle defaultArgs) { mSavedStateRegistry = owner.getSavedStateRegistry(); mLifecycle = owner.getLifecycle(); mDefaultArgs = defaultArgs; mApplication = application; mFactory = application ! =null
? ViewModelProvider.AndroidViewModelFactory.getInstance(application)
: ViewModelProvider.NewInstanceFactory.getInstance();
}
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
// AndroidViewModel subclass
boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
Constructor<T> constructor;
if(isAndroidViewModel && mApplication ! =null) {
// Is a subclass of AndroidViewModel that gets the signature constructor (Application, SavedStateHandle)
constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
} else {
// Not a subclass of AndroidViewModel, get (SavedStateHandle) signature constructor
constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
}
if (constructor == null) {
// If the SavedStateHandle constructor is not available, use mFactory instead.
return mFactory.create(modelClass);
}
// SavedStateHandle is required below
SavedStateHandleController controller = SavedStateHandleController.create(
mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
try {
T viewmodel;
if(isAndroidViewModel && mApplication ! =null) {
// Reflect the constructor that creates the signature (Application, SavedStateHandle) and pass in SavedStateHandle.
viewmodel = constructor.newInstance(mApplication, controller.getHandle());
} else {
// Reflect the constructor that creates the signature (SavedStateHandle) and pass in SavedStateHandle.
viewmodel = constructor.newInstance(controller.getHandle());
}
viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller);
/ / return the ViewModel
return viewmodel;
} catch (IllegalAccessException e) {
throw new RuntimeException("Failed to access " + modelClass, e);
} catch (InstantiationException e) {
throw new RuntimeException("A " + modelClass + " cannot be instantiated.", e);
} catch (InvocationTargetException e) {
throw new RuntimeException("An exception happened in constructor of "+ modelClass, e.getCause()); }}@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
String canonicalName = modelClass.getCanonicalName();
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
/ / use the name of the class as the key, create ViewModemLastNonConfigurationInstancesl.
return create(canonicalName, modelClass);
}
// (Application, SavedStateHandle) signature
private static finalClass<? >[] ANDROID_VIEWMODEL_SIGNATURE =new Class[]{Application.class,
SavedStateHandle.class};
/ / (SavedStateHandle) signature
private static finalClass<? >[] VIEWMODEL_SIGNATURE =new Class[]{SavedStateHandle.class};
// Find the signature constructor, no null is returned.
@SuppressWarnings("unchecked")
private static <T> Constructor<T> findMatchingConstructor(Class
modelClass, Class
[] signature)
{
for(Constructor<? > constructor : modelClass.getConstructors()) { Class<? >[] parameterTypes = constructor.getParameterTypes();if (Arrays.equals(signature, parameterTypes)) {
return(Constructor<T>) constructor; }}return null;
}
/ * * *@hide* /
@Override
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public void onRequery(@NonNull ViewModel viewModel) { attachHandleIfNeeded(viewModel, mSavedStateRegistry, mLifecycle); }}Copy the code
Androidx creates a default factory for activities and fragments:
androidx
theActivity
andFragment
createSavedStateViewModelFactory
When, are passed inApplication
So its factorymFactory
forAndroidViewModelFactory
.create(String,Class<*>)
Method, ifViewModel
It doesn’t work in the constructorSavedStateHandle
, then directly use the factorymFactory
(forAndroidViewModelFactory
).
Description:
- use
SavedStateViewModelFactory
Create if thisViewModel
It doesn’t work in the constructorSavedStateHandle
Is directly usedAndroidViewModelFactory
Create; If used, reflection is created(Application, SavedStateHandle)
or(SavedStateHandle)
Signature constructor.
- Can be handled as follows
ViewModel
:
class MyViewModel : ViewModel()
class MyViewModel(application: Application) : AndroidViewModel(application)
class MyViewModel(val handle: SavedStateHandle) : ViewModel()
class MyViewModel(application: Application, val handle: SavedStateHandle) : AndroidViewModel(application)
- Due to the
SavedStateHandle
Is passed to the current pageParameter passed in, so throughSavedStateHandle
You can also get the current pageParameter passed in.- use
SavedStateHandle
Relevant, will be inJetpact- Save stateTo explain in detail.
Having said the creation of the ViewModelProvider object, let’s look at how its get() method gets the ViewModel.
ViewModelProvider. The get method
ViewModelProvider – > the get method
@MainThread
public open operator fun <T : ViewModel> get(modelClass: Class<T>): T {
// Get the class name
valcanonicalName = modelClass.canonicalName ? :throw IllegalArgumentException("Local and anonymous classes can not be ViewModels")
// Use the default name + class name as key to get the ViewModel.
return get("$DEFAULT_KEY:$canonicalName", modelClass)
}
@Suppress("UNCHECKED_CAST")
@MainThread
public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
// Get the ViewModel from the ViewModelStore
var viewModel = store[key]
if (modelClass.isInstance(viewModel)) {
// viewModel is not empty and is the target class, which returns directly.
(factory as? OnRequeryFactory)? .onRequery(viewModel)return viewModel as T
} else {
@Suppress("ControlFlowWithEmptyBody")
if(viewModel ! =null) {
// TODO: log a warning.}}// If no ViewModel is found, create it directly and store it in ViewModelStore.
viewModel = if (factory is KeyedFactory) {
// Is a subclass of KeyedFactory that calls create(key, modelClass) directly.
factory.create(key, modelClass)
} else {
factory.create(modelClass)
}
// Store it in ViewModelStore
store.put(key, viewModel)
return viewModel
}
Copy the code
Viewmodelprovider.get code flow:
get(Class<*>)
Method, usingDefault name + class nameAs akey
, the callget(String, Class<*>)
Method, obtainViewModel
.get(String, Class<*>)
Method, first fromViewModelStore
To deriveViewModel
If theThere are and are target classes, returns directly, otherwise usesFactory
Create it directly and save it toViewModelStore
To be obtained later.
conclusion
Take the Activity on AndroidX to get the ViewModel constructor without arguments as an example to explain the code flow.
Declare the ViewModel
class MyViewModel : ViewModel() {
override fun onCleared(a) {
super.onCleared()
}
}
Copy the code
Access to the ViewModel
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?). {
/ / get the ViewModel
val model = ViewModelProvider(this).get(MyViewModel::class.java)
}
}
Copy the code
Sample code flow:
- create
ViewModelProvider
The incoming isComponentActivity
, it’sViewModelStore
forComponentActivity
To provide theViewModelStore
, it’sFactory
forComponentActivity
The default factory providedSavedStateViewModelFactory
.get()
Method, first fromViewModelStore
To deriveViewModel
If theThere are and are target classes, returns directly, otherwise usesFactory
(SavedStateViewModelFactory
) directly create and save toViewModelStore
To be obtained later.SavedStateViewModelFactory
thecreate()
Method is called directlyAndroidViewModelFactory
thecreate()
Methods. (Because of the acquisitionMyViewModel
Don’t useSavedStateHandle
, so it calls directlymFactory
Creation. And because of creatingSavedStateViewModelFactory
When introduced into theApplication
, somFactory
forAndroidViewModelFactory
)AndroidViewModelFactory
thecreate()
Method will be used directlyreflectioncreateNo argumentsConstructor. (Because of the acquisitionMyViewModel
No inheritanceAndroidViewModel
, so it goes to the parent classNewInstanceFactory
Logical creation of
ViewModel lifecycle
Why the ViewModel life cycle is longer than the Activity and Fragment life cycle, how it stays the same, and how it is removed, let’s examine them separately.
How does the ViewModel stay the same?
Activities and fragments are destroyed and recreated in the event of a configuration change (such as a screen rotation), but the reacquired ViewModel instance remains the same. In reverse analysis, to keep the ViewModel instance unchanged, you need to keep the ViewModelStore unchanged. Let’s take a look at the getViewModelStore() methods of the Activity and Fragment on androidx.
Activity
ComponentActivity – > getViewModelStore method
@NonNull
@Override
public ViewModelStore getViewModelStore(a) {
if (getApplication() == null) {
// The ViewModel cannot be obtained before the onCreate call
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
/ / make sure ViewModelStore
ensureViewModelStore();
/ / return ViewModelStore
return mViewModelStore;
}
@SuppressWarnings("WeakerAccess") /* synthetic access */
void ensureViewModelStore(a) {
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if(nc ! =null) {
/ / to recover from NonConfigurationInstances ViewModelStore
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
// if mViewModelStore is empty, it will be created.
mViewModelStore = newViewModelStore(); }}}Copy the code
Get ViewModelStore, we first obtained from the NonConfigurationInstances, its internal contains a ViewModelStore member variables, . Let’s analyse NonConfigurationInstances viewModelStore how the assignment, and then to analyze how to get to it.
Description:
- why
ComponentActivity
themViewModelStore
Properties,Before the configuration changeStore value while inAfter configuration changesIs empty?
- because
Activity
inAfter configuration changes, recreatedActivity
.Activity
Object is new, so it’smViewModelStore
Property is the initial state: empty.
ComponentActivity. NonConfigurationInstances class
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
}
Copy the code
By looking for reference, NonConfigurationInstances viewModelStore is in ComponentActivity onRetainNonConfigurationInstance () method to complete the assignment.
ComponentActivity – > onRetainNonConfigurationInstance method
public final Object onRetainNonConfigurationInstance(a) {
// Maintain backward compatibility.
Object custom = onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
/ / viewModelStore is empty, then this time did not call getViewModelStore (), by getLastNonConfigurationInstance () from before reconstruction.
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if(nc ! =null) { viewModelStore = nc.viewModelStore; }}if (viewModelStore == null && custom == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
// Record the current viewModelStore to complete the assignment operation.
nci.viewModelStore = viewModelStore;
return nci;
}
Copy the code
This method, create ComponentActivity NonConfigurationInstances object, record the current viewModelStore, and returns the object.
Description:
- Overrides the parent class
Activity
theonRetainNonConfigurationInstance()
Method to make it createdComponentActivity.NonConfigurationInstances
In object,After configuration changesNot affected.ComponentActivity.NonConfigurationInstances.viewModelStore
Property, saved inBefore the configuration changeMaintenance of theViewModelStore
.
By looking for references, ComponentActivity onRetainNonConfigurationInstance () method is the Activity of retainNonConfigurationInstances invoke () method.
The Activity – > retainNonConfigurationInstances method
NonConfigurationInstances retainNonConfigurationInstances(a) {
// Get the data to save for the current activity
Object activity = onRetainNonConfigurationInstance();
HashMap<String, Object> children = onRetainNonConfigurationChildInstances();
FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();
// We're already stopped but we've been asked to retain.
// Our fragments are taken care of but we need to mark the loaders for retention.
// In order to do this correctly we need to restart the loaders first before
// handing them off to the next activity.
mFragments.doLoaderStart();
mFragments.doLoaderStop(true);
ArrayMap<String, LoaderManager> loaders = mFragments.retainLoaderNonConfig();
if (activity == null && children == null && fragments == null && loaders == null
&& mVoiceInteractor == null) {
return null;
NonConfigurationInstances nci = new NonConfigurationInstances();
// Record the current activity data to complete the assignment.
nci.activity = activity;
nci.children = children;
nci.fragments = fragments;
nci.loaders = loaders;
if(mVoiceInteractor ! =null) {
mVoiceInteractor.retainInstance();
nci.voiceInteractor = mVoiceInteractor;
}
return nci;
}
Copy the code
This method, create Activity. NonConfigurationInstances object, record its Activity to save the data (i.e. ComponentActivity. NonConfigurationInstances object), and returns the object.
Description:
Activity
theretainNonConfigurationInstances()
Method to make it createdActivity.NonConfigurationInstances
In object,After configuration changesNot affected.Activity.NonConfigurationInstances.activity
Property, savedComponentActivity.NonConfigurationInstances
Object.
Through the global search, the Activity. RetainNonConfigurationInstances () method is in ActivityThread performDestroyActivity invoke () method.
ActivityThread – > performDestroyActivity method
void performDestroyActivity(ActivityClientRecord r, boolean finishing,
int configChanges, boolean getNonConfigInstance, String reason) {...if (getNonConfigInstance) {
try {
/ / the Activity was obtained from the Activity of ActivityClientRecord. NonConfigurationInstances object,
/ / and then save it lastNonConfigurationInstances, complete the save operation.
r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances();
} catch (Exception e) {
if(! mInstrumentation.onException(r.activity, e)) {throw new RuntimeException("Unable to retain activity "
+ r.intent.getComponent().toShortString() + ":"+ e.toString(), e); }}}...// Call back the Activity's onDestroy methodmInstrumentation.callActivityOnDestroy(r.activity); . }Copy the code
When the Activity is destroyed, Will first will not change as a result of configuration changes data (i.e. the Activity. NonConfigurationInstances) saved to ActivityClientRecord lastNonConfigurationInstances attributes.
Description:
ActivityThread
: it managementThe applicationIn the process ofThe main threadExecution, scheduling, and execution ofactivity
, broadcasting andactivity manager
Additional operations requested.ActivityClientRecord
:Activity
Client record, for realActivity
The bookkeeping of instances.ActivityClientRecord.lastNonConfigurationInstances.activity.viewModelStore
Property, saved inBefore the configuration changeMaintenance of theViewModelStore
.
Next, let’s take a look at is if you get to keep the maintenance of ViewModelStore before configuration changes, let’s take a look at the Activity. The getLastNonConfigurationInstance () method.
The Activity – > getLastNonConfigurationInstance method
@Nullable
public Object getLastNonConfigurationInstance(a) {
returnmLastNonConfigurationInstances ! =null
? mLastNonConfigurationInstances.activity : null;
}
Copy the code
MLastNonConfigurationInstances for Activity. NonConfigurationInstances, getLastNonConfigurationInstance () results back its Activity attribute, Namely ComponentActivity NonConfigurationInstances object.
Let’s see, where is mLastNonConfigurationInstances for assignment. By looking for mLastNonConfigurationInstances is the Activity of the attach () in the assignment.
The Activity – > attach method
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,
IBinder shareableActivityToken) {...// Complete the assignmentmLastNonConfigurationInstances = lastNonConfigurationInstances; . }Copy the code
Through the global search, the Activity. RetainNonConfigurationInstances () method is in ActivityThread performDestroyActivity invoke () method.
ActivityThread – > performLaunchActivity method
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {.../ / call the attach, the incoming ActivityClientRecord lastNonConfigurationInstances.
activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor, window, r.configCallback, r.assistToken, r.shareableActivityToken); .return activity;
}
Copy the code
When the Activity starts, its attach() method is called, The incoming ActivityClientRecord. LastNonConfigurationInstances preservation Activity. NonConfigurationInstances object.
Description:
- why
ActivityThread
theperformLaunchActivity()
,performDestroyActivity()
Methods the insideActivityClientRecord
Is it the same?
- because
ActivityClientRecord
Stored in theActivityThread.mActivities
Property, which isActivityClientRecord
theMap
The collection,ActivityClientRecord
instartActivityNow()
Method is created and calledperformLaunchActivity()
Method within which the createdActivityClientRecord
Object, so it can be accessed fromMap
To retrieve the previously savedActivityClientRecord
, soperformLaunchActivity()
,performDestroyActivity()
Methods the insideActivityClientRecord
It’s the same.
Code flow:
- in
ActivityThread.performDestroyActivity()
Method,ActivityClientRecord.lastNonConfigurationInstances
Save theActivity.retainNonConfigurationInstances()
Method returnActivity.NonConfigurationInstances
Object.- One of the
Activity.NonConfigurationInstances.activity
Property, savedComponentActivity.onRetainNonConfigurationInstance()
Method returnComponentActivity.NonConfigurationInstances
Object.- One of the
ComponentActivity.NonConfigurationInstances.viewModelStore
Property, saved inBefore the configuration changeMaintenance of theViewModelStore
.- in
ActivityThread.performLaunchActivity()
Method, callActivity.attach()
The method passed in is saved inActivityClientRecord.lastNonConfigurationInstances
theActivity.NonConfigurationInstances
Object.Activity.attach()
Method that saves the incomingActivity.NonConfigurationInstances
Object.- By calling the
Activity.getLastNonConfigurationInstance()
Method, can getActivity.NonConfigurationInstances.activity
Attribute savedComponentActivity.NonConfigurationInstances
Object.- Finally get
ComponentActivity.NonConfigurationInstances.viewModelStore
The value of the property is immediately availableComponentActivity
theViewModelStore
Object.
Conclusion:
- in
Activity
When it was destroyed,ActivityClientRecord.lastNonConfigurationInstances.activity.viewModelStore
Property, saved inBefore the configuration changeMaintenance of theViewModelStore
.- in
Activity
When it starts up,ActivityClientRecord.lastNonConfigurationInstances
The value of theActivity.attach()
Was deposited inActivity
, so the follow-up can also be obtained inBefore the configuration changeMaintenance of theViewModelStore
, soBefore and after configuration ChangeTo get toViewModelStore
,ViewModel
Examples of the same.
Fragment
@NonNull
@Override
public ViewModelStore getViewModelStore(a) {
if (mFragmentManager == null) {
Detached ViewModels cannot be accessed from the detached Fragment
throw new IllegalStateException("Can't access ViewModels from detached fragment");
}
if (getMinimumMaxLifecycleState() == Lifecycle.State.INITIALIZED.ordinal()) {
throw new IllegalStateException("Calling getViewModelStore() before a Fragment "
+ "reaches onCreate() when using setMaxLifecycle(INITIALIZED) is not "
+ "supported");
}
return mFragmentManager.getViewModelStore(this);
}
Copy the code
MFragmentManager is FragmentManager, and let’s look at its getViewModelStore() method.
FragmentManager –> getViewModelStore method
@NonNull
ViewModelStore getViewModelStore(@NonNull Fragment f) {
return mNonConfig.getViewModelStore(f);
}
Copy the code
MNonConfig is FragmentManagerViewModel. Let’s first look at how it was created and then look at its getViewModelStore() method.
By looking for, found the FragmentManager. AttachController create () method.
FragmentManager –> attachController method
@SuppressWarnings("deprecation")
@SuppressLint("SyntheticAccessor")
void attachController(@NonNullFragmentHostCallback<? > host,@NonNull FragmentContainer container, @Nullable final Fragment parent) {...// Get the FragmentManagerViewModel
if(parent ! =null) {
// If parent is not null, call getChildNonConfig of parent FragmentManager.
mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
} else if (host instanceof ViewModelStoreOwner) {
// Get the ViewModelStore from host and then use FragmentManagerViewModel.
ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
} else {
mNonConfig = new FragmentManagerViewModel(false); }... }Copy the code
By looking up, I found attachController method will call, when fragments of the attach one host for FragmentActivity inner class FragmentActivity. HostCallbacks, It implements the ViewModelStoreOwner interface.
Create mNonConfig. If there is no parent Fragment, getViewModelStore from host by calling getViewModelStore(). Then call FragmentManagerViewModel. GetInstance (viewModelStore) to obtain FragmentManagerViewModel.
Generally because there is no father Fragment, second if most go, so let’s analyze it, let’s take a look at FragmentActivity. The HostCallbacks getViewModelStore () method, Then look at the FragmentManagerViewModel’s getInstance() method.
FragmentActivity. HostCallbacks – > getViewModelStore method
class HostCallbacks extends FragmentHostCallback<FragmentActivity> implements
ViewModelStoreOwner.OnBackPressedDispatcherOwner.ActivityResultRegistryOwner.SavedStateRegistryOwner.FragmentOnAttachListener {...@NonNull
@Override
public ViewModelStore getViewModelStore(a) {
return FragmentActivity.this.getViewModelStore(); }... }Copy the code
FragmentActivity. HostCallbacks getViewModelStore () method, direct call the FragmentActivity getViewModelStore () method, That is, the getViewModelStore() method of its parent ComponentActivity is called.
So FragmentManager. AttachController () method, through the host also can get ComponentActivity ViewModelStore.
Next, let’s look at the getInstance() method of FragmentManagerViewModel.
FragmentManagerViewModel –> getInstance method
final class FragmentManagerViewModel extends ViewModel {
private static final String TAG = FragmentManager.TAG;
private static final ViewModelProvider.Factory FACTORY = new ViewModelProvider.Factory() {
@NonNull
@Override
@SuppressWarnings("unchecked")
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
FragmentManagerViewModel viewModel = new FragmentManagerViewModel(true);
return(T) viewModel; }};@NonNull
static FragmentManagerViewModel getInstance(ViewModelStore viewModelStore) {
ViewModelProvider viewModelProvider = new ViewModelProvider(viewModelStore,
FACTORY);
returnviewModelProvider.get(FragmentManagerViewModel.class); }}Copy the code
FragmentManagerViewModel is a ViewModel, The getInstance(ViewModelStore) method will first get from the ViewModelStore that’s passed in, If not, use FACTORY to create the FragmentManagerViewModel.
Description:
- The incoming
ViewModelStore
forComponentActivity
theViewModelStore
At firstViewModelStore
Inside there is noFragmentManagerViewModel
, so createFragmentManagerViewModel
And in theComponentActivity
theViewModelStore
In the.- Due to the
ComponentActivity
theViewModelStore
After configuration changesThe instance doesn’t change, soFragmentManagerViewModel.getInstance()
Methods can also be derived fromComponentActivity
theViewModelStore
Get to theBefore configuration ChangeThe depositFragmentManagerViewModel
The instance.
Having said the creation of FragmentManagerViewModel, let’s look at its getViewModelStore() method.
FragmentManagerViewModel –> getViewModelStore method
@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
GetViewModelStore (Fragment) method, obtain the specified Fragment ViewModelStore, if not, create and save to mViewModelStores. MViewModelStores is a Map collection of ViewModelStores.
Description:
- why
FragmentManagerViewModel.getViewModelStore(Fragment)
Method to pass inFragment
In order to obtainViewModelStore
?
- because
FragmentManagerViewModel
, saved toComponentActivity
theViewModelStore
In, so eachFragment
To get toFragmentManagerViewModel
Instances of the same, so we need to pass inFragment
The instance distinction is acquisitionViewModelStore
A collection ofOf which.
- why
Fragment
inBefore and after configuration ChangeTo get toViewModelStore
,ViewModel
Examples of the same?
- because
ComponentActivity
inBefore and after configuration ChangeTo get toViewModelStore
,ViewModel
Examples of the sameSo there isComponentActivity
theViewModelStore
In theFragmentManagerViewModel
Examples of the sameSo there ismViewModelStores
Each of theFragment
theViewModelStore
Examples of the same, soViewModel
Examples of the same.
Code flow:
Fragment
theattach
When, to obtainComponentActivity
theViewModelStore
To createFragmentManagerViewModel
And in theComponentActivity
theViewModelStore
In the.FragmentManagerViewModel.getViewModelStore(Fragment)
By means ofFragment
frommViewModelStores
To obtain the correspondingViewModelStore
If no, create a file and save the file tomViewModelStores
In the.
How is the ViewModel cleared?
To analyze how the ViewModel is cleared, you need to analyze how the ViewModelStore is cleared.
Activity
A reference lookup shows that the ViewModelStore cleanup operation is called in the Constructor for ComponentActivity.
ComponentActivity class
public ComponentActivity(a) {
Lifecycle lifecycle = getLifecycle();
//noinspection ConstantConditions
if (lifecycle == null) {
throw new IllegalStateException("getLifecycle() returned null in ComponentActivity's "
+ "constructor. Please make sure you are lazily constructing your Lifecycle "
+ "in the first call to getLifecycle() rather than relying on field "
+ "initialization."); }... getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
// Clear out the available context
mContextAwareHelper.clearAvailableContext();
// And clear the ViewModelStore
if(! isChangingConfigurations()) {// Clear all viewModels instead of configuration changes.getViewModelStore().clear(); }}}}); . }Copy the code
Lifecycle is used to observe the state of the current Lifecycle, and if the event is ON_DESTROY and not a configuration change, empty all viewmodels.
Description:
Activity
theViewModel
How was it removed?
- use
Lifecycle
Observe the status of the current lifecycle, if the event isON_DESTROY
andNot a configuration change, empty allViewModel
.
Fragment
By reference, we found that in FragmentManagerViewModel clearNonConfigStateInternal method calls the ViewModelStore removal operations.
FragmentManagerViewModel – > clearNonConfigStateInternal method
void clearNonConfigState(@NonNull Fragment f) {
if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
Log.d(TAG, "Clearing non-config state for " + f);
}
clearNonConfigStateInternal(f.mWho);
}
void clearNonConfigState(@NonNull String who) {
if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
Log.d(TAG, "Clearing non-config state for saved state of Fragment " + who);
}
clearNonConfigStateInternal(who);
}
private void clearNonConfigStateInternal(@NonNull String who) {
// Clear and remove the Fragment's child non config state
FragmentManagerViewModel childNonConfig = mChildNonConfigs.get(who);
if(childNonConfig ! =null) {
childNonConfig.onCleared();
mChildNonConfigs.remove(who);
}
// Clear and remove the Fragment's ViewModelStore
// Obtain the corresponding Fragment ViewModelStore
ViewModelStore viewModelStore = mViewModelStores.get(who);
if(viewModelStore ! =null) {
// Clear all viewModels.viewModelStore.clear(); mViewModelStores.remove(who); }}Copy the code
ClearNonConfigStateInternal (String) method, can get to the corresponding ViewModelStore fragments, and then call the clear () method to remove all the ViewModel.
Through the reference, we found that in clearNonConfigStateInternal (String) method is clearNonConfigState (fragments), clearNonConfigState (String) method calls, Then it is two and several calls, and finally through the Debug found FragmentStateManager. Destroy () method, performs a clearNonConfigState (fragments) method.
FragmentStateManager –> destroy method
void destroy(a) {...if(shouldDestroy) { FragmentHostCallback<? > host = mFragment.mHost;boolean shouldClear;
if (host instanceof ViewModelStoreOwner) {
shouldClear = mFragmentStore.getNonConfig().isCleared();
} else if (host.getContext() instanceofActivity) { Activity activity = (Activity) host.getContext(); shouldClear = ! activity.isChangingConfigurations(); }else {
shouldClear = true;
}
if((beingRemoved && ! mFragment.mBeingSaved) || shouldClear) {// Run clearNonConfigState(Fragment) of FragmentManagerViewModel to clear the state that will not change due to configuration changes.mFragmentStore.getNonConfig().clearNonConfigState(mFragment); }... }... }Copy the code
Host for FragmentActivity HostCallbacks, it implements the ViewModelStoreOwner interface, so will walk first the if. Whenever shouldClear is true, the clearNonConfigState(Fragment) method of FragmentManagerViewModel is executed, What is the return value of the isCleared() method of the FragmentManagerViewModel?
FragmentManagerViewModel –> isCleared method
final class FragmentManagerViewModel extends ViewModel {
@Override
protected void onCleared(a) {
if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
Log.d(TAG, "onCleared called for " + this);
}
// The tag has been cleared
mHasBeenCleared = true;
}
boolean isCleared(a) {
returnmHasBeenCleared; }}Copy the code
FragmentManagerViewModel is a ViewModel that’s added to the ViewModelStore for ComponentActivity, The onCleared() method of ViewModel is called when the ViewModelStore for ComponentActivity is cleared (the event is ON_DESTROY and not a configuration change), then mHasBeenCleared is true, The isCleared() method returns true.
Because isCleared () method returns true, so FragmentStateManager. Destroy () method is executed within the FragmentManagerViewModel clearNonConfigState (fragments) method, The Fragment’s ViewModelStore is retrieved and its clear() method is called to clear all viewModels.
Description:
Fragment
theViewModel
How was it removed?
FragmentManagerViewModel
Is aViewModel
, has been added toComponentActivity
theViewModelStore
When theComponentActivity
theViewModelStore
When cleared (the event isON_DESTROY
andNot a configuration change), will callViewModel
theonCleared()
Methods,mHasBeenCleared
fortrue
, i.e.,isCleared()
Method returnstrue
, soFragmentStateManager.destroy()
Method is executedFragmentManagerViewModel
theclearNonConfigState(Fragment)
Method, and you get the correspondingFragment
theViewModelStore
And then call itclear()
methodsRemove allViewModel
.
conclusion
That’s the full jetpack-ViewModel source code! Jetpack’s other source code series will be published later, please stay tuned. If you have any questions, see you in the comments!
Finally, I would like to recommend my website, devbolg.cn, the developer’s technical blog, which currently contains android related technologies, and will be open to all developers later. Welcome to experience!