• Locale changes and the AndroidViewModel antipattern
  • Jose Alcerreca
  • The Nuggets translation Project
  • Permanent link to this article: github.com/xitu/gold-m…
  • Translator: solerji

TL; DR: Expose the resource ID from the view model to avoid showing obsolete data.

In the ViewModel, if you want to expose resources (strings, drawable files, colors…) You must focus on the ViewModel object and ignore configuration changes, such as locale changes. When the user changes his locale, the activity is re-created, but the ViewModel object is not created.

AndroidViewModel is a subclass of ViewModel that knows the context of your application. However, accessing a context can be dangerous if you are not aware of it or do not respond to its lifecycle. The recommended approach is to avoid dealing with objects that have a lifecycle in ViewModels.

Let’s look at an example in the tracker based on this problem: updating the ViewModel when the system locale changes.

// Don't do that
public class MyViewModel extends AndroidViewModel {
    public final MutableLiveData<String> statusLabel = new MutableLiveData<>();
    
    public SampleViewModel(Application context) {
        super(context); statusLabel.setValue(context.getString(R.string.labelString)); }}Copy the code

The point is that strings are interpreted only once in the constructor. If there are locale changes, the viewmodel is not recreated. This would cause our application to display deprecated data and therefore be only partially localized.

As Sergey pointed out in his comments, the recommended approach is to expose the ID of the resource to load and do so in the view. Because the view (activities, fragments, and so on) is lifecycle aware, it is recreated after configuration changes so that resources are properly reloaded.

// Displays the resource ID
public class MyViewModel extends ViewModel {
    public final MutableLiveData<Int> statusLabel = new MutableLiveData<>();
    
    public SampleViewModel(Application context) {
        super(context); statusLabel.setValue(R.string.labelString); }}Copy the code

Even if you don’t plan to localize your application, it makes testing easier and empties out your ViewModel objects, so there’s no reason not to consider it forward-looking.

We solve this problem in the Java-based Android architecture repository in Java as well as on the Kotlin branch. We also moved resources to the data binding layout.

If you find any mistakes in your translation or other areas that need to be improved, you are welcome to the Nuggets Translation Program to revise and PR your translation, and you can also get the corresponding reward points. The permanent link to this article at the beginning of this article is the MarkDown link to this article on GitHub.


The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, front-end, back-end, blockchain, products, design, artificial intelligence and other fields. If you want to see more high-quality translation, please continue to pay attention to the Translation plan of Digging Gold, the official Weibo, Zhihu column.