android-architecture:TO-DO-MVVM-Lifecycles解析
程序员文章站
2022-03-16 12:42:15
...
GitHub:https://github.com/googlesamples/android-architecture/tree/todo-mvvm-live/
架构图
LAUNCHER
TasksActivity
<activity
android:name="com.example.android.architecture.blueprints.todoapp.tasks.TasksActivity"
android:theme="@style/AppTheme.OverlapSystemBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
TasksActivity.java
TasksActivity extends AppCompatActivity
tasks_act.xml
DrawerLayout(
LinearLayout(
AppBarLayout(
Toolbar
)
CoordinatorLayout(
FrameLayout
FloatingActionButton
)
)
NavigationView
)
1. onCreate:
1. 获取TasksViewModel.java
public static TasksViewModel obtainViewModel(FragmentActivity activity) {
// Use a Factory to inject dependencies into the ViewModel
ViewModelFactory factory = ViewModelFactory.getInstance(activity.getApplication());
TasksViewModel viewModel =
ViewModelProviders.of(activity, factory).get(TasksViewModel.class);
return viewModel;
}
2. 添加LiveData感知
// Subscribe to "open task" event fragment -> 过来的数据
mViewModel.getOpenTaskEvent().observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String taskId) {
if (taskId != null) {
openTaskDetails(taskId);
}
}
});
// Subscribe to "new task" event
mViewModel.getNewTaskEvent().observe(this, new Observer<Void>() {
@Override
public void onChanged(@Nullable Void _) {
addNewTask();
}
});
3. 设置要显示的Fragment
private void setupViewFragment() {
//检测该contentFrame是否添加过
TasksFragment tasksFragment =
(TasksFragment) getSupportFragmentManager().findFragmentById(R.id.contentFrame);
if (tasksFragment == null) {
// Create the fragment
tasksFragment = TasksFragment.newInstance();
ActivityUtils.replaceFragmentInActivity(
getSupportFragmentManager(), tasksFragment, R.id.contentFrame);
}
}
4. 其他 ...
TasksFragment
1. tasks_frag.xml
Android Studio 开启
dataBinding {
enabled = true
}
会生成相应的Binding管理对象
->TasksFragBinding.java
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<!--变量-->
<variable
name="viewmodel"
type="com.example.android.architecture.blueprints.todoapp.tasks.TasksViewModel" />
</data>
<com.example.android.architecture.blueprints.todoapp.ScrollChildSwipeRefreshLayout
android:id="@+id/refresh_layout"
...
android:onRefresh="@{viewmodel}"
app:refreshing="@{viewmodel.dataLoading}">
<RelativeLayout
android:id="@+id/tasksContainer"
...>
<LinearLayout
android:id="@+id/tasksLL"
...
android:visibility="@{viewmodel.empty ? View.GONE : View.VISIBLE}">
<TextView
android:id="@+id/filteringLabel"
...
android:text="@{viewmodel.currentFilteringLabel}"
/>
<ListView
android:id="@+id/tasks_list"
...
app:items="@{viewmodel.items}" />
</LinearLayout>
<!-- 中间提示-->
<LinearLayout
android:id="@+id/noTasks"
...
android:visibility="@{viewmodel.empty ? View.VISIBLE : View.GONE}">
<ImageView
android:id="@+id/noTasksIcon"
...
android:src="@{viewmodel.noTaskIconRes}" />
<TextView
android:id="@+id/noTasksMain"
...
android:text="@{viewmodel.noTasksLabel}" />
<TextView
android:id="@+id/noTasksAdd"
...
android:onClick="@{() -> viewmodel.addNewTask()}"
android:visibility="@{viewmodel.tasksAddViewVisible ? View.VISIBLE : View.GONE}" />
</LinearLayout>
</RelativeLayout>
</com.example.android.architecture.blueprints.todoapp.ScrollChildSwipeRefreshLayout>
</layout>
2. TasksFragment.java
public class TasksFragment extends Fragment {}
1. onCreateView:
// 绑定 View 与 ViewModel
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mTasksFragBinding = TasksFragBinding.inflate(inflater, container, false);
mTasksViewModel = TasksActivity.obtainViewModel(getActivity());
// 向View 设置 ViewModel
mTasksFragBinding.setViewmodel(mTasksViewModel);
...
//从 TasksFragBinding.inflate 中获取 layout
return mTasksFragBinding.getRoot();
}
2. onActivityCreated:
// 添加LiveData感知
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setupSnackbar();
setupFab();
setupListAdapter();
setupRefreshLayout();
}
private void setupSnackbar() {
// 设置 Snackbar 的感知,当数据改变时会显示 snackbar
mTasksViewModel.getSnackbarMessage().observe(this, new SnackbarMessage.SnackbarObserver() {
@Override
public void onNewMessage(@StringRes int snackbarMessageResourceId) {
SnackbarUtils.showSnackbar(getView(), getString(snackbarMessageResourceId));
}
});
}
private void setupFab() {
FloatingActionButton fab =
(FloatingActionButton) getActivity().findViewById(R.id.fab_add_task);
fab.setImageResource(R.drawable.ic_add);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 触发事件
mTasksViewModel.addNewTask();
/*
public void addNewTask() {
mNewTaskEvent.call();
}
*/
}
});
}
// 绑定 ListView
private void setupListAdapter() {
// 获取 android:id="@+id/tasks_list"
ListView listView = mTasksFragBinding.tasksList;
mListAdapter = new TasksAdapter(
new ArrayList<Task>(0),
mTasksViewModel
);
listView.setAdapter(mListAdapter);
}
// 绑定 SwipeRefreshLayout
private void setupRefreshLayout() {
//android:id="@+id/tasks_list"
ListView listView = mTasksFragBinding.tasksList;
//android:id="@+id/refresh_layout"
final ScrollChildSwipeRefreshLayout swipeRefreshLayout = mTasksFragBinding.refreshLayout;
swipeRefreshLayout.setColorSchemeColors(
ContextCompat.getColor(getActivity(), R.color.colorPrimary),
ContextCompat.getColor(getActivity(), R.color.colorAccent),
ContextCompat.getColor(getActivity(), R.color.colorPrimaryDark)
);
// Set the scrolling view in the custom SwipeRefreshLayout.
swipeRefreshLayout.setScrollUpChild(listView);
}
2. onResume:
//加载数据
@Override
public void onResume() {
super.onResume();
mTasksViewModel.start();
}