Viewmode原理
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Viewmode原理相关的知识,希望对你有一定的参考价值。
参考技术A ViewModel旨在以注重生命周期的方式存储和管理界面相关的数据(配合它里面的livedata)。1.1 将Activity的UI处理和数据处理分离,分开管理,解耦且高效。
1.2 ViewModel在屏幕旋转等系统配置更改后被继续保留,避免再次请求数据,浪费网络资源。重建该 Activity时,它接收的ViewModel实例与之前的Activity持有的ViewModel相同。
只有当Activity真正销毁时,框架才会调用getViewModelStore().clear()清除所有的ViewModel。
1.3 避免页面销毁后,数据返回后刷新界面导致crash,例如页面发起请求后,数据还没返回就关闭activity,数据返回后,刷新界面,因view不存在而crash。
1.4 两个Fragment可以使用其Activity的ViewModel来处理通信。
1.5 和onSaveInstanceState()对比,onSaveInstanceState()仅适合可以序列化再反序列化的少量数据,而不适合数量可能较大的数据,如用户列表或位图。
1.6 ViewModelScope,为应用中的每个ViewModel定义了ViewModelScope。如果ViewModel已清除,则在此范围内启动的协程都会自动取消。
ViewModelStoreOwner:是一个接口,ComponentActivity和Fragment实现了这个接口,所以我们在Activity或者Fragment中使用ViewModelProvider传入的this就可以了。
ViewModelStore:ViewModelStore主要是用来存储ViewModel对象的,内部有一个HashMap集合用来存储ViewModel对象。
ComponentActivity持有一个ViewModelStore,可以通过ViewModelStoreOwner中的getViewModelStore()方法获取。(为啥不直接在Activity获取ViewModelStore,再获取ViewModel呢?因为ViewModel要通过ViewModelProvider.Factory创建)
Factory:是一个接口,用来创建ViewModel的
调用get方法后,会调用第二个get方法,传递key(DEFAULT_KEY + ":" + canonicalName)给第二个get方法
首先根据提供的key从ViewModelStore中获取一个ViewModel对象
如果这个获取到的ViewModel对象实例存在,那么就将其返回
如果该ViewModel对象不存在,就通过Factory创建一个ViewModel对象,并将其存储到ViewModelStore中,并将这个新创建的ViewModel对象返回。
这里面存在三个Factory:Factory,KeyedFactory和OnrequeryFactory,keyedFactory和Factory相比就是create方法中多了一个key参数。
ViewModelStore获取到ViewModel时,会判断当前mFactory是否是OnRequeryFactory类型的,是的话会回调onRequery方法
那么OnRequeryFactory回调onRequery有什么用呢?其实ViewModel不仅可以因为配置改变可以恢复Activity数据,也能恢复因为系统资源紧张而回收掉的Activity数据,只不过后者需要依靠SaveStateHandler
总结:ViewModelProvider获取到ViewModel:
1,首先创建ViewModelProvider传入ViewModelStoreOwner和Factory
2,调用ViewModelProvider的get方法,从ViewModelStore中获取ViewModel,有则直接返回,没有就通过反射创建一个,加入ViewModelStore中后,返回。
ViewModel是从ViewModelStore中获取
ViewModelStore是通过ViewModelStoreOwner.getViewModelStore方法获取
ComponentActivity实现了ViewModelStoreOwner接口和HasDefaultViewModelProviderFactory
getViewModelStore()通过两种方法获取到ViewModelStore
1,从NonConfigurationInstances中拿到
2,new一个出来
NonConfigurationInstances,用来包装不受配置更改影响的数据
Activity的NonConfigurationInstances在系统配置改变时保存了ViewModelStore和fragments等
系统配置发生改变时,AMS会调用ActivityThread的handleRelaunchActivity,并且通过当前Activity对应的ActivityRecord构建一个ActivityClientRecord传递过来
Activity的生命周期方法是在ActivityThread中执行的
Activity的retainNonConfigurationInstances 调用了onRetainNonConfigurationInstance
在调用onDestory()方法前,会创建一个NonConfigurationInstances对象,将viewModelStore存储在NonConfigurationInstances,然后将NonConfigurationInstances存储在ActivityClientrecord中。
ActivityThread的handleLaunchActivity最终会调用
performLaunchActivity,最终调用到activity.attach,传入了lastNonConfigurationInstances
这样对于新的Activity来说,获取到的就是之前Activity的NonConfigurationInstance,其中的ViewModelStore也是之前的,ViewModel自然也是之前的。
这样就保证了在系统配置改变时,ViewModel不变了。
总结:
1,系统配置改变时,构建一个NonConfigurationInstance,将ViewModelStore保持到NonConfigurationInstance,再将NonConfigurationInstance保存到ActivityClientrecord的lastNonConfigurationInstances
2,恢复时,将ActivityClientrecord的lastNonConfigurationInstances传递给新的Activity,再通过getViewModelStore()获取时就能从新的Activity的lastNonConfigurationInstances获取ViewModelStore,进而获取之前的ViewModel
(1,系统配置发生改变时,调用handleRelaunchActivity,在这个方法中会先取出activity对应的ActivityClientrecord,然后调用handleDestroyActivity,在这个方法中,会调用ComponentActivity 的onRetainNonConfigurationInstance(),在这个方法中,会构建一个NonConfigurationInstance,将ViewModelStore保持到NonConfigurationInstance,再将NonConfigurationInstance保存到ActivityClientrecord的lastNonConfigurationInstances
2,恢复时,调用到handleLaunchActivity,在这个方法中会调用activity.attach方法,在这个方法中,将ActivityClientrecord的lastNonConfigurationInstances传递给新的Activity的lastNonConfigurationInstances变量。获取ViewModelStore时,会从Activity的lastNonConfigurationInstances去获取(如果没有就新创建一个)如果有的话,自然就是之前的ViewModelStore,里面的ViewModel自然也是之前的。)
Activity正常销毁时,会通过getViewModelStore().clear()清理所有的ViewModel。
1, https://www.jianshu.com/p/e2cc680d5829
2, https://developer.android.com/topic/libraries/architecture/viewmodel?hl=zh-cn
3, https://juejin.cn/post/6873356946896846856
poj 3077Rounders(模拟)
转载请注明出处:http://blog.csdn.net/u012860063?
viewmode=contents
id=3077
Description
For a given number, if greater than ten, round it to the nearest ten, then (if that result is greater than 100) take the result and round it to the nearest hundred, then (if that result is greater than 1000) take that number and round it to the nearest thousand,
and so on ...
Input
Input to this problem will begin with a line containing a single integer n indicating the number of integers to round. The next n lines each contain a single integer x (0 <= x <= 99999999).
Output
For each integer in the input, display the rounded integer on its own line.
Note: Round up on fives.
Note: Round up on fives.
Sample Input
9 15 14 4 5 99 12345678 44444445 1445 446
Sample Output
20 10 4 5 100 10000000 50000000 2000 500
代码一、例如以下:
#include <iostream> #include <cstring> using namespace std; int main() { int t, n, k, count; char s[17]; int i, j; while(cin >>t) { while(t--) { count = 0; int p = 0, l = 0;; memset(s,0,sizeof(s)); cin>>s; int len = strlen(s); if(len == 1) { cout<<s[0]<<endl; continue; } for(i = len-1; i > 0; i--) { if(s[i]-'0'+p > 4) { p = 1; count++; } else { p = 0; count++; } } if(s[0]-'0' + p > 9) { cout<<10; } else { cout<<s[0]-'0'+p; } for(i = 0; i < count; i++) { cout<<'0'; } cout<<endl; } } return 0; }
代码二、例如以下:
#include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> using namespace std; int main() { int t; scanf("%d", &t); while (t--) { int n, count = 0; scanf("%d", &n); double x = n; while (x >= 10) { x /= 10; x = (int)(x + 0.5); count++; } n = (int)x; for (int i = 0; i < count; i++) n *= 10; printf("%d\n", n); } return 0; }
以上是关于Viewmode原理的主要内容,如果未能解决你的问题,请参考以下文章