Hello, everyone
I’m KunMinX, author of Jetpack MVVM Essentials and Jetpack MVVM Best Practices,
In the past year, we have collected the most frequently mentioned questions by new users when they applied Jetpack MVVM to their projects through maintenance and communication channels.
With the popularity of Jetpack MVVM, high-frequency questions are increasingly being asked during interviews or refactoring,
Considering that these scattered Q&A’s are not easy for novice readers to read, I prepared this article separately, which can be directly viewed from hundreds of readers’ thousands of questions carefully selected from the high-frequency Q&A.
So this article, before and even in the future to provide only such one, please cherish to enjoy.
Directory in
- Subscribe to the TOP 5 frequent Q&A forums
- TOP 1: How to do page communication under Jetpack MVVM?
- TOP 2: What is the situation of LiveData “data flooding” and how to solve it?
- TOP 3: Why isn’t UI logic written in ViewModel?
- TOP 4: Why not LiveDataBus?
- TOP 5: How to restore view state when Navigation replace is returned?
- TOP 5 high-frequency Q&A in the Issue area of Best Practices project
- TOP 1: Shouldn’t pages receive messages when onPause occurs?
- TOP 2: What about the “DataBinding Strict Pattern” in the Best Practices project?
- TOP 3: Bind view state, LiveData and ObservableField.
- TOP 4: LiveData Observe Has Gone Many times. What should I Do?
- TOP 5: Introduce Navigation modifications to Best Practices into your own project, and the result is still replace.
Subscribe to the TOP 5 frequent Q&A forums
TOP 1: How to do page communication under Jetpack MVVM?
Solution: Do it via SharedViewModel.
Follow-up: Why?
Answer: We chose the Application-level ViewModel rather than static singletons or traditional Bus to communicate messages (such as event callbacks, etc.) between pages of the Application because:
1. The ViewModel is encapsulated in the Activity/Fragment base class so that messages can be propagated only between view controllers without contaminating areas outside.
2. At the same time, it can also avoid being obtained by external components, resulting in unexpected push.
See the use of SharedViewModel in the Best Practices project.
TOP 2: What is the situation of LiveData “data flooding” and how to solve it?
Answer: the phenomenon of “data inversion” is the generalization of a certain kind of phenomenon initiated by my whole network, so it is probably impossible to find this kind of description on the Internet.
Data dump refers to the situation in which the current page is notified once by LiveData of SharedViewModel in the scene of page communication (event callback), and the page is returned to the previous page, and the old data is pushed repeatedly when the current page is entered next time.
The current Best Practices project addresses these issues with UnPeekLiveData, available in the latest source code.
The Event wrapper | Non-invasive rewriting | UnPeekLiveData |
---|---|---|
TOP 3: Why isn’t UI logic written in ViewModel?
Answer: Jetpack MVVM is data-driven and separation of concerns,
The separation of concerns is reflected by the principle of least knowledge:
The UI logic is written in the Activity/Fragment view controller,
The business logic is written in the data layer, such as the DataRepository.
As a bridge between the view controller and the data layer, the ViewModel itself should be lightweight enough to serve as a “link” (keeping the overall framework unidirectional dependence).
And, just like any other question, “should the logic be written in the Activity or in the ViewModel?”
To figure that out, we still need to figure out, first of all, what’s the context of this —
It’s in the context of multi-person collaborative software engineering.
👆 👆 👆 to highlight
What does that mean? Which means that once you write your UI logic in your ViewModel, it’s out of your control,
Your colleagues who are not familiar with this development pattern may be driven by the “broken window effect” of fetching context directly from the ViewModel, fetching all sorts of things they shouldn’t, and eventually leaking memory, all of that.
To sum up, the ViewModel’s responsibility boundary is to help activities/fragments host data, which is not suitable for writing logic in the ViewModel.
For more details, see the Jetpack ViewModel that works both ways in Page Development.
TOP 4: Why not LiveDataBus?
Answer: Same reason as above.
We are not using LiveDataBus because we are talking about architectural design in the context of multi-person collaborative, multi-page software engineering. In this context, any trivial hidden dangers can be magnified infinitely.
Bus itself lacks the concept constraint of unique trusted source and it is difficult to trace the event source object, so it should be completely removed from the project in order to avoid the misuse and abuse of new team members.
For details, please refer to LiveData’s little-known background and Unique Mission.
In the meantime, whenever possible, use singletons or global ViewModels to host liveData so that the event source can be found based on the liveData object in memory during debugging. LiveDataBus, which is tagged, is hard to find.
TOP 5: How to restore view state when Navigation replace is returned?
Answer: The FragmentNavigator of Navigation is officially written to start a new Fragment with replace. This can cause problems such as redrawing the page on return. There are two ways to do this. Start a new Fragment with add Hide, or reuse the last instantiated View in onCreateView.
For specific operations and precautions, please refer to the detailed supplement at the end of the article “Analysis of opening Methods and Defects of Jetpack Navigation”, and Flywith24 and I wrote in “My Fragments are obedient, Your Fragment has a Mind of its own.
“Best Practices” project Issue
TOP 1: Shouldn’t pages receive messages when onPause occurs?
Answer: We refute the rumor that there are many erroneous web articles spreading false views such as “page onPause will not receive LiveData notification”, which give readers trouble and delay a lot of time.
Instead, onPause can receive onStart, but not all scenarios can (as of 2020.2, activities can, fragments cannot) —
Only onResume and onPause are in between STARTED and onPause, meaning they are the only two life-cycle nodes that are 100% sure to receive LiveData’s pushes.
See the latest additions at the end of Jetpack Lifecycle for you to see why
TOP 2: What about the “DataBinding Strict Pattern” in the Best Practices project?
Answer: “strict mode” is based on my understanding of the nature of “data driven”, and the whole network initiative of software engineering security “pure data driven” writing method. In other words, by following the “strict mode,” you can ensure 100% consistency of view calls (security equivalent to Jetpack Compose based on functional programming ideas) and avoid the various NULL security situations that can arise in multiple layouts and other contexts.
For more on the nature of “data-driven,” see Jetpack DataBinding from Misunderstood to Delicious! And “all in all” “declarative UI” literacy dry goods “in the full network exclusive in-depth analysis.
TOP 3: Why use LiveData to bind view State in MainActivityViewModel while other state-viewModels use ObservableField?
Solution: ObservaleField has the characteristics of anti-shake, remember this feature, and then choose to use according to the situation.
ObservaleField
is not an ObservaleField for PureMusic, and LiveData is an ObservaleField for LiveData, because ObservaleField is an ObservaleField for LiveData. The second set of ObservaleBoolean is set to true, and the notify view is not refreshed.
Anti-shake can avoid repeated refreshes to reduce unnecessary performance overhead, so choose ObservaleField or LiveData as appropriate.
For more details, see Jetpack DataBinding from Misunderstood to Really Fragrant! At the end of the article and in the comments section.
TOP 4: LiveData Observe Has Gone Many times. What should I Do?
Answer :(note that the situation referred to here is different from “data dump”)
Considering that several friends have privately asked LiveData about “repeated callback”, here is an additional disclaimer:
LiveData is designed to support one-to-many distribution of data from ViewModel, singleton and other unique trusted sources, so its internal observation routine is not “one-to-one” observer mode, but “one-to-many” publish-subscribe mode. The VIABUS architecture, which I designed and opened source in early 2018, follows this pattern, internally maintaining subscribers through Maps.
Therefore, under normal circumstances, for a LiveData instance, the registration is only observed once in the same page, do not register in the RecyclerView Adapter onBindViewHolder and other places, to avoid repeated registration of multiple subscribers. Thus unexpectedly “receiving multiple pushes” after each request.
For more complete tips, see the latest supplement at the end of LiveData’s little-known background and unique Mission.
TOP 5: Introduce Navigation modifications to Best Practices into your own project, and the result is still replace.
Solution: Please remove navigation. Fragment Gradle references introduced in your own project, otherwise they may overwrite those from the Architecture Module. Also, make sure that navigation. Fragment is moved into your project using the full com.androidx package name path as in the original Architecture Module.
Copyright statement
This article is issued under the CC signature – Non-commercial Use – No Deduction 4.0 International Agreement.
Copyright © 2019 – present KunMinX
The introduction, train of thought and conclusion of this paper belong to the author KunMinX. When you reference or quote the introduction, train of thought and conclusion of this paper for second creation or full text reprint, you must indicate the link source, otherwise we reserve the right to pursue responsibility.