Jetpack 是 Android 软件组件的集合,使您可以更轻松地开发出色的 Android 应用。这些组件可帮助您遵循最佳做法、让您摆脱编写样板代码的工作并简化复杂任务,以便您将精力集中放在所需的代码上。
最近有空边学习边把学习笔记做了。巩固知识,输入输出,强化学习,如有不对望指出,感谢。
(以下是对官方代码文档的翻译和自己的部分见解)
如果引用JetPack库
implementation 'android.arch.lifecycle:extensions:1.1.1'
ViewModel是一个负责用于准备和管理Activity或者Fragment的数据的类,它也负责对Application中其他的Activity和Fragment进行数据通信(比如:调用业务逻辑类,Fragment之间的数据同步,Activity和Fragment的数据同步。后面的列子会讲到)
LiveData是一个用于保管数据的类。
启动 Android Studio 3.2 或以上版本,就能使用具有ViewModel的Fragment和Activity。
生成目录结构如下
系统自动生成了MainActivity,MainFragment,MainViewModel。
PS:MainViewModel继承于抽象类ViewModel,ViewModel中有个onCleared的方法,这个方法适用于ViewModel长时间没有被使用,这对于当ViewModel观察一些数据并且你需要清理ViewModel的订阅以防止泄漏很有用。
ViewModel的产生过程如图:
以下是生成源码分析
//MainFragment中将生成如下代码
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mViewModel = ViewModelProviders.of(getActivity()).get(MainViewModel.class);
// TODO: Use the ViewModel
//我在这里创建了个LiveData并
//添加了一个Observer用于观察User数据的变化,
//并为TextView赋值
mViewModel.getUserLiveData().observe(this, new Observer<User>() {
@Override
public void onChanged(@Nullable User user) {
message.setText(user.name);
}
});
}
ViewModel是通过ViewModelProviders.get方法获得的。而get方法是用于返回一个与当前Activity/Fragment绑定的已存在ViewModel或者创建一个新的绑定的ViewModel。那这里是如何判断是否已存在ViewModel或者创建一个新的ViewModel呢?源码如下:
//1.ViewModelProviders.of()方法获得ViewModelProvider对象,
//ViewModelProvider方法调用get如下
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
//2.返回当前类的更具体的名字
String canonicalName = modelClass.getCanonicalName();
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
//3.把这个canonicalName作为key获取
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
//4.通过key获得之前已存在的ViewModel对象
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
//noinspection unchecked
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
//5.如果ViewModel为空则通过ViewModelProvider.Factory创建一个新的ViewModel
//
viewModel = mFactory.create(modelClass);
//6.并把viewModel存入ViewModelStore中.
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
//7.ViewModelProvider.Factory如何创建的ViewModel?
//AndroidViewModelFactory是ViewModelProvider的静态内部类
public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {
//部分代码已省略
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
//noinspection TryWithIdenticalCatches
try {
//8.通过反射机制创建实例/如果失败调用默认构造器创建实例
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);
}
}
return super.create(modelClass);
}
}
//9.ViewModel的存储类ViewModelStore
public class ViewModelStore {
//10.整个Application的ViewModel实例都被存储于Map中。
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();//清除ViewModel中长期不用的引用
}
}
final ViewModel get(String key) {
return mMap.get(key);
}
/**
* Clears internal storage and notifies ViewModels that they are no longer used.
*/
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.onCleared();
}
mMap.clear();
}
}
一个简单的例子。Activity中的一个按钮,点击以后,Fragment内部的文字实现变化。
在JetPack出现之前。我们大概会使用如下方法:Fragment暴露个方法给Activity中调用,EventBus,BoradCastRecevie等。但这都有缺陷,当然还有RxBus.现在有了JetPack,谷歌统一框架后,我们就能优雅的在Fragment和Activity之间共享数据了。
示例代码如下:
MainActivity.class
public class MainActivity extends AppCompatActivity {
private MainViewModel mainViewModel;
private Button send;
int count=1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
mainViewModel = ViewModelProviders.of(this).get(MainViewModel.class);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, MainFragment.newInstance())
.commitNow();
}
send=findViewById(R.id.send);
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
count++;
mainViewModel.post("1001","Test"+count);
}
});
}
}
MainFragment
public class MainFragment extends Fragment {
private MainViewModel mViewModel;
private TextView message;
public static MainFragment newInstance() {return new MainFragment();}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.main_fragment, container, false);
message=view.findViewById(R.id.message);
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mViewModel = ViewModelProviders.of(getActivity()).get(MainViewModel.class);
// TODO: Use the ViewModel
mViewModel.getUserLiveData().observe(this, new Observer<User>() {
@Override
public void onChanged(@Nullable User user) {
message.setText(user.name);
}
});}}
MainViewModel
public class MainViewModel extends ViewModel {
private MutableLiveData<User> userLiveData;
public LiveData<User> getUserLiveData() {
if(userLiveData==null){
userLiveData=new MutableLiveData<>();
}
return userLiveData;
}
public void post(String id, String name){
userLiveData.setValue(new User(id,name));
}
}
代码很优雅,逻辑很清晰。
这里没有直接使用LiveData而是MutableLiveData。JetPack中不允许我们直接操作LiveData而是使用MutableLiveData(可变数据)。
public class MutableLiveData<T> extends LiveData<T> {
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
}
MutableLiveData中postValue和setValue有什么区别呢?
其实源码中的注释描述的很清楚。
postValue是创建一个任务在主线程中用于设置你给的value。
而setValue是直接在主线程执行该方法。
liveData.postValue("a");
liveData.setValue("b");
The value "b" would be set at first and later the main thread would override it with the value "a".
官方给的例子很明显,同时调用后,“a"参数将覆盖"b”。
下次我们仔细来看看LiveData的源码吧。