Android跨界面共享数据——LiveData应用

业务场景

3个界面中有3个独立控件,需要同步他们的状态,即其中任一控件状态变化,其余两个随之而变。

解决方案

1. 传递值:startActivityForResult() + onActivityResult()

这是最容易想到的方案,实现步骤如下:

  • 在界面A将控件状态封装在Intent
  • 在界面A通过startActivityForResult()跳转到界面B
  • 在界面A返回之前通过setResult()将控件状态返回给界面A
  • 在界面A的onActivityResult()中获取控件状态并更新UI

但该方案有缺点:

  1. 代码可读性较差,特别是当onActivityResult()中还夹杂着其他业务逻辑。
  2. 增加了Activity间的耦合(即Activiy B依赖于Activity A的特殊传值方式,Activity A依赖于Activity B的回传值)。因为界面间是两两耦合的,所以也导致了扩展性较差,如果需求改成“从Activity A直接跳转到Activity B”,需要重新出处理Activity AActivity B的跳转逻辑。
2. 共享值(持久化)

既然通过传递值的方式不够好,那直接“共享值”呢?即将每次状态改变都持久化(存在本地),每次绘制界面都从本地读取状态。

设想界面A中有一个列表,每个表项都包含一个需要状态同步的控件,当服务器返回一批新数据后,需要挨个将数据进行存储,随着列表不断刷新,本地存储的内容就不断增多,为控制本地存储占用的空间,在 App 退出时需清空本地存储。

3. 共享值(LiveData)

既然在 App 退出时需要清空数据,则表明控件状态信息的生命周期和 App 的生命周期同步,而持久化解决的问题是生命周期长于 App 生命周期的情况。于是第三个解决方案就闪亮登场了~~~

LiveData是谷歌在Google I/O 2017发布的Android Architecture Components(Google教你如何写 App 系列)中的一项内容。

对于当前这个case,LiveData充当如下角色:

  • LiveData是一个数据持有者,但不像一般的数据持有者,它可以感知系统组件的生命周期。
  • LiveData可以被观察,但它不像一般的观察者模式(一有数据变动就通知所有观察者)。只有当被观察者处于激活状态时才被通知。

所以基于LiveData的解决方案如下:将控件状态信息保存在LiveData中,三个不同的界面分别观察LiveData

通过观察者模式将方案1中数据传递问题转换为数据共享,三个界面没有丝毫耦合。将LiveData设置为单例,使其和 App 生命周期相一致,也避免了开辟额外的本地存储。

LiveData应用

1. 创建状态信息实体类

将要共享的状态信息封装成实体类,简单起见,demo将状态信息设置为int值,如下:

public class Status {
    private int level;

    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }
}
复制代码
2. 创建LiveData单例

下面的代码只是将状态信息实体类和LiveData关联,并将LiveData定义为单例,方便跨界面使用。

public class StatusLiveData extends MutableLiveData<Status> {
    private StatusLiveData() {
    }

    private static class Holder {
        public static final StatusLiveData INSTANCE = new StatusLiveData();
    }

    public static StatusLiveData getInstance() {
        return Holder.INSTANCE;
    }
}

//MutableLiveData在LiveData基础上暴露两个设值接口
public class MutableLiveData<T> extends LiveData<T> {
    @Override
    public void postValue(T value) {
        super.postValue(value);
    }

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}
复制代码
3. 为LiveData添加观察者

LiveData的观察者通常是带有生命周期概念的组件,比如Activity,Fragment等等。观察者需实现Observer<T>接口,以定义数据变化时做出的响应。

public class ActivityA extends AppCompatActivity implements View.OnClickListener, Observer<Status> {
    private int level;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        StatusLiveData.getInstance().observe(this, this);
    }
    
    ...
    
    @Override
    public void onChanged(@Nullable Status status) {
        /**
         * get status data when it is changed and update UI
         */
        int level = status.getLevel();
        changeArrowStatus(level);
    }
}
复制代码
4. 更新LiveData

最后一步就是在状态值变化时候调用LiveData.setValue()更新数据。这里的逻辑和具体业务相关,demo中的业务场景是点击ImageView控件时改变其图片。

public class ActivityB extends AppCompatActivity implements View.OnClickListener, Observer<Status> {
    private int level;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
        findViewById(R.id.iv_arrow).setOnClickListener(this);
        ...
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        switch (id) {
            ...
            case R.id.iv_arrow:
                changeArrowStatus(++level);
                putStatus(level);
                break;
        }
    }

    /**
     * put status data into LiveData when data is changed
     */
    private void putStatus(int level) {
        Status status = new Status();
        status.setLevel(level);
        StatusLiveData.getInstance().setValue(status);
    }

    private void changeArrowStatus(int level) {
        ImageView ivArrow = findViewById(R.id.iv_arrow);
        LevelListDrawable levelListDrawable = ((LevelListDrawable) ivArrow.getDrawable());
        levelListDrawable.setLevel(level % 2);
    }
}
复制代码

talk is cheap, show me the code

抛砖引玉,若大家有更好的方案,欢迎交流~~

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值