美文网首页AndroidAndroid技术知识Android开发
谷歌架构组件(一)ViewModel的使用与分析

谷歌架构组件(一)ViewModel的使用与分析

作者: wenson123 | 来源:发表于2018-02-12 16:34 被阅读186次

ViewModel 是google推出的架构组件之一,它被设计用于存储和管理UI相关的数据。

背景:

1方便数据存储

以生命周期的方式存储和管理UI相关数据。当屏幕旋转等改变时,数据能够被恢复。

2生命周期控制

使用fragment时我们都会对它复杂的生命周期处理感到痛苦,稍有不慎报各种null异常。ViewModel,Lifecycle等组件的推出,可以有效的解决生命周期的处理问题,提高app的稳定性。`

3 DataBinding数据驱动UI

从字面意思看ViewModel就是activity fragment的数据抽象模型。我们知道activity fragment是由系统管理,不受app控制,当内存不足时,系统随时都有可能回收杀死app。所以这也是android app开发具有挑战的地方,我们需要在不确定的环境下保证我们的业务流程顺利进行。由于ViewModel设计是和activity fragment的生命周期是解耦的,所以当activity fragmegnt重新create时,如果ViewModel已经创建过,则仍使用原ViewModel。

ViewMode生命周期见下图:


viewmodel-lifecycle.png

如何使用:

1自定义ViewModel

    class UserModel extends ViewModel{  
      String name;  
      String age;  
      
    } 

2 获取ViewModel

public class MyActivity extends AppCompatActivity {  
    public void onCreate(Bundle savedInstanceState) {  
        // Create a ViewModel the first time the system calls an activity's onCreate() method.  

            // Re-created activities receive the same MyViewModel instance created by the first activity.  
      
            UserModel model = ViewModelProviders.of(this).get(UserModel.class);  
            
        }  
    } 

因为ViewModel生命周期感知的,所以我们不需要手动释放,使用起来非常方便。

注意事项:

ViewModel不可以持有activity fragment等view的引用,否则会导致内存泄漏。

读到这里你可能会有如下疑问:

  1. ViewModel 为什么不可以持有activity fragment等View的引用

  2. ViewModel 如果感知activity fragment的生命周期

  3. ViewModel 如何保存数据

接下来我们根据上述疑问,跟踪ViewModel 的相关代码具体分析。

111.png

以ViewModelProviders.of(this).get(UserModel.class); 这行代码作为切入点

@MainThread  
public static ViewModelProvider of(@NonNull Fragment fragment) {  
    FragmentActivity activity = fragment.getActivity();  
    if (activity == null) {  
        throw new IllegalArgumentException(  
                "Can't create ViewModelProvider for detached fragment");  
    }  
    initializeFactoryIfNeeded(activity.getApplication());  
    return new ViewModelProvider(ViewModelStores.of(fragment), sDefaultFactory);  
} 

1 创建默认的工厂方法,实例化新的ViewModels

2 通过传入fragment或者acitity参数,new ViewModelProvider实例并返回。

这里有2个关键的代码点

1 ViewModelStores.of(fragment)

2 return new ViewModelProvider(…)

针对代码点1 ViewModelStores.of(fragment) 查看ViewModelStores源码

    @MainThread  
    public static ViewModelStore of(FragmentActivity activity) {  
        return holderFragmentFor(activity).getViewModelStore();  
    }  

它通过holderFragmentFor函数返回ViewModelStore对象

继续跟踪holderFragmentFor函数,找到HolerFragment 这个关键类

从HolerFragment类的代码中我们找到了ViewModel感知fragment,activity生命周期的原因。

Google在底层默默的create了一个新的HolderFragment 对象,

由HolderFragment负责生命周期感知,当onDestroy()时清理ViewModelStore

持有ViewModelStore对象,setRetainInstance(true) 保证当界面旋转被销毁再重建时保证mViewModelStore 不被销毁。但对于因内存被系统杀死后重新进入,数据不会被恢复。

public class HolderFragment extends Fragment {    
  
      private ViewModelStore mViewModelStore = new ViewModelStore();  
  
      public HolderFragment() {  
        setRetainInstance(true);  
      }  
      
        HolderFragment holderFragmentFor(Fragment parentFragment) {    
                FragmentManager fm = parentFragment.getChildFragmentManager();    
                HolderFragment holder = findHolderFragment(fm);    
                ......
                holder = createHolderFragment(fm);    
                mNotCommittedFragmentHolders.put(parentFragment, holder);    
                return holder;    
            }    
        
    } 

解决了ViewModel如果感知生命周期的问题,我们再分析下ViewModel的数据存储。

我们查看ViewModelStore这个类,发现ViewModel是被存储在一个HashMap内,所以它是保存在app内存中,并没有做持久化处理。

public class ViewModelStore {  
  
    private final HashMap<String, ViewModel> mMap = new HashMap<>();  
  
    ......

} 

针对代码点2 return new ViewModelProvider(…),我们看下ViewModelProvider。

从代码中可知ViewModelProvider是对ViewModelStore 和Factory的封装,当viewModel存着时获取ViewModel,如果不存在则调用工厂方法创建ViewModel。

public class ViewModelProvider {  
    private final Factory mFactory;  
    private final ViewModelStore mViewModelStore;  
  
    public ViewModelProvider(ViewModelStore store, Factory factory) {  
        mFactory = factory;  
        this.mViewModelStore = store;  
    }  
  
      
        @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 {  
                ......  
            }  
      
            viewModel = mFactory.create(modelClass);  
            mViewModelStore.put(key, viewModel);  
            //noinspection unchecked  
            return (T) viewModel;  
        }  
      
    } 

总结:

通过代码的跟踪分析我们解决了3大疑问,发现ViewModel的实现主要依赖于HolderFragment类的实现。

  • 通过添加新的HolderFragment感知生命周期的变化

  • 通过HolderFragment持有ViewModelStore对象

  • ViewModel存储在ViewModelStore的hashmap内存中,不做持久化数据存储,当activity fragment处于后台因内存问题被系统杀死后,重新进入后数据不会被恢复。

  • Fragment和Activity作为key访问获取ViewModel对象

  • ViewModel不能持有activity,fragment等view的引用,避免内存泄漏

参考
https://developer.android.google.cn/topic/libraries/architecture/viewmodel.html
android source code 8.0

相关文章

网友评论

    本文标题:谷歌架构组件(一)ViewModel的使用与分析

    本文链接:https://www.haomeiwen.com/subject/sftdtftx.html