Skip to content

Files

Latest commit

822f1cf · Jan 1, 2022

History

History
176 lines (129 loc) · 8.3 KB

File metadata and controls

176 lines (129 loc) · 8.3 KB

三十四、安卓 Jetpack 实时数据教程

前一章开始了设计一个应用的过程,以符合推荐的 Jetpack 架构指南。这些初始步骤包括选择片段+视图模型项目模板,以及在视图模型实例中实现应用用户界面的数据模型。

本章将通过使用 LiveData 架构组件进一步增强应用设计。一旦本章的项目增加了 LiveData 支持,接下来的章节(从“安卓 Jetpack 数据绑定概述”开始)将利用 Jetpack 数据绑定库从项目中删除更多代码。

34.1 生活数据-回顾

LiveData 之前在标题为“搭载 Jetpack 的现代安卓应用架构”的章节中介绍过。如前所述,LiveData 组件可以用作视图模型中数据值的包装器。一旦包含在 LiveData 实例中,这些变量就可以被应用中的其他对象观察到,通常是用户界面控制器,如活动和片段。这允许用户界面控制器在底层实时数据值改变时接收通知。通过创建观察者类的实例并定义当 LiveData 值改变时调用的 onChange()方法来设置观察者。创建观察者实例后,通过调用 LiveData 对象的 observe()方法将其附加到 LiveData 对象。

LiveData 实例可以使用可变数据类声明为可变的,允许视图模型和用户界面控制器对底层数据值进行更改。

34.2 将实时数据添加到视图模型

启动 AndroidStudio,打开上一章创建的视图模型演示项目,并编辑 MainViewModel.java 文件,该文件当前应如下所示:

package com.ebookfrenzy.viewmodeldemo.ui.main;

import androidx.lifecycle.ViewModel;

public class  MainViewModel extends ViewModel {

    private static final Float usd_to_eu_rate = 0.74F;
    private String dollarText = "";
    private Float result = 0F;

    public void setAmount(String value) {
        this.dollarText = value;
        result = Float.valueOf(dollarText)*usd_to_eu_rate;
    }

    public Float getResult()
    {
        return result;
    }
}

本章中这一阶段的目标是将结果变量包装在一个可变的数据实例中(对象需要可变,以便用户每次请求货币转换时可以更改该值)。首先修改该类,使其现在如下所示,注意在使用 LiveData 时需要导入一个额外的包:

package com.ebookfrenzy.viewmodeldemo.ui.main;

import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

public class  MainViewModel extends ViewModel {

    private static final Float usd_to_eu_rate = 0.74F;
    private String dollarText = "";
    private Float result = 0F;
    private MutableLiveData<Float> result = new MutableLiveData<>();

    public void setAmount(String value) {
        this.dollarText = value;
        result = Float.valueOf(dollarText)*usd_to_eu_rate;
    }

    public Float getResult()
    {
        return result;
    }
}

现在结果变量包含在可变的 LiveData 实例中,setAmount()和 getResult()方法都需要修改。在 setAmount()方法的情况下,不能再使用赋值(=)运算符将值赋给结果变量。相反,必须调用 LiveData setValue()方法,将新值作为参数传递。按照目前的实现方式,getResult()方法被声明为返回一个 Float 值,现在需要进行更改以返回一个可变的 iveData 对象。进行这些剩余的更改会生成以下类文件:

package com.ebookfrenzy.viewmodeldemo.ui.main;

import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

public class  MainViewModel extends ViewModel {

    private static final Float usd_to_eu_rate = 0.74F;
    private String dollarText = "";
    private MutableLiveData<Float> result = new MutableLiveData<>();

    public void setAmount(String value) {
        this.dollarText = value;
        result = Float.valueOf(dollarText)*usd_to_eu_rate;
        result.setValue(Float.valueOf(dollarText)*usd_to_eu_rate);
    }

    public Float getResult()
    public MutableLiveData<Float> getResult()
    {
        return result;
    }
}

34.3 实施 观察者

现在转换结果包含在一个 LiveData 实例中,下一步是在 UI 控制器中配置一个观察器,在本例中是 MainFragment 类。找到 MainFragment.java 类(app-> Java->->【main fragment】,双击它将其加载到编辑器中,并修改 onActivityCreated()方法来创建一个名为 resultObserver 的新 Observer 实例:

package com.ebookfrenzy.viewmodeldemo.ui.main;

import androidx.lifecycle.Observer;
.
.
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
.
.
    dollarText = getView().findViewById(R.id.dollarText);
    resultText = getView().findViewById(R.id.resultText);
    convertButton = getView().findViewById(R.id.convertButton);

    resultText.setText(mViewModel.getResult().toString());

    final Observer<Float> resultObserver = new Observer<Float>() {
        @Override
        public void onChanged(@Nullable final Float result) {
            resultText.setText(result.toString());
        }
    };
.
.
}

resultObserver 实例声明了 onChanged()方法,当调用该方法时,会将当前结果值传递给它,然后将其转换为字符串并显示在结果 TextView 对象上。下一步是将观察者添加到结果 LiveData 对象中,通过调用 ViewModel 对象的 getResult()方法可以获得对该对象的引用。由于更新结果文本视图现在是 onChanged()回调方法的责任,现在可以删除执行此任务的现有代码行:

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    mViewModel = new ViewModelProvider(this).get(MainViewModel.class);

    dollarText = getView().findViewById(R.id.dollarText);
    resultText = getView().findViewById(R.id.resultText);
    convertButton = getView().findViewById(R.id.convertButton);

    resultText.setText(mViewModel.getResult().toString());

    final Observer<Float> resultObserver = new Observer<Float>() {
        @Override
        public void onChanged(@Nullable final Float result) {
            resultText.setText(result.toString());
        }
    };

    mViewModel.getResult().observe(getViewLifecycleOwner(), resultObserver);

    convertButton.setOnClickListener(new View.OnClickListener()
    {
        @Override
        public void onClick(View v) {

            if (!dollarText.getText().toString().equals("")) {
                mViewModel.setAmount(Float.valueOf(
				dollarText.getText().toString()));
                resultText.setText(mViewModel.getResult().toString());
            } else {
                resultText.setText("No Value");
            }
        }
    });
}

编译并运行该应用,在美元字段中输入一个值,单击转换按钮,并验证转换后的欧元金额是否出现在文本视图中。这确认观察器收到结果值已更改的通知,并调用 onChanged()方法来显示最新数据。

请注意,在 onActivityCreated()方法的上述实现中,删除了每次调用该方法时负责显示当前结果值的代码行。这最初是为了确保在片段由于任何原因被重新创建的情况下显示的值不会丢失。因为 LiveData 监控其观察者的生命周期状态,所以不再需要这个步骤。当 LiveData 检测到 UI 控制器被重新创建时,它会自动触发任何关联的观察器并提供最新数据。通过在文本视图对象上显示欧元值时旋转设备并确认该值没有丢失来验证这一点。

在进入下一章之前,关闭项目,复制视图模型演示项目文件夹,并将其保存为视图模型演示 _ 实时数据,以便以后在查看保存视图模型状态时使用。

34.4 总结

本章演示了如何使用安卓 LiveData 组件来确保向用户显示的数据始终与视图模型中存储的数据相匹配。这个相对简单的过程包括将视图模型数据值包装在一个实时数据对象中,并在订阅实时数据值的用户界面控制器中设置一个观察器。每次 LiveData 值发生变化时,都会通知观察者,并调用 onChanged()方法并传递更新后的值。

向项目添加 LiveData 支持在一定程度上简化了项目的设计。通过使用数据绑定库,还可以进行额外的重大改进,其细节将在后面的章节中介绍。然而,在此之前,我们将考虑保存视图模型状态。