implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
安装包版本,如果版本太低的话,下面语句会报错
new ViewModelProvider(this).get(MyViewModel.class);
ViewModel可以解决以下问题
Android 框架可以管理界面控制器(如 Activity 和 Fragment)的生命周期。如果系统销毁或重新创建界面控制器,则存储在其中的任何瞬态界面相关数据都会丢失。
界面控制器经常需要进行可能需要一些时间才能返回的异步调用。
诸如 Activity 和 Fragment 之类的界面控制器主要用于显示界面数据、对用户操作做出响应或处理操作系统通信(如权限请求)。如果要求界面控制器也负责从数据库或网络加载数据,那么会使类越发膨胀。
架构组件为界面控制器提供了 [ViewModel
] 辅助程序类,该类负责为界面准备数据。在配置更改期间会自动保留 [ViewModel
]对象,以便它们存储的数据立即可供下一个 Activity 或 Fragment 实例使用。例如,如果您需要在应用中显示用户列表,请确保将获取和保留该用户列表的责任分配给 [ViewModel
],而不是 Activity 或 Fragment,如以下示例代码所示:
public class MyViewModel extends ViewModel {
private MutableLiveData<User> user;
public MutableLiveData<User> getUsers() {
if (user == null) {
user = new MutableLiveData<User>();
}
return user;
}
}
然后,您可以从 Activity 访问该列表,如下所示:
public class MainActivity extends AppCompatActivity {
MyViewModel model;
TextView name, pwd;
Button login;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
name = findViewById(R.id.editTextTextPersonName);
pwd = findViewById(R.id.editTextTextPassword);
login = findViewById(R.id.button);
model = new ViewModelProvider(this).get(MyViewModel.class);
model.getUsers().observe(this, users -> {
//更新UI视图
String username = users.getUsername();
String password = users.getPassword();
Log.d("aaa", username + ":" + password);
});
如果重新创建了该 Activity,它接收的 MyViewModel
实例与第一个 Activity 创建的实例相同。当所有者 Activity 完成时,框架会调用 [ViewModel
] 对象的 [onCleared()
]方法,以便它可以清理资源。
您通常在系统首次调用 Activity 对象的 onCreate()
方法时请求 [ViewModel
]。系统可能会在 Activity 的整个生命周期内多次调用 onCreate()
,如在旋转设备屏幕时。[ViewModel
]存在的时间范围是从您首次请求 [ViewModel
] 直到 Activity 完成并销毁。
Activity 中的两个或更多 Fragment 需要相互通信是一种很常见的现象。想象一下拆分视图 (master-detail
) Fragment 的常见情况,假设您有一个 Fragment,在该 Fragment 中,用户从列表中选择一项,还有另一个 Fragment,用于显示选定项的内容。这种情况不太容易处理,因为这两个 Fragment 都需要定义某种接口描述,并且所有者 Activity 必须将两者绑定在一起。此外,这两个 Fragment 都必须处理另一个 Fragment 尚未创建或不可见的情况。
可以使用 [ViewModel
] 对象解决这一常见的难点。这两个 Fragment 可以使用其 Activity 范围共享 [ViewModel
] 来处理此类通信,如以下示例代码所示:
public class SharedViewModel extends ViewModel {
private final MutableLiveData<Item> selected = new MutableLiveData<Item>();
public void select(Item item) {
selected.setValue(item);
}
public LiveData<Item> getSelected() {
return selected;
}
}
public class MasterFragment extends Fragment {
private SharedViewModel model;
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}
public class DetailFragment extends Fragment {
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
SharedViewModel model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
model.getSelected().observe(getViewLifecycleOwner(), item -> {
// Update the UI.
});
}
}
请注意,这两个 Fragment 都会检索包含它们的 Activity。这样,当这两个 Fragment 各自获取 [ViewModelProvider
] 时,它们会收到相同的 SharedViewModel
实例(其范围限定为该 Activity)。
此方法具有以下优势:
SharedViewModel
约定之外,Fragment 不需要相互了解。如果其中一个 Fragment 消失,另一个 Fragment 将继续照常工作。定义ViewModel
public class ViewModelWithLiveData extends ViewModel {
private MutableLiveData<Integer> LikedNumber;
public MutableLiveData<Integer> getLikedNumber() {
if (LikedNumber == null) {
LikedNumber = new MutableLiveData<>();
LikedNumber.setValue(0);
}
return LikedNumber;
}
public void add(int n) {
LikedNumber.setValue(LikedNumber.getValue() + n);
}
}
在build.gardle添加DataBinding配置
android {
...
dataBinding {
enabled = true
}
...
}
MainActivity进行数据绑定
public class MainActivity extends AppCompatActivity {
ViewModelWithLiveData viewModelWithLiveData;
ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//绑定layout组件
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
viewModelWithLiveData = new ViewModelProvider(this).get(ViewModelWithLiveData.class);
//layout绑定数据
binding.setNumber(viewModelWithLiveData);
binding.setLifecycleOwner(this);
}
}
Layout进行改造
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="number"
type="com.suian.androidtest.ViewModelWithLiveData" />
data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(number.likedNumber)}"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.168" />
<ImageButton
android:id="@+id/imageButton3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="80dp"
android:layout_marginTop="63dp"
android:contentDescription="@string/img1"
android:onClick="@{()->number.add(1)}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:srcCompat="@drawable/ic_baseline_accessibility_24" />
<ImageButton
android:id="@+id/imageButton4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="63dp"
android:layout_marginEnd="62dp"
android:contentDescription="@string/img2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
android:onClick="@{()->number.add(-1)}"
app:srcCompat="@drawable/ic_baseline_directions_run_24" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="52dp"
android:text="@string/button1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.107"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageButton3" />
androidx.constraintlayout.widget.ConstraintLayout>
layout>