HarmonyOS基础技术赋能之轻量级数据库Preferencens 原创 精华

软通张二龙
发布于 2021-8-23 15:05
2.3w浏览
16收藏

HarmonyOS基础技术赋能之轻量级数据库Preferencens-鸿蒙开发者社区

引言
轻量级数据存储适用于对Key-Value结构的数据进行存取和持久化操作。主要用于保存应用的一些常用配置,并不适合存储大量数据和频繁改变数据的场景。用户的数据保存在文件中,可以持久化的存储在设备上。需要注意的是用户访问的实例包含文件所有数据,并一直加载在设备的内存中,并通过轻量级数据存储的API完成数据操作。

功能介绍
轻量级数据存储向本地应用提供的API支持本地应用读写数据及观察数据变化。数据存储形式为键值对,键的类型为字符串型(String),值的存储数据类型包括整型(int)、字符串型(String)、布尔型(boolean)、浮点型(float)、长整型(long)、字符串型Set集合(Set<String>)。

开发指南

1. 创建Preferences实例。

// context为上下文对象,PREFERENCE_FILE_NAME为轻量级数据库文件名,String类型,可以自定义
databaseHelper = new DatabaseHelper(context);
preferences = databaseHelper.getPreferences(PREFERENCE_FILE_NAME);

  • 1.
  • 2.
  • 3.

2. 将数据写入指定文件。

// preferences.putString()为存入String类型的数据
preferences.putString(String key, String value);
// flush()为异步持久化数据;flushSync()为同步持久化数据
preferences.flush()/preferences.flushSync();
  • 1.
  • 2.
  • 3.
  • 4.

3.从指定文件读取数据。

//读取时传入的key, 要与写入时传入的key一致,才能获取对应数据,第二个参数为默认值。
  preferences.getString(String key, String default)
  • 1.
  • 2.

4. 开发者可以向Preferences实例注册观察者,观察数据更新变化。

private class PreferencesObserverImpl implements Preferences.PreferencesObserver {
   
    @Override    
    public void onChange(Preferences preferences, String key) {
        if ("key".equals(key)) {
           HiLog.info(LABLE, "Change Received:[key=value]");        
        }    
    }
}


// 向preferences实例注册观察者
PreferencesObserverImpl observer = new PreferencesObserverImpl();
preferences.registerObserver(observer);
// 修改数据后,observer的onChange方法会被回调
// 向preferences实例注销观察者
preferences.unRegisterObserver(observer);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

源码如下:

1.PreferenceUtils

public class PreferenceUtils {

  private static String PREFERENCE_FILE_NAME = "prefrence_file";
  private static Preferences preferences;
  private static DatabaseHelper databaseHelper;
  private static PreferencesObserver mPreferencesObserver;

  private static void initPreference(Context context){
    if(databaseHelper==null){
      databaseHelper = new DatabaseHelper(context);
    }
    if(preferences==null){
      preferences = databaseHelper.getPreferences(PREFERENCE_FILE_NAME);
    }

  }

  //存放、获取时传入的context必须是同一个context,否则存入的数据无法获取
  public static void putString(Context context, String key, String value) {
    initPreference(context);
    preferences.putString(key, value);
    preferences.flush();
  }

  /**
   * @param context 上下文
   * @param key  键
   * @return 获取的String 默认值为:null
   */
  public static String getString(Context context, String key) {
    initPreference(context);
    return preferences.getString(key, null);
  }


  public static void putInt(Context context, String key, int value) {
    initPreference(context);
    preferences.putInt(key, value);
    preferences.flush();
  }

  /**
   * @param context 上下文
   * @param key 键
   * @return 获取int的默认值为:-1
   */
  public static int getInt(Context context, String key) {
    initPreference(context);
    return preferences.getInt(key, -1);
  }


  public static void putLong(Context context, String key, long value) {
    initPreference(context);
    preferences.putLong(key, value);
    preferences.flush();
  }

  /**
   * @param context 上下文
   * @param key  键
   * @return 获取long的默认值为:-1
   */
  public static long getLong(Context context, String key) {
    initPreference(context);
    return preferences.getLong(key, -1L);
  }


  public static void putBoolean(Context context, String key, boolean value) {
    initPreference(context);
    preferences.putBoolean(key, value);
    preferences.flush();
  }

  /**
   * @param context  上下文
   * @param key  键
   * @return 获取boolean的默认值为:false
   */
  public static boolean getBoolean(Context context, String key) {
    initPreference(context);
    return preferences.getBoolean(key, false);
  }


  public static void putFloat(Context context, String key, float value) {
    initPreference(context);
    preferences.putFloat(key, value);
    preferences.flush();
  }

  /**
   * @param context 上下文
   * @param key   键
   * @return 获取float的默认值为:0.0
   */
  public static float getFloat(Context context, String key) {
    initPreference(context);
    return preferences.getFloat(key, 0.0F);
  }


  public static void putStringSet(Context context, String key, Set<String> set) {
    initPreference(context);
    preferences.putStringSet(key, set);
    preferences.flush();
  }

  /**
   * @param context  上下文
   * @param key 键
   * @return 获取set集合的默认值为:null
   */
  public static Set<String> getStringSet(Context context, String key) {
    initPreference(context);
    return preferences.getStringSet(key, null);
  }


  public static boolean deletePreferences(Context context) {
    initPreference(context);
    boolean isDelete= databaseHelper.deletePreferences(PREFERENCE_FILE_NAME);
    return isDelete;
  }


  public static void registerObserver(Context context,PreferencesObserver preferencesObserver){
    initPreference(context);
    mPreferencesObserver=preferencesObserver;
    preferences.registerObserver(mPreferencesObserver);
  }

  public static void unregisterObserver(){
    if(mPreferencesObserver!=null){
      // 向preferences实例注销观察者
      preferences.unregisterObserver(mPreferencesObserver);
    }
  }

}
  • 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.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.

2. MainAbilitySlice

public class MainAbilitySlice extends AbilitySlice implements ClickedListener {
  private TextField tfName;
  private TextField tfGener;
  private TextField tfAge;
  private TextField tfWeight;
  private Text tvResultQuery;
  private Text tvResultListener;
  private String name;
  private boolean isMan;
  private int age;
  private float weight;


  @Override
  public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_ability_main);
    tfName=(TextField)findComponentById(ResourceTable.Id_tf_name);
    tfGener=(TextField)findComponentById(ResourceTable.Id_tf_isMan);
    tfAge=(TextField)findComponentById(ResourceTable.Id_tf_age);
    tfWeight=(TextField)findComponentById(ResourceTable.Id_tf_weight);
    tvResultQuery=(Text) findComponentById(ResourceTable.Id_tvResultQuery);
    tvResultListener=(Text) findComponentById(ResourceTable.Id_tvResultListener);
    Button btSave=(Button)findComponentById(ResourceTable.Id_bt_save);
    Button btQuery=(Button)findComponentById(ResourceTable.Id_bt_query);
    Button btRegister=(Button)findComponentById(ResourceTable.Id_bt_regist);
    Button btUnRegister=(Button)findComponentById(ResourceTable.Id_bt_unregist);
    btSave.setClickedListener(this);
    btQuery.setClickedListener(this);
    btRegister.setClickedListener(this);
    btUnRegister.setClickedListener(this);
  }

  @Override
  public void onActive() {
    super.onActive();
  }

  @Override
  public void onForeground(Intent intent) {
    super.onForeground(intent);
  }

  @Override
  public void onClick(Component component) {
    switch (component.getId()){
      case ResourceTable.Id_bt_save:
        PreferenceUtils.putString(MyApplication.mContext,"name",tfName.getText());
        if(tfGener.getText().equals("男")){
          PreferenceUtils.putBoolean(MyApplication.mContext,"gender",true);
        }
        try {
          String age=tfAge.getText();
          String weight=tfWeight.getText();
          int ageInt=Integer.parseInt(age);
          float weightFloat=Float.parseFloat(weight);
          PreferenceUtils.putInt(MyApplication.mContext,"age",ageInt);
          PreferenceUtils.putFloat(MyApplication.mContext,"weight",weightFloat);
        }catch (Exception e){
          e.printStackTrace();
        }
        new ToastDialog(this).setDuration(2000).setText("保存成功").setAlignment(LayoutAlignment.CENTER).show();
        break;
      case ResourceTable.Id_bt_query:
         name=PreferenceUtils.getString(MyApplication.mContext,"name");
         isMan=PreferenceUtils.getBoolean(MyApplication.mContext,"gender");
         age=PreferenceUtils.getInt(MyApplication.mContext,"age");
         weight=PreferenceUtils.getFloat(MyApplication.mContext,"weight");
        if(isMan){
          tvResultQuery.setText("查询结果:"+name+"/男/"+age+"/"+weight);
        }else {
          tvResultQuery.setText("查询结果:"+name+"/女/"+age+"/"+weight);
        }
        new ToastDialog(this).setDuration(2000).setText("查询成功").setAlignment(LayoutAlignment.CENTER).show();
        break;
      case ResourceTable.Id_bt_regist:
        PreferenceUtils.registerObserver(this,new PreferencesObserver() {
          @Override
          public void onChange(Preferences preferences, String key) {
            switch (key){
              case "name":
                 name=PreferenceUtils.getString(MyApplication.mContext,"name");
                break;
              case "gender":
                 isMan=PreferenceUtils.getBoolean(MyApplication.mContext,"gender");
                break;
              case "age":
                 age=PreferenceUtils.getInt(MyApplication.mContext,"age");
                break;
              case "weight":
                 weight=PreferenceUtils.getFloat(MyApplication.mContext,"weight");
                break;
            }
            if(isMan){
              tvResultListener.setText("兼停结果:"+name+"/男/"+age+"/"+weight);
            }else {
              tvResultListener.setText("兼停结果:"+name+"/女/"+age+"/"+weight);
            }
          }

        });
        new ToastDialog(this).setDuration(2000).setText("注册成功").setAlignment(LayoutAlignment.CENTER).show();
        break;
      case ResourceTable.Id_bt_unregist:
        PreferenceUtils.unregisterObserver();
        new ToastDialog(this).setDuration(2000).setText("解除注册成功").setAlignment(LayoutAlignment.CENTER).show();
        break;
    }

  }



}
  • 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.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.

3. MyApplication

public class MyApplication extends AbilityPackage {
  public static Context mContext ;

  @Override
  public void onInitialize() {
    super.onInitialize();
    mContext=this;
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

4.页面布局ability_main.xml文件

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
  xmlns:ohos="http://schemas.huawei.com/res/ohos"
  ohos:height="match_parent"
  ohos:orientation="vertical"
  ohos:width="match_parent">

  <DirectionalLayout
    ohos:height="match_content"
    ohos:width="match_parent"
    ohos:orientation="vertical"
    ohos:left_padding="15vp"
    ohos:right_padding="15vp"
    ohos:top_padding="16vp">
    <Text
      ohos:height="match_content"
      ohos:width="match_content"
      ohos:text="姓名"
      ohos:text_size="18vp"/>
    <TextField
      ohos:id="$+id:tf_name"
      ohos:height="match_content"
      ohos:width="match_parent"
      ohos:text_input_type="pattern_text"
      ohos:hint="请输入姓名"
      ohos:text_size="18vp"
      ohos:hint_color="#cccccc"
      ohos:top_margin="8vp"/>
    <DirectionalLayout
      ohos:height="1vp"
      ohos:width="match_parent"
      ohos:top_margin="3vp"
      ohos:background_element="#cccccc"/>
  </DirectionalLayout>


  <DirectionalLayout
    ohos:height="match_content"
    ohos:width="match_parent"
    ohos:orientation="vertical"
    ohos:left_padding="15vp"
    ohos:right_padding="15vp"
    ohos:top_padding="16vp">
    <Text
      ohos:height="match_content"
      ohos:width="match_content"
      ohos:text="性别"
      ohos:text_size="18vp"/>
    <TextField
      ohos:id="$+id:tf_isMan"
      ohos:height="match_content"
      ohos:width="match_parent"
      ohos:text_input_type="pattern_text"
      ohos:hint="男/女"
      ohos:text_size="18vp"
      ohos:hint_color="#cccccc"
      ohos:top_margin="8vp"/>
    <DirectionalLayout
      ohos:height="1vp"
      ohos:width="match_parent"
      ohos:top_margin="3vp"
      ohos:background_element="#cccccc"/>
  </DirectionalLayout>


  <DirectionalLayout
    ohos:height="match_content"
    ohos:width="match_parent"
    ohos:orientation="vertical"
    ohos:left_padding="15vp"
    ohos:right_padding="15vp"
    ohos:top_padding="16vp">
    <Text
      ohos:height="match_content"
      ohos:width="match_content"
      ohos:text="年龄"
      ohos:text_size="18vp"/>
    <TextField
      ohos:id="$+id:tf_age"
      ohos:height="match_content"
      ohos:width="match_parent"
      ohos:text_input_type="pattern_number"
      ohos:hint="请输入年龄"
      ohos:text_size="18vp"
      ohos:hint_color="#cccccc"
      ohos:top_margin="8vp"/>
    <DirectionalLayout
      ohos:height="1vp"
      ohos:width="match_parent"
      ohos:top_margin="3vp"
      ohos:background_element="#cccccc"/>
  </DirectionalLayout>


  <DirectionalLayout
    ohos:height="match_content"
    ohos:width="match_parent"
    ohos:orientation="vertical"
    ohos:left_padding="15vp"
    ohos:right_padding="15vp"
    ohos:top_padding="16vp">
    <Text
      ohos:height="match_content"
      ohos:width="match_content"
      ohos:text="体重"
      ohos:text_size="18vp"/>
    <TextField
      ohos:id="$+id:tf_weight"
      ohos:height="match_content"
      ohos:width="match_parent"
      ohos:text_input_type="pattern_number"
      ohos:hint="请输入体重"
      ohos:text_size="18vp"
      ohos:hint_color="#cccccc"
      ohos:top_margin="8vp"/>
    <DirectionalLayout
      ohos:height="1vp"
      ohos:width="match_parent"
      ohos:top_margin="3vp"
      ohos:background_element="#cccccc"/>
  </DirectionalLayout>



  <DirectionalLayout
    ohos:height="match_content"
    ohos:width="match_parent"
    ohos:orientation="horizontal"
    ohos:top_margin="30vp"
    ohos:left_margin="15vp"
    ohos:right_margin="15vp">
    <Button
      ohos:id="$+id:bt_save"
      ohos:height="40vp"
      ohos:width="0"
      ohos:weight="1"
      ohos:text="保存"
      ohos:text_size="20vp"
      ohos:text_color="#ffffff"
      ohos:right_margin="30vp"
      ohos:background_element="$graphic:background_main_circle"
      ohos:layout_alignment="center"/>
    <Button
      ohos:id="$+id:bt_query"
      ohos:height="40vp"
      ohos:width="0"
      ohos:weight="1"
      ohos:text="查询"
      ohos:text_size="20vp"
      ohos:text_color="#ffffff"
      ohos:right_margin="30vp"
      ohos:background_element="$graphic:background_main_circle"
      ohos:layout_alignment="center"/>
  </DirectionalLayout>

  <DirectionalLayout
    ohos:height="match_content"
    ohos:width="match_parent"
    ohos:orientation="horizontal"
    ohos:top_margin="30vp"
    ohos:left_margin="15vp"
    ohos:right_margin="15vp">
    <Button
      ohos:id="$+id:bt_regist"
      ohos:height="40vp"
      ohos:width="0"
      ohos:weight="1"
      ohos:text="注册兼停"
      ohos:text_size="20vp"
      ohos:text_color="#ffffff"
      ohos:right_margin="30vp"
      ohos:background_element="$graphic:background_main_circle"
      ohos:layout_alignment="center"/>
    <Button
      ohos:id="$+id:bt_unregist"
      ohos:height="40vp"
      ohos:width="0"
      ohos:weight="1"
      ohos:text="解除注册"
      ohos:text_size="20vp"
      ohos:text_color="#ffffff"
      ohos:right_margin="30vp"
      ohos:background_element="$graphic:background_main_circle"
      ohos:layout_alignment="center"/>
  </DirectionalLayout>



  <Text
    ohos:id="$+id:tvResultQuery"
    ohos:height="match_content"
    ohos:width="match_content"
    ohos:text_size="18vp"
    ohos:text="查询结果:"
    ohos:background_element="#cccccc"
    ohos:layout_alignment="center"
    ohos:top_margin="30vp"
    ohos:padding="10vp"/>

  <Text
    ohos:id="$+id:tvResultListener"
    ohos:height="match_content"
    ohos:width="match_content"
    ohos:text_size="18vp"
    ohos:text="兼停结果:"
    ohos:background_element="#cccccc"
    ohos:layout_alignment="center"
    ohos:top_margin="30vp"
    ohos:padding="10vp"/>

</DirectionalLayout>
  • 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.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.
  • 210.
  • 211.

5.圆角背景图形background_main_circle.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<shape xmlns:ohos="http://schemas.huawei.com/res/ohos"
       ohos:shape="rectangle">
    <corners
        ohos:radius="10"/>
    <solid
        ohos:color="#00aaf5"/>

</shape>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

实现效果视频:https://harmonyos.51cto.com/show/7929

更多原创内容请关注:软通动力HarmonyOS学院

因敏感词问题故以兼停替换

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
分类
已于2021-8-25 09:50:41修改
17
收藏 16
回复
举报
17
8
16
8条回复
按时间正序
/
按时间倒序
软通田可辉
软通田可辉

张老师的文章写的很细致。

回复
2021-8-23 15:08:38
粉粉gg
粉粉gg

张老师文章排版好整齐哦

回复
2021-8-23 15:11:31
江湖人称鸿老师
江湖人称鸿老师

感谢张老师分享

回复
2021-8-24 09:07:02
可可学鸿蒙
可可学鸿蒙

感谢软通大佬分享

回复
2021-8-24 09:09:31
软通张二龙
软通张二龙 回复了 软通田可辉
张老师的文章写的很细致。

写的细致,大家才能更快学会

回复
2021-8-24 09:21:19
顾自由
顾自由

感谢张老师的分享,多多更新啊

回复
2021-8-24 09:31:07
软通动力HOS
软通动力HOS

感谢张老师分享

回复
2021-8-26 11:38:52
爱吃土豆丝的打工人
爱吃土豆丝的打工人

今天是数据库开发日嘛   热帖全部都是数据库哇

回复
2021-8-26 14:04:29


回复
    相关推荐