想了解更多内容,请访问:
51CTO和华为官方合作共建的鸿蒙技术社区
https://harmonyos.51cto.com
在讲解ActiveData实现原理之前,我们有必要先了解一下两个重要的类Lifecycle以及DataObserver,这两个类在ActiveData整个运行过程中扮演了非常重要的角色。
- Lifecycle提供了观察Ability和AbilitySlice的生命周期能力
- DataObserver通过持有一个Lifecycle对象来观察Ability或者AbilitySlice的生命周期变化,同时DataObserver还允许ActiveData观察其生命周期变化,因此DataObserver和ActiveData相互观察,DataObserver观察ActiveData的数据变化,ActiveData观察DataObserver的生命周期变化。
ActiveData作用和特点
ActiveData是一个具有感知生命周期能力变化的数据通知类组件,非常适合在一些对数据同步性较高的场景下使用,它具有以下三个特点。
基于观察者模式:
ActiveData是一个持有可被观察数据的类,ActiveData需要一个观察者对象,一般是DataObserver类的具体实现。
感知生命周期:
ActiveData具有生命周期感知能力,目前ActiveData具有两种通知模式,一种是Ability/AbilitySlice生命周期是活跃(ACTIVE)状态时才更新数据,另一种是Ability/AbilitySlice生命周期处于任何存活状态(即只要没有被销毁)都可以更新数据。
自动解除数据订阅:
ActiveData必须配合实现了Lifecycle的对象使用。当Ability/AbilitySlice被销毁(STOP状态)后,会自动解除订阅,这在一定程度上可以避免内存泄漏等问题。
实践
1.基础用法
public class MainAbilitySlice extends AbilitySlice {
private ActiveData<String> activeData;
private Text mText;
private final DataObserver<String> dataObserver = new DataObserver<String>() {
@Override
public void onChanged(String s) {
mText.setText(s);
}
};
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
activeData = new ActiveData<>();
dataObserver.setLifecycle(getLifecycle());
mText = (Text) findComponentById(ResourceTable.Id_text_helloworld);
subscribe();
}
private void subscribe() {
activeData.addObserver(dataObserver, true);
}
@Override
public void onActive() {
super.onActive();
activeData.setData("New Hello World");
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
运行之后的截图:
从运行结果可以看出,setData调用后会立即触发onChanged回调方法
2.主线程手动调用
// 添加如下代码测试DataObserver的onChanged方法是否会执行
findComponentById(ResourceTable.Id_button)
.setClickedListener(component -> activeData.setData("I Love China"));
- 1.
- 2.
- 3.
运行结果如下:
从运行结果我们可以看到,onChanged方法会一直触发,并不会因为值相同而不执行,虽然暂时看不了鸿蒙源码,但我们可以大胆猜测,鸿蒙底层维护了一个类似于版本号的标记,每次setData,该标记会自动+1,从而通过此版本号来判断data是否有变化,进而决定是否触发onChanged回调方法。
3.子线程调用
@Override
public void onActive() {
super.onActive();
new Thread(() -> activeData.setData("New Hello World")).start();
}
- 1.
- 2.
- 3.
- 4.
- 5.
4.运行后发现没有问题,可以正常调用,说明setData方法可以在子线程调用。
public class MainAbilitySlice extends AbilitySlice {
private ActiveData<String> activeData;
private ActiveData<String> activeData2;
private Text mText;
private final DataObserver<String> dataObserver = new DataObserver<String>() {
@Override
public void onChanged(String s) {
mText.setText(s);
System.out.println("ActiveData:---onChange:"+s);
}
};
private final DataObserver<String> dataObserver2 = new DataObserver<String>() {
@Override
public void onChanged(String s) {
mText.setText(s);
System.out.println("ActiveData:---onChange:"+s);
}
};
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
activeData = new ActiveData<>();
activeData2 = new ActiveData<>();
dataObserver.setLifecycle(getLifecycle());
dataObserver2.setLifecycle(getLifecycle());
mText = (Text) findComponentById(ResourceTable.Id_text_helloworld);
findComponentById(ResourceTable.Id_button)
.setClickedListener(component -> activeData.setData("I Love China"));
findComponentById(ResourceTable.Id_addObserver_true).setClickedListener(component -> {
System.out.println("ActiveData:-------------");
Intent intent1 = new Intent();
Operation operation = new Intent.OperationBuilder()
.withDeviceId("")
.withBundleName(getBundleName())
.withAbilityName(SecondAbility.class.getName())
.build();
intent1.setOperation(operation);
startAbility(intent1);
// 此处是为了验证Ability在inActive状态的值的变化情况
new EventHandler(EventRunner.getMainEventRunner()).postTask(() -> activeData.setData("New Hello World"), 2000);
});
findComponentById(ResourceTable.Id_addObserver_false).setClickedListener(component -> {
System.out.println("ActiveData:-------------");
Intent intent1 = new Intent();
Operation operation = new Intent.OperationBuilder()
.withDeviceId("")
.withBundleName(getBundleName())
.withAbilityName(SecondAbility.class.getName())
.build();
intent1.setOperation(operation);
startAbility(intent1);
// 此处是为了验证Ability在inActive状态的值的变化情况
new EventHandler(EventRunner.getMainEventRunner()).postTask(() -> activeData2.setData("New Hello World"), 2000);
});
subscribe();
}
private void subscribe() {
activeData.addObserver(dataObserver, true);
activeData2.addObserver(dataObserver, false);
}
@Override
public void onActive() {
super.onActive();
System.out.println("ActiveData:---onActive");
}
@Override
protected void onInactive() {
super.onInactive();
System.out.println("ActiveData:---onInactive");
}
@Override
protected void onBackground() {
super.onBackground();
System.out.println("ActiveData:---onBackground");
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
System.out.println("ActiveData:---onForeground");
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
运行效果如下:
从以上运行结果,可以看出addObserver(dataObserver, true/false)方法的特点,当为true是表示无论Ability/AbilitySlice处于任何生命周期状态,均会触发onChanged回调方法,当为false时表示Ability/AbilitySlice只有处于ACTIVE状态时才会触发onChanged方法。
总结
- ActiveData内部是依靠Lifecycle来感知组件的生命周期,从而可以避免内部泄漏
- 开发者无需维护observer对象,当Ability/AbilitySlice被销毁时,相关联的observer会被自动移除
- 当Ability/AbilitySlice处于活跃(ACTIVE)状态时,当ActiveData数据源发生变化时onChanged方法会立即触发,去更新UI或者执行我们想要的任何操作
- setData方法可在任意线程中去调用,开发者无需关心调用者是否在主线程中
- setData方法即使设置同样的数据对象,onChanged方法仍然会被触发
想了解更多内容,请访问:
51CTO和华为官方合作共建的鸿蒙技术社区
https://harmonyos.51cto.com