当前位置:网站首页>Basic usage and skills of Hongmeng lightweight database databasehelper

Basic usage and skills of Hongmeng lightweight database databasehelper

2022-06-09 15:35:00 Hua Weiyun

Preface :

Hello everyone I haven't updated the article for you for a while ( Because I have been busy with the purchase loan before So stop I'm really sorry ) Today we are going to talk about the lightweight data in Hongmeng DatabaseHelper Basic usage some skills So, without much nonsense, we'll officially start

design sketch

6865547-2cbecdb84dc2dbd8.png
6865547-41f26b59289f1996.png
6865547-f450d3d210495865.png
6865547-41024521ed397be1.png
6865547-27af47d1f1c6e011.png

1 Introduce

Lightweight preference databases are lightweight storage , It is mainly used to save some common configurations of the application . It stores data in the form of key value pairs , When saving data , You need to provide a key for this data , When reading data, use this key to get the corresponding value .

explain

image.png
By looking at the source code The storage data types for lightweight preference database values include integers 、 Long integer 、 floating-point 、 Boolean type 、 String type 、 String type Set aggregate . The data is stored in a local file , It is also loaded in memory , It is not suitable for scenarios that need to store a large amount of data and change data frequently , It is recommended that no more than 10000 pieces of data be stored .

2 Create database

Create a database and use auxiliary classes for database operations DatabaseHelper, adopt DatabaseHelper Of getPreferences(String name) Method to get the corresponding file name Preferences example , Re pass Preferences Provides methods for database related operations .
DatabaseHelper The construct of needs to be passed in context,Ability and AbilitySlice It's all done ohos.app.Context Interface . Therefore, it can be seen from the Ability or AbilitySlice call getContext() How to get context.
Preferences The data is stored in a file , Therefore, you need to specify the name of the stored file , Its value cannot be empty , It can't contain paths , The default storage directory can be accessed through Context.getPreferencesDir() obtain .

DatabaseHelper databaseHelper = new DatabaseHelper(context);  String filename = "pdb";  Preferences preferences = databaseHelper.getPreferences(filename);

3 Write data

We are getting the numbers and words entered in the input box Then click on the button to call preferences Inside put Method to store data
adopt Preferences Of putString(String var1, String var2) and putInt(String var1, int var2) Method can write data to Preferences example , adopt flush() perhaps flushSync() take Preferences Instance persistence .
flush() Will immediately change the... In memory Preferences object , But updates are written asynchronously to disk .flushSync() Changing the data in memory will synchronously write the data to the disk . because flushSync() It's synchronous , It is not recommended to call it from the main thread , To avoid interface jamming .

  /*** *  Write data  * * */    private void btnWrite() {        btnWrite.setClickedListener(new Component.ClickedListener() {            @Override            public void onClick(Component component) {                String fruit = textFiledFruit.getText();                try {                    int number = Integer.parseInt(textFiledNumber.getText());                    preferences.putInt("number",number);                    preferences.putString("fruit",fruit);                    preferences.flush();                    new ToastDialog(context).setText("Write to DB file success").show();                } catch (NumberFormatException e) {                    new ToastDialog(context).setText("Please input number in Number row").show();                }            }        });    }

4 Reading data

We call preferences Medium get Method to get stored in DataBase Data in the library
adopt Preferences Of getString(String var1, String var2) and getInt(String var1, int var2) Method to get the corresponding value by passing in the key ; If the key doesn't exist , Returns the default value .
For example, get the above fruit and number Value of key , If fruit and number The key doesn't exist , Will return separately "" and 0 value . By setting the default value , To avoid program exceptions .

    /*** * *  Reading data  * */    private void btnRead() {        btnRead.setClickedListener(new Component.ClickedListener() {            @Override            public void onClick(Component component) {                String string = String.format(Locale.ENGLISH,"Fruit: %s,Number: %d",                        preferences.getString("fruit", ""),preferences.getInt("number", 0));                new ToastDialog(context).setText(string).show();            }        });    }

5 Delete database

adopt DatabaseHelper Of deletePreferences(String name) Method to delete the specified file .
When deleting the specified file , The application is not allowed to use this instance for data operations , Otherwise, there will be data consistency problems . Delete the above name as "pdb" For example .

  /** *  Delete data  * */    private void btnDelete() {        btnDelete.setClickedListener(new Component.ClickedListener() {            @Override            public void onClick(Component component) {                if (databaseHelper.deletePreferences(filename)) {                    preferences.clear();                    new ToastDialog(context).setText("Delete DB file success").show();                } else {                    new ToastDialog(context).setText("Delete DB file failed").show();                }            }        });    }

explain

The lightweight preference database supports the creation of database files 、 Move , Data query 、 Insert 、 Delete , And support the registration of observers to observe whether the data changes . Details are available Lightweight preference database .

6 cache list data

By observing the source code, we find that DatabaseHelper There is no way to store our data directly in a lightweight database list aggregate This is what we should do We pass the will List Turn into json character string And then json Save up We are taking the value and getting json The string is reverting to list It can be realized To facilitate the demonstration, we have written a tool class here

  • 1 Storage list Methods
   /** * 4. Storage list */   public static void putSelectBean(Context context, List<UserBean> phoneList, String key) {       databaseHelper = new DatabaseHelper(context);       preferences = databaseHelper.getPreferences(filename);       Gson gson = new Gson();       String json = gson.toJson(phoneList);       preferences.putString(key, json);       preferences.flush();   }

We wrote a putSelectBean To store our list

  • 2 Read list Methods
   /** *  Read list */    public static List<UserBean> getSelectBean(Context context, String key) {        databaseHelper = new DatabaseHelper(context);        preferences = databaseHelper.getPreferences(filename);        Gson gson = new Gson();        String json = preferences.getString(key, null);        Type type = new TypeToken<List<UserBean>>() {        }.getType();        List<UserBean> arrayList = gson.fromJson(json, type);        return arrayList;    }
  • 3 Specific storage list call
    /*** * *  cache list  Collection type data  * */    private void btnSavelist() {      btnsavelist.setClickedListener(new Component.ClickedListener() {          @Override          public void onClick(Component component) {              UserBean userBean=new UserBean();              userBean.setUsername("test");              userBean.setPassword("123456");              List<UserBean> datalist=new ArrayList<>();              datalist.add(userBean);              DataBaseUtil.putSelectBean(context,datalist,"datalist");              new ToastDialog(context).setText(" Write successfully ").show();          }      });    }
  • 4 Read list Type data call
     /*** * *  Read list  Collection type data  * */    private  void  btnReadList(){        btn_read_list.setClickedListener(new Component.ClickedListener() {            @Override            public void onClick(Component component) {                List<UserBean>getData= (List<UserBean>) DataBaseUtil.getSelectBean(context,"datalist");                UserBean userBean= getData.get(0);                new ToastDialog(context).setText(userBean.getUsername()+userBean.getPassword()).show();            }        });    }

7 DatabaseHelper Simple encapsulation of storage

We are using DatabaseHelper Every time when you are

DatabaseHelper databaseHelper = new DatabaseHelper(context);  String filename = "pdb";  Preferences preferences = databaseHelper.getPreferences(filename);

And then call preferences Of put Method storage and get Method reading The code is not very concise We can do a simple tool class encapsulation

  • 1 Encapsulation of storage methods
 private static  String filename = "pdb";    private static  Preferences preferences;    private static  DatabaseHelper databaseHelper;    /** *  How to save data , We need to get the specific type of data saved , Then call different save methods according to the type  * * @param context * @param key * @param object * @param :DataBaseUtil.setParam(this, "key", "value"); * key -- userid / accountId obj== */    public static void setParam(Context context, String key, Object object) {        String type = "String";        if (object != null) {            type = object.getClass().getSimpleName();        }        databaseHelper = new DatabaseHelper(context);        preferences = databaseHelper.getPreferences(filename);        if ("String".equals(type)) {            preferences.putString(key, (String) object);        } else if ("Integer".equals(type) || "int".equals(type)) {            preferences.putInt(key, (Integer) object);        } else if ("Boolean".equals(type) || "boolean".equals(type)) {            preferences.putBoolean(key, (Boolean) object);        } else if ("Float".equals(type) || "float".equals(type)) {            preferences.putFloat(key, (Float) object);        } else if ("Long".equals(type) || "long".equals(type)) {            preferences.putLong(key, (Long) object);        }        preferences.flush();    }
  • 2 Simple encapsulation of read methods
    /** *  Get a way to save data , We get the specific type of data saved according to the default value , Then call the relative method to get the value.  * * @param context * @param key  keyword  * @param defaultObject  If a null value is retrieved, this default value is returned  * @param :DataBaseUtil.getParam(Activity.this, "key", "defaultValue"); * @return */    public static Object getParam(Context context, String key, Object defaultObject) {        String type = "String";        if (defaultObject != null) {            type = defaultObject.getClass().getSimpleName();        }        databaseHelper = new DatabaseHelper(context);        preferences = databaseHelper.getPreferences(filename);        if ("String".equals(type)) {            return preferences.getString(key, (String) defaultObject);        } else if ("Integer".equals(type) || "int".equals(type)) {            return preferences.getInt(key, (Integer) defaultObject);        } else if ("Boolean".equals(type) || "boolean".equals(type)) {            return preferences.getBoolean(key, (Boolean) defaultObject);        } else if ("Float".equals(type) || "float".equals(type)) {            return preferences.getFloat(key, (Float) defaultObject);        } else if ("Long".equals(type) || "long".equals(type)) {            return preferences.getLong(key, (Long) defaultObject);        }        return null;    }
  • Specific call
   /*** * *  Call the tool class method to store  */    private void btnSavetoutils() {     btnsave_toutils.setClickedListener(new Component.ClickedListener() {         @Override         public void onClick(Component component) {             String fruit = textFiledFruit.getText();             try {                 int number = Integer.parseInt(textFiledNumber.getText());                 DataBaseUtil.setParam(context,"number",number);                 DataBaseUtil.setParam(context,"fruit",fruit);                 new ToastDialog(context).setText(" Write successfully ").show();             } catch (NumberFormatException e) {                 new ToastDialog(context).setText("Please input number in Number row").show();             }         }     });    }

Complete example

  • 1 xml Layout code
   <?xml version="1.0" encoding="utf-8"?><DirectionalLayout    xmlns:ohos="http://schemas.huawei.com/res/ohos"    ohos:height="match_parent"    ohos:width="match_parent"    ohos:orientation="vertical">    <Text        ohos:id="$+id:text_fruit_tag"        ohos:height="35vp"        ohos:width="match_parent"        ohos:background_element="$graphic:text_element"        ohos:layout_alignment="left"        ohos:text="Fruit"        ohos:text_size="85"        ohos:right_margin="20vp"        ohos:left_margin="20vp"        ohos:top_margin="25vp"        ohos:text_color="#000000"        />    <TextField        ohos:id="$+id:text_fruit"        ohos:height="35vp"        ohos:width="match_parent"        ohos:background_element="$graphic:text_element"        ohos:layout_alignment="left"        ohos:text="Orange"        ohos:text_size="50"        ohos:right_margin="20vp"        ohos:left_margin="20vp"        ohos:text_color="#000000"        ohos:top_margin="25vp"        ohos:basement="#000099"        />    <Text        ohos:id="$+id:text_number_tag"        ohos:height="35vp"        ohos:width="match_parent"        ohos:background_element="$graphic:text_element"        ohos:layout_alignment="left"        ohos:text="Number"        ohos:text_size="85"        ohos:right_margin="20vp"        ohos:left_margin="20vp"        ohos:text_color="#000000"        ohos:top_margin="25vp"        />    <TextField        ohos:id="$+id:text_number"        ohos:height="35vp"        ohos:width="match_parent"        ohos:background_element="$graphic:text_element"        ohos:layout_alignment="left"        ohos:text="25"        ohos:text_size="50"        ohos:right_margin="20vp"        ohos:left_margin="20vp"        ohos:text_color="#000000"        ohos:top_margin="25vp"        ohos:basement="#000099"        />    <Button        ohos:id="$+id:write_btn"        ohos:width="match_parent"        ohos:height="35vp"        ohos:text=" Write cache "        ohos:background_element="$graphic:button_element"        ohos:text_size="50"        ohos:text_color="#FFFFFF"        ohos:top_margin="25vp"        ohos:right_margin="20vp"        ohos:left_margin="20vp"        />    <Button        ohos:id="$+id:read_btn"        ohos:width="match_parent"        ohos:height="35vp"        ohos:text=" Read cache "        ohos:background_element="$graphic:button_element"        ohos:text_size="50"        ohos:text_color="#FFFFFF"        ohos:top_margin="25vp"        ohos:right_margin="20vp"        ohos:left_margin="20vp"        />    <Button        ohos:id="$+id:delete_btn"        ohos:width="match_parent"        ohos:height="35vp"        ohos:text=" Delete cache "        ohos:background_element="$graphic:button_element"        ohos:text_size="50"        ohos:text_color="#FFFFFF"        ohos:top_margin="25vp"        ohos:right_margin="20vp"        ohos:left_margin="20vp"        />    <Button        ohos:id="$+id:save_list"        ohos:width="match_parent"        ohos:height="35vp"        ohos:text=" Storage list"        ohos:background_element="$graphic:button_element"        ohos:text_size="50"        ohos:text_color="#FFFFFF"        ohos:top_margin="25vp"        ohos:right_margin="20vp"        ohos:left_margin="20vp"        />    <Button        ohos:id="$+id:read_list"        ohos:width="match_parent"        ohos:height="35vp"        ohos:text=" Read list"        ohos:background_element="$graphic:button_element"        ohos:text_size="50"        ohos:text_color="#FFFFFF"        ohos:top_margin="25vp"        ohos:right_margin="20vp"        ohos:left_margin="20vp"        />    <Button        ohos:id="$+id:save_toutils"        ohos:width="match_parent"        ohos:height="35vp"        ohos:text=" Tool class cache calls "        ohos:background_element="$graphic:button_element"        ohos:text_size="50"        ohos:text_color="#FFFFFF"        ohos:top_margin="25vp"        ohos:right_margin="20vp"        ohos:left_margin="20vp"        /></DirectionalLayout>
  • 2 Layout renderings

image.png

  • 3 java Logic code
package com.example.datademo.slice;import com.example.datademo.ResourceTable;import com.example.datademo.bean.UserBean;import com.example.datademo.utils.DataBaseUtil;import ohos.aafwk.ability.AbilitySlice;import ohos.aafwk.content.Intent;import ohos.agp.components.Button;import ohos.agp.components.Component;import ohos.agp.components.TextField;import ohos.agp.window.dialog.ToastDialog;import ohos.app.Context;import ohos.data.DatabaseHelper;import ohos.data.preferences.Preferences;import java.util.ArrayList;import java.util.List;import java.util.Locale;public class MainAbilitySlice extends AbilitySlice {    private Context context;    private Button btnWrite;    private Button btnRead;    private Button btnDelete;    private TextField textFiledFruit;    private TextField textFiledNumber;    private String filename;    private Preferences preferences;    private DatabaseHelper databaseHelper;    private Button btnsavelist;    private Button btnsave_toutils;    private Button btn_read_list;    @Override    public void onStart(Intent intent) {        super.onStart(intent);        super.setUIContent(ResourceTable.Layout_ability_main);        context = getContext();        btnWrite = (Button) findComponentById(ResourceTable.Id_write_btn);        btnRead = (Button) findComponentById(ResourceTable.Id_read_btn);        btnDelete = (Button) findComponentById(ResourceTable.Id_delete_btn);        textFiledFruit = (TextField) findComponentById(ResourceTable.Id_text_fruit);        textFiledNumber = (TextField) findComponentById(ResourceTable.Id_text_number);        btnsavelist= (Button) findComponentById(ResourceTable.Id_save_list);        btnsave_toutils= (Button) findComponentById(ResourceTable.Id_save_toutils);        btn_read_list= (Button) findComponentById(ResourceTable.Id_read_list);        databaseHelper = new DatabaseHelper(context);        filename = "pdb";        preferences = databaseHelper.getPreferences(filename);        btnWrite();        btnRead();        btnDelete();        btnSavelist();        btnSavetoutils();        btnReadList();    }    /*** *  Write data  * * */    private void btnWrite() {        btnWrite.setClickedListener(new Component.ClickedListener() {            @Override            public void onClick(Component component) {                String fruit = textFiledFruit.getText();                try {                    int number = Integer.parseInt(textFiledNumber.getText());                    preferences.putInt("number",number);                    preferences.putString("fruit",fruit);                    preferences.flush();                    new ToastDialog(context).setText("Write to DB file success").show();                } catch (NumberFormatException e) {                    new ToastDialog(context).setText("Please input number in Number row").show();                }            }        });    }    /*** * *  Reading data  * */    private void btnRead() {        btnRead.setClickedListener(new Component.ClickedListener() {            @Override            public void onClick(Component component) {                String string = String.format(Locale.ENGLISH,"Fruit: %s,Number: %d",                        preferences.getString("fruit", ""),preferences.getInt("number", 0));                new ToastDialog(context).setText(string).show();            }        });    }    /** *  Delete data  * */    private void btnDelete() {        btnDelete.setClickedListener(new Component.ClickedListener() {            @Override            public void onClick(Component component) {                if (databaseHelper.deletePreferences(filename)) {                    preferences.clear();                    new ToastDialog(context).setText("Delete DB file success").show();                } else {                    new ToastDialog(context).setText("Delete DB file failed").show();                }            }        });    }    /*** * *  cache list  Collection type data  * */    private void btnSavelist() {      btnsavelist.setClickedListener(new Component.ClickedListener() {          @Override          public void onClick(Component component) {              UserBean userBean=new UserBean();              userBean.setUsername("test");              userBean.setPassword("123456");              List<UserBean> datalist=new ArrayList<>();              datalist.add(userBean);              DataBaseUtil.putSelectBean(context,datalist,"datalist");              new ToastDialog(context).setText(" Write successfully ").show();          }      });    }    /*** * *  Call the tool class method to store  */    private void btnSavetoutils() {     btnsave_toutils.setClickedListener(new Component.ClickedListener() {         @Override         public void onClick(Component component) {             String fruit = textFiledFruit.getText();             try {                 int number = Integer.parseInt(textFiledNumber.getText());                 DataBaseUtil.setParam(context,"number",number);                 DataBaseUtil.setParam(context,"fruit",fruit);                 new ToastDialog(context).setText(" Write successfully ").show();             } catch (NumberFormatException e) {                 new ToastDialog(context).setText("Please input number in Number row").show();             }         }     });    }    /*** * *  Read list  Collection type data  * */    private  void  btnReadList(){        btn_read_list.setClickedListener(new Component.ClickedListener() {            @Override            public void onClick(Component component) {                List<UserBean>getData= (List<UserBean>) DataBaseUtil.getSelectBean(context,"datalist");                UserBean userBean= getData.get(0);                new ToastDialog(context).setText(userBean.getUsername()+userBean.getPassword()).show();            }        });    }}
  • 4 bean class
package com.example.datademo.bean;/*** * *  founder :xuqing *  Creation time :2021 year 6 month 20 Japan 20:54:28 *  Class description : User account password  bean class  * * */public class UserBean {    private  String username;    private  String password;    public UserBean() {    }    public UserBean(String username, String password) {        this.username = username;        this.password = password;    }    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password;    }    @Override    public String toString() {        return "UserBean{" +                "username='" + username + '\'' +                ", password='" + password + '\'' +                '}';    }}
  • 4 Tool class core code
package com.example.datademo.utils;import com.example.datademo.bean.UserBean;import com.google.gson.Gson;import com.google.gson.reflect.TypeToken;import ohos.app.Context;import ohos.data.DatabaseHelper;import ohos.data.preferences.Preferences;import java.io.*;import java.lang.reflect.Type;import java.util.List;public class DataBaseUtil {    private static  String filename = "pdb";    private static  Preferences preferences;    private static  DatabaseHelper databaseHelper;    /** *  How to save data , We need to get the specific type of data saved , Then call different save methods according to the type  * * @param context * @param key * @param object * @param :DataBaseUtil.setParam(this, "key", "value"); * key -- userid / accountId obj== */    public static void setParam(Context context, String key, Object object) {        String type = "String";        if (object != null) {            type = object.getClass().getSimpleName();        }        databaseHelper = new DatabaseHelper(context);        preferences = databaseHelper.getPreferences(filename);        if ("String".equals(type)) {            preferences.putString(key, (String) object);        } else if ("Integer".equals(type) || "int".equals(type)) {            preferences.putInt(key, (Integer) object);        } else if ("Boolean".equals(type) || "boolean".equals(type)) {            preferences.putBoolean(key, (Boolean) object);        } else if ("Float".equals(type) || "float".equals(type)) {            preferences.putFloat(key, (Float) object);        } else if ("Long".equals(type) || "long".equals(type)) {            preferences.putLong(key, (Long) object);        }        preferences.flush();    }    /** *  Get a way to save data , We get the specific type of data saved according to the default value , Then call the relative method to get the value.  * * @param context * @param key  keyword  * @param defaultObject  If a null value is retrieved, this default value is returned  * @param :DataBaseUtil.getParam(Activity.this, "key", "defaultValue"); * @return */    public static Object getParam(Context context, String key, Object defaultObject) {        String type = "String";        if (defaultObject != null) {            type = defaultObject.getClass().getSimpleName();        }        databaseHelper = new DatabaseHelper(context);        preferences = databaseHelper.getPreferences(filename);        if ("String".equals(type)) {            return preferences.getString(key, (String) defaultObject);        } else if ("Integer".equals(type) || "int".equals(type)) {            return preferences.getInt(key, (Integer) defaultObject);        } else if ("Boolean".equals(type) || "boolean".equals(type)) {            return preferences.getBoolean(key, (Boolean) defaultObject);        } else if ("Float".equals(type) || "float".equals(type)) {            return preferences.getFloat(key, (Float) defaultObject);        } else if ("Long".equals(type) || "long".equals(type)) {            return preferences.getLong(key, (Long) defaultObject);        }        return null;    }    // Delete data     public static void removeParam(Context context, Object defaultObject) {        databaseHelper = new DatabaseHelper(context);        preferences = databaseHelper.getPreferences(filename);        preferences.clear();    }    /** * 4. Storage list */    public static void putSelectBean(Context context, List<UserBean> phoneList, String key) {        databaseHelper = new DatabaseHelper(context);        preferences = databaseHelper.getPreferences(filename);        Gson gson = new Gson();        String json = gson.toJson(phoneList);        preferences.putString(key, json);        preferences.flush();    }    /** *  Read list */    public static List<UserBean> getSelectBean(Context context, String key) {        databaseHelper = new DatabaseHelper(context);        preferences = databaseHelper.getPreferences(filename);        Gson gson = new Gson();        String json = preferences.getString(key, null);        Type type = new TypeToken<List<UserBean>>() {        }.getType();        List<UserBean> arrayList = gson.fromJson(json, type);        return arrayList;    }    // Save data to SD Inside the card     public static void storetosd(File file, List<UserBean> data) {        try {            Gson gson = new Gson();            String json = gson.toJson(data);            OutputStream os = new FileOutputStream(file);            os.write(json.getBytes("utf-8"));            os.close();        } catch (Exception e) {            e.printStackTrace();        }    }    // Read SD The data in the card     public static List<UserBean> readbysd(File file) {        List<UserBean> arrayList = null;        Gson gson = new Gson();        try {            InputStream is = new FileInputStream(file);            byte[] data = new byte[is.available()];            is.read(data);            String content = new String(data, "utf-8");            Type type = new TypeToken<List<UserBean>>() {            }.getType();            arrayList = gson.fromJson(content, type);            is.close();        } catch (Exception e) {            e.printStackTrace();        }        return arrayList;    }}

Here we are DatabaseHelper Basically finished Congratulations! After reading this article, you will master Hongmeng lightweight database DatabaseHelper The usage and skills of

The final summary

Hongmeng DatabaseHelper Lightweight database and Android sharepreferences Usage and the like are that only basic data types can be stored by default But Hongmeng provided flush and flushSync Two methods take Preferences Instance persistence . flush() Will immediately change the... In memory Preferences object , But updates are written asynchronously to disk .flushSync() Changing the data in memory will synchronously write the data to the disk . because flushSync() It's synchronous , It is not recommended to call it from the main thread , To avoid interface jamming . There are still some differences between this and Android Attention, students . Use up DatabaseHelper It is also more convenient and simple . And how to convert some non basic data types to store them If you are interested, you can download the code to have a look Finally, I hope my article can help you to solve the problem , In the future, I will contribute more useful code to share with you . If you think the article is good , Please pay attention and star, Thank you here !

Project address :

Code cloud :https://gitee.com/qiuyu123/database

原网站

版权声明
本文为[Hua Weiyun]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/160/202206091513574821.html