HarmonyOS关于元数据绑定框架探索

开发 OpenHarmony
根据官方Demo介绍,元数据绑定框架是基于HarmonyOS SDK开发的一套提供UI和数据源绑定能力的框架。通过使用元数据绑定框架,HarmonyOS应用开发者无需开发繁琐重复的代码即可实现绑定UI和数据源。

[[418493]]

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

前言

在上一篇HarmonyOS DataBinding 使用指南中,有人提到了元数据绑定框架并提出了疑问,元数据绑定框架跟DataBinding有什么区别?功能上似乎也是做数据绑定,我查阅了官方文档,没有太多的资料,只有Codelabs上有个Demo教程,带着这种疑问,让我们一起来探索一下。

概述

根据官方Demo介绍,元数据绑定框架是基于HarmonyOS SDK开发的一套提供UI和数据源绑定能力的框架。通过使用元数据绑定框架,HarmonyOS应用开发者无需开发繁琐重复的代码即可实现绑定UI和数据源。这跟Databinding功能类似,接下来让我们再来看看它们有什么不同之处。

开始使用

简单UI组件绑定

1.首先,我们在模块的build.gradle文件中的dependencies中添加对元数据绑定框架的引用,并开启注解处理器:

  1. implementation 'com.huawei.middleplatform:ohos-metadata-annotation:1.0.0.0' 
  2. implementation 'com.huawei.middleplatform:ohos-metadata-binding:1.0.0.0' 
  3. annotationProcessor 'com.huawei.middleplatform:ohos-metadata-processor:1.0.0.0' 
  1. ohos { 
  2.     compileOptions { 
  3.         annotationEnabled true 
  4.     } 

2.引用之后我们在MyApplication中对其进行初始化并添加对应注解,具体代码如下:

  1. /** 
  2.  * requireData = true 表示该application需要获取数据 
  3.  * exportData = false 表示该application不对外提供数据 
  4.  */ 
  5. @MetaDataApplication(requireData = true, exportData = false
  6. public class MyApplication extends AbilityPackage { 
  7.     private static Context context; 
  8.  
  9.     @Override 
  10.     public void onInitialize() { 
  11.         super.onInitialize(); 
  12.         mContext = this.getContext(); 
  13.         //初始化MetaDataFramework 
  14.         MetaDataFramework.init(this); 
  15.     } 
  16.       public static Context getApplication() { 
  17.         return context; 
  18.     } 

其中注解中的requireData表示该application是否需要获取数据,exportData表示该application是否外提供数据,大家可根据自己的需求进行配置。

3.接下来我们需要定义元数据,数据是以Json的格式,而DataBinding则是采用ActiveData对象绑定数据。我们简单的定义两个参数。Json数据采用得是Json Schema定义的一套词汇和规则,我们用这套词汇和规则用来定义Json元数据。最后我们需要将元数据Json文件放在resource/rawfile.jsonschema路径下。

  1.   "id""com.example.meta-data.time"
  2.   "title""test"
  3.   "$schema""http://json-schema.org/draft-04/schema#"
  4.   "description""test description"
  5.   "type""object"
  6.   "properties": { 
  7.     "id": { 
  8.       "type""integer" 
  9.     }, 
  10.     "message": { 
  11.       "type""string" 
  12.     } 
  13.   } 

4.在我们XML布局文件中,最外层的Layout中加入元数据绑定的框架的命名空间:xmlns:metaDataBinding,并创建元数据实体,作用跟我们Databinding的标签类似,之后再我们组件中进行数据绑定,注意!在Databinding中用的是ohos的命名空间,而使用元数据绑定的时候,需要用metaDataBinding命名空间,具体代码如下:

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <DirectionalLayout 
  3.     xmlns:ohos="http://schemas.huawei.com/res/ohos" 
  4.     xmlns:metaDataBinding="http://schemas.huawei.com/res/metaDatabinding" 
  5.     ohos:height="match_parent" 
  6.     ohos:width="match_parent" 
  7.     ohos:orientation="vertical"
  8.     <request-meta-data 
  9.         name="TestData" 
  10.         schema="com.example.meta-data.time" 
  11.         uri="dataability:///com.example.time.db.TestDataAbility"/> 
  12.      <Text 
  13.         ohos:id="$+id:title_text" 
  14.         ohos:height="300" 
  15.         ohos:width="match_parent" 
  16.         metaDataBinding:text="@{TestData.message}" 
  17.         ohos:text_alignment="center" 
  18.         ohos:text_color="#FF555555" 
  19.         ohos:text_size="50"/> 
  20. </DirectionalLayout> 

这时候这个标签就会报错:request-meta-data is not allowed here,具体原因还不清楚,怀疑是编译器的原因,但没关系,这并不影响我们的运行。

言归正传,在标签中,name为元数据名称,之后我们进行绑定的时候根据这个名称来引用,schema需要与刚定义的Json数据中id一致,uri则是我们使用元数据绑定的DataAbility路径。

5.接下来需要在代码中请求绑定,我们在AbilitySlice中的onStart方法中添加如下代码:

  1. @Override 
  2. public void onStart(Intent intent) { 
  3.     super.onStart(intent); 
  4.       Test alarm = TestOperation.queryFirst(this); 
  5.         if (alarm == null) { 
  6.             TestOperation.insert(this); 
  7.         } 
  8.     MetaDataRequestInfo request = new MetaDataRequestInfo.Builder() 
  9.             .setMetaDataClass("TestData", TestData.class) 
  10.             .setSyncRequest("TestData"true
  11.             .build(); 
  12.     MetaDataBinding binding; 
  13.     Component mainComponent; 
  14.     try { 
  15.         // 请求绑定 
  16.         binding = AbilityindexpageMetaDataBinding.requestBinding(this, request, null); 
  17.         // 获得绑定的界面组件 
  18.         mainComponent = binding.getLayoutComponent(); 
  19.     } catch (DataSourceConnectionException e) { 
  20.         mainComponent = LayoutScatter.getInstance(this) 
  21.                 .parse(ResourceTable.Layout_error_layout, nullfalse); 
  22.     } 
  23.     setUIContent((ComponentContainer) mainComponent); 

刚才第4点说到,TestData为对应的XML中标签中的name,TestData类是继承自DataAbilityMetaData的类,我们可以在里面根据业务需求对数据进行处理,作用有点类似DataBinding的Model。配置完布局文件之后会自动生成XXXMetaDataBinding文件,然后通过调用requestBinding方法进行绑定,如果绑定异常的话我们就返回一个错误页面。

  1. public class TestData  extends DataAbilityMetaData { 
  2.     public String toMessage(String message) { 
  3.         return message + "元数据绑定"
  4.     } 

6.配置部分基本完成,接下来就是配置数据库部分。数据库部分内容也比较多,这里只做简单的说明。关于数据库后续会有专门的文章进行详细讲解,欢迎大家订阅关注。

在我们上面XML布局中,标签uri属性指向的就是我们的DataAbility,这边主要做的就是数据访问更新等等。

  1. public class TestDataAbility extends Ability { 
  2.     public static final Uri CLOCK_URI = Uri.parse( 
  3.             "dataability:///com.example.time.db.TestDataAbility"); 
  4.  
  5.     private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "Demo"); 
  6.     private OrmContext ormContext = null
  7.  
  8.     @Override 
  9.     public void onStart(Intent intent) { 
  10.         super.onStart(intent); 
  11.         HiLog.info(LABEL_LOG, "TestDataAbility onStart"); 
  12.         DatabaseHelper manager = new DatabaseHelper(this); 
  13.         ormContext = manager.getOrmContext( 
  14.                 TestOrmDatabase.DATABASE_NAME_ALIAS, 
  15.                 TestOrmDatabase.DATABASE_NAME, 
  16.                 TestOrmDatabase.class); 
  17.     } 
  18.  
  19.     @Override 
  20.     public ResultSet query(Uri uri, String[] columns, DataAbilityPredicates predicates) { 
  21.         if (uri.equals(CLOCK_URI)) { 
  22.             OrmPredicates ormPredicates = DataAbilityUtils.createOrmPredicates(predicates, Test.class); 
  23.             return ormContext.query(ormPredicates, columns); 
  24.         } 
  25.         return null
  26.     } 
  27.  
  28.     @Override 
  29.     public int insert(Uri uri, ValuesBucket value) { 
  30.         Test alarm = new Test(); 
  31.         if (ormContext.insert(alarm.fromValues(value))) { 
  32.             ormContext.flush(); 
  33.             DataAbilityHelper.creator(this, uri).notifyChange(uri); 
  34.             return (int) alarm.getRowId(); 
  35.         } 
  36.         return -1; 
  37.     } 
  38.  
  39.     @Override 
  40.     public int delete(Uri uri, DataAbilityPredicates predicates) { 
  41.         return 0; 
  42.     } 
  43.  
  44.     @Override 
  45.     public int update(Uri uri, ValuesBucket value, DataAbilityPredicates predicates) { 
  46.         OrmPredicates ormPredicates; 
  47.         if (predicates == null) { 
  48.             Integer id = value.getInteger("id"); 
  49.             if (id == null) { 
  50.                 return -1; 
  51.             } 
  52.             value.delete("id"); 
  53.             ormPredicates = new OrmPredicates(Test.class).equalTo("id", id); 
  54.         } else { 
  55.             ormPredicates = DataAbilityUtils.createOrmPredicates(predicates, Test.class); 
  56.         } 
  57.         int rst = ormContext.update(ormPredicates, value); 
  58.         DataAbilityHelper.creator(getContext(), uri).notifyChange(uri); 
  59.         return rst; 
  60.     } 
  61.  
  62.     @Override 
  63.     public FileDescriptor openFile(Uri uri, String mode) { 
  64.         return null
  65.     } 
  66.  
  67.     @Override 
  68.     public String[] getFileTypes(Uri uri, String mimeTypeFilter) { 
  69.         return new String[0]; 
  70.     } 
  71.  
  72.     @Override 
  73.     public PacMap call(String method, String arg, PacMap extras) { 
  74.         return null
  75.     } 
  76.  
  77.     @Override 
  78.     public String getType(Uri uri) { 
  79.         return null
  80.     } 
  81.  
  82.     @Override 
  83.     protected void onStop() { 
  84.         super.onStop(); 
  85.         if (ormContext != null) { 
  86.             ormContext.close(); 
  87.         } 
  88.     } 

TestOperation类,是一个数据库的操作类,负责数据库的查询或写入等操作。

  1. public class TestOperation { 
  2.     private static final String COL_MSG = "message"
  3.     private static int idx = 0; 
  4.     private static int count = 0; 
  5.  
  6.     public TestOperation() { 
  7.     } 
  8.     public static void insert(Context context) { 
  9.         try { 
  10.             int time = Math.abs((int) System.currentTimeMillis()); 
  11.             ValuesBucket bucket = new ValuesBucket(); 
  12.             bucket.putString(COL_MSG, "元数据绑定" + idx++); 
  13.             DataAbilityHelper.creator(context).insert(TestDataAbility.CLOCK_URI, bucket); 
  14.         } catch (DataAbilityRemoteException ex) { 
  15.         } 
  16.     } 
  17.     public static void insertAnAlarm(MetaDataBinding binding) { 
  18.         MetaDataRequestInfo.RequestItem requestItem = binding.getRequestInfo().getRequestItem("TestData"); 
  19.         MetaData metaData = AbilityindexpageMetaDataBinding.createMetaData(requestItem); 
  20.         metaData.put(COL_MSG, "count" + count); 
  21.         binding.addMetaData(metaData, requestItem); 
  22.         count++; 
  23.     } 
  24.     public static Test queryFirst(Context context) { 
  25.         DataAbilityHelper helper = DataAbilityHelper.creator(context); 
  26.         ResultSet resultSet = null
  27.         try { 
  28.             resultSet = helper.query( 
  29.                     TestDataAbility.CLOCK_URI, 
  30.                     new String[]{COL_MSG}, 
  31.                     null); 
  32.         } catch (DataAbilityRemoteException e) { 
  33.         } 
  34.         Test test = null
  35.         if (resultSet != null) { 
  36.             boolean hasData = resultSet.goToFirstRow(); 
  37.             if (!hasData) { 
  38.                 return null
  39.             } 
  40.             test = getQueryResults(resultSet); 
  41.         } 
  42.         return test; 
  43.     } 
  44.  
  45.     private static Test getQueryResults(ResultSet resultSet) { 
  46.         Test alarm = new Test(); 
  47.         for (String column : resultSet.getAllColumnNames()) { 
  48.             int index = resultSet.getColumnIndexForName(column); 
  49.             alarm.setMessage(getFromColumn(resultSet, index).toString()); 
  50.         } 
  51.         return alarm; 
  52.     } 
  53.  
  54.     private static Object getFromColumn(ResultSet resultSet, int index) { 
  55.         ResultSet.ColumnType type = resultSet.getColumnTypeForIndex(index); 
  56.         switch (type) { 
  57.             case TYPE_INTEGER: 
  58.                 return resultSet.getInt(index); 
  59.             case TYPE_FLOAT: 
  60.                 return resultSet.getDouble(index); 
  61.             case TYPE_STRING: 
  62.                 return resultSet.getString(index); 
  63.             case TYPE_BLOB: 
  64.             case TYPE_NULL: 
  65.             default
  66.                 return null
  67.         } 
  68.     } 

TestOrmDatabase类,就是我们对象关系映射数据库的相关操作,具体可看官方文档。

  1. @Database(entities = {Test.class}, version = 1) 
  2. public abstract class TestOrmDatabase extends OrmDatabase { 
  3.  
  4.     public static final String DATABASE_NAME = "TestOrmDatabase.db"
  5.  
  6.     public static final String DATABASE_NAME_ALIAS = "TestOrmDatabase"

到目前位置我们整个元数据绑定的开发流程就完整了,下面是展示页面:

【中软国际】HarmonyOS 关于元数据绑定框架探索-鸿蒙HarmonyOS技术社区

Text显示的内容就是我们TestOperation类,在数据库添加的Message的数据( bucket.putString(COL_MSG, “元数据绑定” + idx++))。

UI容器组件绑定

接下来给大家说一下容器组件绑定,容器组件也就是我们的ListContainer,无处不列表,可以说是我们平时用的最多的组件,接下来给大家讲一下ListContainer如何进行绑定。(大致配置与简单UI差不多,下面只列出它们的区别之处)

1.首先我们需要在XML中添加ListContainer组件,我们直接沿用刚才的数据:

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <DirectionalLayout 
  3.     xmlns:ohos="http://schemas.huawei.com/res/ohos" 
  4.     xmlns:metaDataBinding="http://schemas.huawei.com/res/metaDatabinding" 
  5.     ohos:height="match_parent" 
  6.     ohos:width="match_parent" 
  7.     ohos:orientation="vertical"
  8.     <request-meta-data 
  9.         name="TestData" 
  10.         schema="com.example.meta-data.time" 
  11.         uri="dataability:///com.example.time.db.TestDataAbility"/> 
  12.     <Text 
  13.         ohos:id="$+id:title_text" 
  14.         ohos:height="300" 
  15.         ohos:width="match_parent" 
  16.         ohos:text="容器组件绑定" 
  17.         ohos:text_alignment="center" 
  18.         ohos:text_color="#FF555555" 
  19.         ohos:text_size="50"/> 
  20.  
  21.     <ListContainer 
  22.         ohos:id="$+id:list_view" 
  23.         ohos:top_margin="10vp" 
  24.         ohos:height="match_parent" 
  25.         ohos:width="match_parent" 
  26.         /> 
  27. </DirectionalLayout> 

2.跟正常使用一样,我们需要创建继承BaseItemProvider的Provider类:

  1. public class TestListProvider extends BaseItemProvider { 
  2.  
  3.     private final Context mContext; 
  4.     private List<TestRow> mData; 
  5.  
  6.     public TestListProvider(Context mContext) { 
  7.         this.mContext = mContext; 
  8.     } 
  9.  
  10.     public void initData(List<TestRow> testList) { 
  11.         this.mData = testList; 
  12.     } 
  13.     public void addItems(List<TestRow> alarmList) { 
  14.         this.mData.addAll(alarmList); 
  15.         mContext.getUITaskDispatcher().asyncDispatch(this::notifyDataChanged); 
  16.     } 
  17.     @Override 
  18.     public int getCount() { 
  19.         return mData.size(); 
  20.     } 
  21.  
  22.     @Override 
  23.     public Object getItem(int i) { 
  24.         return mData.get(i); 
  25.     } 
  26.  
  27.     @Override 
  28.     public long getItemId(int i) { 
  29.         return i; 
  30.     } 
  31.  
  32.     @Override 
  33.     public Component getComponent(int i, Component component, ComponentContainer componentContainer) { 
  34.         TestRow testRow = mData.get(i); 
  35.         if (component == null) { 
  36.             Component newComponent = testRow.createComponent(); 
  37.             testRow.bindComponent(newComponent); 
  38.             return newComponent; 
  39.         } else { 
  40.             testRow.bindComponent(component); 
  41.             return component; 
  42.         } 
  43.     } 

3.TestRow表示列表的条目,它持有一个元数据对象,我们对每个item进行数据绑定,获取UI组件及响应点击事件。

  1. public class TestRow { 
  2.     private final AbilitySlice context; 
  3.     private final TestData clockMeta; 
  4.  
  5.     public TestRow(AbilitySlice context, MetaData clockMeta) { 
  6.         this.context = context; 
  7.         this.clockMeta = (TestData) clockMeta; 
  8.     } 
  9.  
  10.     public Component createComponent() { 
  11.        TestlistitemlayoutMetaDataBinding metaBinding = TestlistitemlayoutMetaDataBinding.createBinding(context, clockMeta); 
  12.         Component comp = metaBinding.getLayoutComponent(); 
  13.         comp.setTag(metaBinding); 
  14.         return comp; 
  15.     } 
  16.  
  17.     public void bindComponent(Component component) { 
  18.         TestlistitemlayoutMetaDataBinding metaBinding = (TestlistitemlayoutMetaDataBinding) component.getTag(); 
  19.         metaBinding.reBinding(component, clockMeta); 
  20.     } 
  21. //      public void onClick() {  
  22. //       context.present(new XXXSlice(clockMeta), new Intent());  
  23. //   }  

TestlistitemlayoutMetaDataBinding是我们定义布局后自动生成的MetaDataBinding类,通过createBinding方法将布局与数据进行绑定。

4.接下来看一下item的布局:

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <DirectionalLayout 
  3.     xmlns:ohos="http://schemas.huawei.com/res/ohos" 
  4.     xmlns:metaDataBinding="http://schemas.huawei.com/res/metaDatabinding" 
  5.     ohos:height="match_content" 
  6.     ohos:width="match_parent" 
  7.     ohos:background_element="#000000" 
  8.     ohos:orientation="vertical"
  9.     <using-meta-data 
  10.         class="com.example.time.bean.TestData" 
  11.         name="TestData" 
  12.         schema="com.example.meta-data.time"/> 
  13.     <DirectionalLayout 
  14.         ohos:height="match_content" 
  15.         ohos:width="match_parent" 
  16.         ohos:background_element="#3c3c3c" 
  17.         ohos:bottom_padding="15vp" 
  18.         ohos:end_padding="15vp" 
  19.         ohos:orientation="vertical" 
  20.         ohos:start_padding="15vp" 
  21.         ohos:top_padding="15vp"
  22.  
  23.         <Text 
  24.             ohos:id="$+id:title_tv" 
  25.             ohos:height="match_content" 
  26.             ohos:width="match_parent" 
  27.             metaDataBinding:text="@={TestData.message}" 
  28.             ohos:text_size="16fp" 
  29.             ohos:text_color="#ffffff" 
  30.             /> 
  31.         <Text 
  32.             ohos:id="$+id:desc_tv" 
  33.             ohos:height="match_content" 
  34.             ohos:width="match_parent" 
  35.             ohos:top_margin="10vp" 
  36.             metaDataBinding:text="@={TestData.message}" 
  37.             ohos:text_size="12fp" 
  38.             ohos:text_color="#727272" 
  39.             /> 
  40.     </DirectionalLayout> 
  41.  
  42. </DirectionalLayout> 

这里需要注意的是,和普通布局区别在于item的元数据实体为

5.接下来就是在AbilitySlice中进行请求绑定:

  1. public class IndexPageAbilitySlice extends AbilitySlice implements IMetaDataObserver { 
  2.     private ListContainer mListContainer; 
  3.     private TestListProvider mTestListProvider; 
  4.  
  5.     @Override 
  6.     public void onStart(Intent intent) { 
  7.         super.onStart(intent); 
  8.         initView(); 
  9.     } 
  10.  
  11.     private void initView() { 
  12.         Test alarm = TestOperation.queryFirst(this); 
  13.         if (alarm == null) { 
  14.             TestOperation.insert(this); 
  15.         } 
  16.         // 创建元数据请求对象 
  17.         MetaDataRequestInfo request = new MetaDataRequestInfo.Builder() 
  18.                 .setMetaDataClass("TestData", TestData.class) 
  19.                 .setSyncRequest("TestData"false
  20.                 .build(); 
  21.         MetaDataBinding binding; 
  22.         Component mainComponent; 
  23.         try { 
  24.             // 请求绑定 
  25.             binding = AbilityindexpageMetaDataBinding.requestBinding(this, request, this); 
  26.             // 获得绑定的界面组件 
  27.             mainComponent = binding.getLayoutComponent(); 
  28.         } catch (DataSourceConnectionException e) { 
  29.             mainComponent = LayoutScatter.getInstance(this) 
  30.                     .parse(ResourceTable.Layout_error_layout, nullfalse); 
  31.         } 
  32.         setUIContent((ComponentContainer) mainComponent); 
  33.         mListContainer = (ListContainer) findComponentById(ResourceTable.Id_list_view); 
  34.         mTestListProvider = new TestListProvider(this); 
  35.  
  36.     } 
  37.  
  38.     @Override 
  39.     public void onActive() { 
  40.         super.onActive(); 
  41.     } 
  42.  
  43.     @Override 
  44.     public void onForeground(Intent intent) { 
  45.         super.onForeground(intent); 
  46.     } 
  47.  
  48.     @Override 
  49.     public void onDataLoad(List<MetaData> list, MetaDataRequestInfo.RequestItem requestItem) { 
  50.         if (list == null || requestItem == null) { 
  51.             return
  52.         } 
  53.         if (mListContainer != null) { 
  54.             mTestListProvider.initData(createAlarms(this, list)); 
  55.             mListContainer.setItemProvider(mTestListProvider); 
  56.         } 
  57.     } 
  58.     private List<TestRow> createAlarms(AbilitySlice context, List<MetaData> dataList) { 
  59.         List<TestRow> list = new ArrayList<>(); 
  60.         for (MetaData metaData : dataList) { 
  61.             TestRow item = new TestRow(context, metaData); 
  62.             list.add(item); 
  63.         } 
  64.         return list; 
  65.     } 
  66.     @Override 
  67.     public void onDataChange(List<MetaData> list, List<MetaData> list1, List<MetaData> list2, MetaDataRequestInfo.RequestItem requestItem) { 
  68.         if (list == null) { 
  69.             return
  70.         } 
  71.         mTestListProvider.addItems(createAlarms(this, list)); 
  72.     } 

容器组件绑定的话,我们实现了IMetaDataObserver接口,主要用于数据的加载及数据更新,在onDataLoad将Provider跟ListContainer进行绑定,如数据有发生变化,则onDataChange对列表进行更新,而在setSyncRequest传参中我们改为false,表示为异步请求,因为IMetaDataObserver方法会异步执行,如果传Ture的话,会在onDataLoad方法执行之后requestBinding方法才会返回,之后在请求绑定requestBinding方法中第三个参数,dataCallback传入this进行监听。

6.最终实现效果

【中软国际】HarmonyOS 关于元数据绑定框架探索-鸿蒙HarmonyOS技术社区

7.添加数据只需要调用我们之前的**TestOperation.insertAnAlarm(binding)**方法就可以进行数据添加:

元数据表达式

在xml文件中进行元数据绑定时 metaDataBinding会用到多种表达式,具体用法如下:

总结

元数据绑定的简单使用就介绍到这里,这里只跟大家展示了我们最常用的两种布局的绑定,我们还可以进行自定义UI的绑定、自定义数据源等等更多的用法等着大家一起来探索。

回到我们最初的问题,元数据绑定框架跟DataBinding有什么区别?我个人理解是,元数据绑定框架是基于元数据,而DataBinding则是绑定ActiveData(我们专栏有专门讲解ActiveData的文章,欢迎大家前去查阅。),两者的功能及数据源是不一样的,可以针对自己的业务需求进行选择。

但在Demo的编写过程中,也发现了一个问题,同一个页面普通UI组件和容器组件不能同事绑定,问题也时处在我们容器组件第5点所说的,实现了IMetaDataObserver接口进行异步请求,这点也希望跟大家一起继续探索,欢迎在评论区共同探讨。

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

 

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2021-09-01 14:36:14

鸿蒙HarmonyOS应用

2021-09-01 10:37:25

鸿蒙HarmonyOS应用

2011-08-25 16:28:23

Lua绑定系统

2023-09-04 18:57:01

API接口数据中心

2021-09-13 09:20:20

前端框架VUE

2022-05-24 09:50:27

元宇宙艺术人工智能

2010-07-30 11:03:54

Flex数据绑定

2009-11-06 10:45:47

WCF服务元数据交换

2024-12-16 08:30:00

JVMJava虚拟机Java

2024-05-23 07:39:00

大数据TBDS数据湖

2022-01-19 07:24:28

MetaCon元宇宙技术

2023-10-20 09:42:43

人工智能元宇宙

2024-04-02 09:55:36

GolangColly开发者

2018-05-02 16:34:56

EAF嵌入式框架

2022-06-15 15:40:16

元宇宙

2011-08-23 15:57:21

Lua元表元方法

2023-02-01 13:23:00

AI自动化

2022-07-04 23:24:17

元宇宙虚拟世界伦理问题

2009-06-02 17:18:10

hibernate框架简介

2023-08-07 09:00:00

点赞
收藏

51CTO技术栈公众号