Activity的内部实例保存-Jetpack ViewModel

概览

ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel 类让数据可在发生屏幕旋转等配置更改后继续留存。

疑问1 ViewModel怎么保留实例
疑问2 ViewModel什么时候执行onCleared清除方法

使用

先创建一个类继承ViewModel,如以下示例代码所示:

public class TempModel extends ViewModel {

    public TempModel() {
        Log.d("TempModel", "create " + getClass().getSimpleName());
    }
    @Override
    protected void onCleared() {
        super.onCleared();
        Log.d("TempModel", "onCleared " + getClass().getSimpleName());
    }

}

然后,您可以从 Activity 访问该对象,如下所示:

public class MainActivity extends AppCompatActivity {
    private TempModel mTempModel;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTempModel = new ViewModelProvider(this).get(TempModel.class);
    }
}

如果重新创建了该 Activity,它接收的 TempModel 实例与第一个 Activity 创建的实例相同。当所有者 Activity 完成时,框架会调用 ViewModel 对象的 onCleared() 方法,以便它可以清理资源。

注意:ViewModel 绝不能引用视图、Lifecycle 或可能存储对 Activity 上下文的引用的任何类。

ViewModel怎么保留实例

ViewModel 对象存在的时间比Activity对象更长, 因为是通过onRetainNonConfigurationInstance的方式保留了实例,activity重启的时候不会销毁,而是待恢复新的对象activity时把ViewModel实例在导入给activity这个新实例。

这里我们主要看看是怎么实现的先看看ViewModelProvider 的构造

    public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
        this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                : NewInstanceFactory.getInstance());
    }

这里会传递两个参数给this,
第一个owner.getViewModelStore()
字面意思是通过owner获取一个ViewModel的商店或者是存储等。
第二个owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance()
字面意思是获取获取提供工厂,默认是HasDefaultViewModelProviderFactory这个类

先看 owner是什么?

public interface ViewModelStoreOwner {
    /**
     * Returns owned {@link ViewModelStore}
     *
     * @return a {@code ViewModelStore}
     */
    @NonNull
    ViewModelStore getViewModelStore();
}

从代码上看他是一个ViewModelStoreOwner的接口,在Activity的调用ViewModelProvider的时构造传的是this。 这说明我们activity 肯定实现了这个ViewModelStoreOwner,那么我们从当前Activity找起

public class MainActivity extends AppCompatActivity {

FragmentActivity

public class AppCompatActivity extends FragmentActivity implements AppCompatCallback,
        TaskStackBuilder.SupportParentable, ActionBarDrawerToggle.DelegateProvider {

ComponentActivity

public class FragmentActivity extends ComponentActivity implements
        ActivityCompat.OnRequestPermissionsResultCallback,
        ActivityCompat.RequestPermissionsRequestCodeValidator {
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        HasDefaultViewModelProviderFactory,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner {

在ComponentActivity类中找到ViewModelStoreOwner接口
那么在这个类中找到他的实现方法getViewModelStore

    @NonNull
    @Override
    public ViewModelStore getViewModelStore() {
        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 = new ViewModelStore();
            }
        }
        return mViewModelStore;
    }

这个代码有点熟悉,当mViewModelStore等于空的时候会通过getLastNonConfigurationInstance这个方法获取nc的实例,在通过nc.viewModelStore; 赋值给mViewModelStore,如果nc为空则重现创建一个ViewModelStore

getLastNonConfigurationInstance这个方法是获取最后一次实例保留,可以里理解activity销毁时保留的实例传递给了当前新的Activity,与之成对的保留方法

    @Override
    @Nullable
    public final Object onRetainNonConfigurationInstance() {
        Object custom = onRetainCustomNonConfigurationInstance();

        ViewModelStore viewModelStore = mViewModelStore;
        if (viewModelStore == null) {
            // No one called getViewModelStore(), so see if there was an existing
            // ViewModelStore from our last NonConfigurationInstance
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                viewModelStore = nc.viewModelStore;
            }
        }

        if (viewModelStore == null && custom == null) {
            return null;
        }

        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.custom = custom;
        nci.viewModelStore = viewModelStore;
        return nci;
    }

onRetainNonConfigurationInstance这个方法是在销毁时保留的实例的方法。
具体可参考Activity的内部实例保存-onRetainNonConfigurationInstance

继续看ViewModelProvider的get方法

    @NonNull
    @MainThread
    public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
        String canonicalName = modelClass.getCanonicalName();
        if (canonicalName == null) {
            throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
        }
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }

下面是get的重载方法

    @NonNull
    @MainThread
    public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        //通过mViewModelStore获取ViewModel实例 
        ViewModel viewModel = mViewModelStore.get(key);

        //第一次viewModel获取为空则不会走这个if里面
        if (modelClass.isInstance(viewModel)) {
            if (mFactory instanceof OnRequeryFactory) {
                ((OnRequeryFactory) mFactory).onRequery(viewModel);
            }
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        //默认都是KeyedFactory这个工厂类,里面就是通过class反射创建一个实例
        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
        } else {
            viewModel = (mFactory).create(modelClass);
        }
        //通过mViewModelStore保存ViewModel实例
        mViewModelStore.put(key, viewModel);
        return (T) viewModel;
    }

ViewModel什么时候执行onCleared清除方法

这里了解完ViewModel为什么生命周期时间大于Activity,在看看他如何监听销毁的。这里就需要看
ComponentActivity的构造函数

    public ComponentActivity() {
        //省略...
        getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    if (!isChangingConfigurations()) {
                        getViewModelStore().clear();
                    }
                }
            }
        });
        //省略...
    }

先看 getViewModelStore().clear();

public class ViewModelStore {
    private final HashMap<String, ViewModel> mMap = new HashMap<>();
    //省略...
    /**
     *  Clears internal storage and notifies ViewModels that they are no longer used.
     */
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}

ViewModelStore里面有个mMap 是包含当前activity所有的ViewModel对象。

在看看ViewModel 的clear

public abstract class ViewModel {
    //省略...
    protected void onCleared() {
    }
    @MainThread
    final void clear() {
        //省略...
        onCleared();
    }
    //省略...
}

最终会调到onCleared ,故也会执行到我们自定义的TempModel类的onCleared方法

public class TempModel extends ViewModel {

    public TempModel() {
        Log.d("TempModel", "create " + getClass().getSimpleName());
    } 
    @Override
    protected void onCleared() {
        super.onCleared();
        Log.d("TempModel", "onCleared " + getClass().getSimpleName());
    } 
}

好,回到ComponentActivity构造里的注册监听, getLifecycle().addObserver
先看看getLifecycle()方法实现

    @NonNull
    @Override
    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }

查看定义,是一个LifecycleRegistry类


    private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);

这里先不展开,后续单独一篇文章来探讨,这里直接给出结论:
LifecycleRegistry 是一个生命周期的注册类,addObserver方法是这个类的注册方法,主用用于监听Activity或者Fragment的生命周期。

        getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                    //这里是判断event 的事件是否是销毁
                if (event == Lifecycle.Event.ON_DESTROY) {
                //在判断是否是配置改动而销毁的
                    if (!isChangingConfigurations()) {
                        getViewModelStore().clear();
                    }
                }
            }
        });
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月夜持剑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值