HarmonyOS开发入门笔记 在线词典

简介: HarmonyOS开发入门笔记 在线词典

创建默认工程

创建工程时注意这里

service是不会在本地安装APP的

所以在选择service 时你在调试设备时时桌面时不会有图标的 image.png

通过下面这个位置我们可以启动自己的鸿蒙环境

image.png

然后看下我们的配置文件夹

image.png

找到main文件夹,其中config.json是我们的配置文件

image.png

具体可以查看

https://harmonyos.51cto.com/posts/7621

界面开发

<?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:alignment="center"
    ohos:orientation="vertical">
    <!--  缩窄两侧 和 上部  -->
    <DirectionalLayout
        ohos:height="match_parent"
        ohos:width="match_parent"
        ohos:left_margin="20vp"
        ohos:right_margin="20vp"
        ohos:top_margin="40vp"
        ohos:background_element="#FFFAFA"
        ohos:orientation="vertical">
        <!--上半部分-->
        <DirectionalLayout
            ohos:height="50vp"
            ohos:width="match_parent"
            ohos:orientation="horizontal">
            <!--左侧文本框-->
            <!--        weight代表权重 设置此值之后 会线让其他元素填充区域后占满剩余区域 -->
            <!--        padding 内边距-->
            <!--        ohos:background_element="$graphic:select_border" 设置背景 这里使用了xml配置 通过xml可以设置边框等  也可以不使用xml直接赋给颜色值-->
            <TextField
                ohos:id="$+id:textField_ID"
                ohos:height="match_content"
                ohos:width="match_parent"
                ohos:hint="请输入要查找的单词"
                ohos:weight="1"
                ohos:background_element="$graphic:select_border"
                ohos:padding="2vp"
                ohos:text_size="20vp"
                ohos:hint_color="#FF4500"/>
            <!--右侧搜索按钮-->
            <Image
                ohos:id="$+id:sou_word"
                ohos:height="23vp"
                ohos:width="23vp"
                ohos:image_src="$media:sou"
                ohos:scale_mode="zoom_center"/>
        </DirectionalLayout>
        <!--搜索结果-->
<!--        layout_alignment="left|top"  文本对齐方式:左上角-->
<!--            visibility="hide"  设置隐藏-->
        <Text
            ohos:id="$+id:text_select_return"
            ohos:height="match_content"
            ohos:width="match_content"
            ohos:multiple_lines="true"
            ohos:background_element="$graphic:background_ability_main"
            ohos:visibility="hide"
            ohos:top_margin="40"
            ohos:layout_alignment="left|top"
            ohos:text_size="20vp"
            />
        <Image
            ohos:id="$+id:image"
            ohos:height="match_parent"
            ohos:width="match_parent"
            ohos:top_margin="60vp"
            ohos:image_src="$media:OIP_C"
            ohos:scale_mode="zoom_center"/>
    </DirectionalLayout>
</DirectionalLayout>

image.png

我们看到这里引用了select_border.xml这个文件

image.png

<?xml version="1.0" encoding="UTF-8" ?>
<shape xmlns:ohos="http://schemas.huawei.com/res/ohos"
       ohos:shape="rectangle">
    <solid
        ohos:color="#FFFFFF"/>
    <stroke
        ohos:color="#00FFFF"
        ohos:width="1vp"
        />
</shape>

主要配置了边框和背景色

底层部分

这里先贴出鸿蒙官方的api开发文档

https://developer.harmonyos.com/cn/docs/documentation/doc-references/component-0000001054678683

爬取单词,封装sql

我们先从网站上爬出词库,并封装成sqlite

这里使用py来爬取

import os.path
import sqlite3
import requests
import re
words = {}
def add_word(word_line):
    global words
    result = re.split('[a-z]+\.',word_line)
    pattern = re.compile('[a-z]+\.')
    result2 = pattern.findall(word_line)
    word = result[0].strip()
    meanings = {}
    for i in range(0,len(result2)):
        key = result2[i].strip()
        value = result[i+1].strip()
        meanings[key] = value
    words[word] = meanings
r = requests.get('https://www.eol.cn/html/en/cetwords/cet4.shtml')
html = r.content
html_doc = str(html, 'utf-8')
print(html_doc)
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
tags = soup.find_all(attrs={'class': 'wordL fl'})
for tag in tags:
    p_list = tag.select('p')
    for p in p_list:
        add_word(p.text)
print(words)
print('单词抓取完毕')
db_path = 'dict.sqlite'
if os.path.exists(db_path):
    os.remove(db_path)
conn = sqlite3.connect(db_path)
c = conn.cursor()
c.execute('''create table words
    (id int primary key not null,
    word varchar(30) not null,
    type  varchar(10) not null,
    meanings text not null);
    ''')
c.execute('create index word_index on words(word)')
conn.commit()
conn.close()
print("数据库创建完毕")
conn = sqlite3.connect(db_path)
c = conn.cursor()
i = 1
for word in words:
    value = words[word]
    for type in value:
        meanmings = value[type]
        sql = f'insert into words(id,word,type,meanings) values ( {i},"{word}","{type}","{meanmings}" )'
        c.execute(sql)
        print(sql)
        i += 1
    conn.commit()
conn.close()
print("生成完毕")

这时我们就得到了sqlite

sqlite文件操作类

我们在鸿蒙项目里创建sqlite类

package com.example.onlinedict.common;
import ohos.app.AbilityContext;
import ohos.data.DatabaseHelper;
import ohos.data.rdb.RdbOpenCallback;
import ohos.data.rdb.RdbStore;
import ohos.data.rdb.StoreConfig;
import ohos.global.resource.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Paths;
public class MyDict {
    //AbilityContext 是一个 Context 类,其功能是与系统环境进行交互,可以获取和改变一些与应用有关的属性值。
    private AbilityContext context;
    //词典数据库文件路径
    private File dictPath;
    //词典数据库文件
    private File dbPath;
    //鸿蒙数据库https://blog.csdn.net/dsbdsbdsb/article/details/112603421  及  https://harmonyos.51cto.com/posts/8013
    //数据
    private RdbStore rdbStore;
    private StoreConfig storeConfig=StoreConfig.newDefaultConfig("dict.sqlite");
    //创建数据库需要的回调  虽然这回调啥都不用写 但是需要有
    private static final RdbOpenCallback callback = new RdbOpenCallback() {
        @Override
        public void onCreate(RdbStore rdbStore) {
        }
        @Override
        public void onUpgrade(RdbStore rdbStore, int i, int i1) {
        }
    };
    //创建HAP私有路径
    public MyDict(AbilityContext context) {
        this.context = context;
        dictPath = new File(context.getDataDir().toString()+"/MainAbility/databases/db");
        if (!dictPath.exists()){//如果路径不存在就创建路径
            dictPath.mkdirs();
        }
        //获取文件
        dbPath = new File(Paths.get(dictPath.toString(),"dict.sqlite").toString());
    }
    //读取数据库文件拷贝到私有路径
    private void extractDB() throws IOException{
        //加载资源
        Resource resource = context.getResourceManager().getRawFileEntry("resources/rawfile/dict.sqlite").openRawFile();
        //如果路径为空 则删除  我也不知道为啥要写这个
        if (dbPath.exists()){
            dbPath.delete();
        }
        //输出流创建sqlite文件
        FileOutputStream fileOutputStream = new FileOutputStream(dbPath);
        //用于读取
        byte[] buffer = new byte[4096];
        int count = 0;
        while ((count=resource.read(buffer))>0){
            //将数组内容输出到文件中
            fileOutputStream.write(buffer,0,count);
        }
        resource.close();
        fileOutputStream.close();
    }
    //初始化
    public void init() throws IOException{
        //创建数据库
        extractDB();
        //打开数据库
        //数据库操作的辅助类
        DatabaseHelper helper = new DatabaseHelper(context);
        rdbStore = helper.getRdbStore(storeConfig,1,callback);
    }
}

调用初始化,添加前端监听事件

更改MainAbilitySlice文件

package com.example.onlinedict.slice;
import com.example.onlinedict.ResourceTable;
import com.example.onlinedict.common.MyDict;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Component;
import ohos.agp.components.Image;
import ohos.agp.components.Text;
import ohos.agp.components.TextField;
import java.io.IOException;
public class MainAbilitySlice extends AbilitySlice {
    private MyDict myDict;
    private Image imageSearch;
    private Text textSelectReturn;
    private TextField textField_ID;
    private Image image;
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);
        myDict = new MyDict(this);
        try {
            myDict.init();
        } catch (IOException e) {
            e.printStackTrace();
        }
        imageSearch = (Image) findComponentById(ResourceTable.Id_sou_word);
        textSelectReturn = (Text) findComponentById(ResourceTable.Id_text_select_return);
        textField_ID = (TextField) findComponentById(ResourceTable.Id_textField_ID);
        image = (Image) findComponentById(ResourceTable.Id_image);
        if (imageSearch!=null){
            imageSearch.setClickable(true);
            imageSearch.setClickedListener(new Component.ClickedListener() {
                @Override
                public void onClick(Component component) {
                    image.setVisibility(Component.HIDE);//下面图像不可见
                    textSelectReturn.setVisibility(Component.VISIBLE);
                    String s = textField_ID.getText();//获取文字
                }
            });
        }
    }
    @Override
    public void onActive() {
        super.onActive();
    }
    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }
}

此时运行就可以实现点击搜索按钮下方图片隐藏

添加查询本地单词功能

为MyDict类添加方法

    /**
     * 搜索单词
     * @param word
     * @return
     */
    public List<DictBean> searchLocalWord(String word){
        //将其全部转换为小写
        word = word.toLowerCase();
        String[] args = new String[]{word};
        ResultSet resultSet = rdbStore.querySql("select * from words where word = ?",args);
        ArrayList<DictBean> dictBeans = new ArrayList<DictBean>();
        while (resultSet.goToNextRow()){
            DictBean dictBean = new DictBean();
            dictBean.setType(resultSet.getString(2));
            dictBean.setChineseWord(resultSet.getString(3));
            dictBeans.add(dictBean);
        }
        resultSet.close();
        return dictBeans;
    }

之后将监听器内的代码更改一下

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);
        //初始化本地词典
        myDict = new MyDict(this);
        try {
            myDict.init();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //获取前端控件的对象
        imageSearch = (Image) findComponentById(ResourceTable.Id_sou_word);
        textSelectReturn = (Text) findComponentById(ResourceTable.Id_text_select_return);
        textField_ID = (TextField) findComponentById(ResourceTable.Id_textField_ID);
        image = (Image) findComponentById(ResourceTable.Id_image);
        //添加搜索按钮监听
        if (imageSearch!=null){
            imageSearch.setClickable(true);
            imageSearch.setClickedListener(new Component.ClickedListener() {
                @Override
                public void onClick(Component component) {
                    selectWord();
                }
            });
        }
//        //添加文本框变更的监听器
//        textField_ID.addTextObserver(new Text.TextObserver() {
//            @Override
//            public void onTextUpdated(String s, int i, int i1, int i2) {
//                selectWord();
//            }
//        });
    }
  public void selectWord(){
        image.setVisibility(Component.HIDE);//下面图像不可见
        textSelectReturn.setVisibility(Component.VISIBLE);
        String s = textField_ID.getText();//获取文字
        List<DictBean> dictBeans = myDict.searchLocalWord(s);//获取list
        textSelectReturn.setText("");
        if (!dictBeans.isEmpty()){
            for (int i = 0; i < dictBeans.size(); i++) {
                textSelectReturn.append(dictBeans.get(i).getType()+" "+dictBeans.get(i).getChineseWord()+"\r\n");//添加文本内容
            }
        }
        else{
            textSelectReturn.setText("本地词库不存在此单词");
            myDict.searchWebWord(s,new SearchWordCallBackimpl());
        }
    }

添加网络爬虫搜索单词的功能

首先创建一个回调的接口ISearchWordCallBack

package com.example.onlinedict.common;
import com.example.onlinedict.common.bean.DictBean;
import java.util.List;
public interface ISearchWordCallBack {
    void onResult(List<DictBean> result);
}

之后创建线程类AsyncSearchWord

这里创建线程类的原因:主线程是ui线程 如果ui线程堵塞则程序会卡死,所以要再重新创建线程来在网络上查询

注意:这里用到了Jsoup这个jar包

package com.example.onlinedict.common;
import com.example.onlinedict.common.bean.DictBean;
import ohos.data.rdb.RdbStore;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.List;
class AsyncSearchWord extends Thread{
    private String word;
    private RdbStore rdbStore;
    private ISearchWordCallBack callBack;
    public AsyncSearchWord(String word,RdbStore rdbStore,ISearchWordCallBack callBack){
        this.word = word;
        this.callBack = callBack;
        this.rdbStore = rdbStore;
    }
    @Override
    public void run() {
        try{
            HiLogLabel label = new HiLogLabel(HiLog.LOG_APP ,223, "MY_RUN");
            //获取html
            String url="https://www.iciba.com/word?w=" + word;
            HiLog.warn(label, url+"/");
            Document document = Jsoup.connect(url).get();
            Elements ul = document.getElementsByClass("Mean_part__1Xi6p");
//            String sql = "insert into word(word ,type ,meanings ) values(?,?,?);";
            List<DictBean> dictBeans = new ArrayList<DictBean>();
            for (Element element : ul){
                //获取词义和词性
                Elements lis = element.getElementsByTag("li");
                HiLog.warn(label, lis.text()+"/listext");
                for (Element li:lis){
                    DictBean dictBean = new DictBean();
                    //词性
                    Elements itags = li.getElementsByTag("i");
                    for (Element itag:itags){
                        dictBean.setType(itag.text());
                        break;
                    }
                    //词义
                    Elements divs = li.getElementsByTag("div");
                    for (Element div :divs){
                        dictBean.setChineseWord(div.text());
                        break;
                    }
                    dictBeans.add(dictBean);
                    HiLog.warn(label, dictBean.toString()+"/");
//                    rdbStore.executeSql(sql,new String[]{word,dictBean.getType(),dictBean.getChineseWord()});
                }
                break;
            }
            if (callBack!=null){
                callBack.onResult(dictBeans);
            }
        }
        catch (Exception e){
            HiLogLabel label = new HiLogLabel(HiLog.LOG_APP ,223, "MY_errwo");
            HiLog.error(label, e.toString());
            e.printStackTrace();
        }
    }
}

在MyDict类中添加网络查询的方法,用于开启线程

    public void searchWebWord(String word , ISearchWordCallBack callBack){
        word = word.toLowerCase();
        HiLogLabel label = new HiLogLabel(HiLog.LOG_APP ,223, "MY_TAG");
        HiLog.error(label, word+"//");
        //异步搜索
        new AsyncSearchWord(word,rdbStore,callBack).start();
    }

添加MyEventHandler类负责主线程与网络线程的通信

 private class  MyEventHandler extends EventHandler {
        private List<DictBean> dictBeans;
        public MyEventHandler(EventRunner runner,List<DictBean> dictBeans) throws IllegalArgumentException {
            super(runner);
            this.dictBeans=dictBeans;
        }
        @Override
        protected void processEvent(InnerEvent event) {
            super.processEvent(event);
            if (event==null){
                return;
            }
            int eventid = event.eventId;
            switch (eventid){
                case SEARCH_RESULT:{
                    if (dictBeans.size()==0){
                        textSelectReturn.setText("单词不存在");
                    }
                    else {
                        textSelectReturn.setText("");
                        for (int i = 0; i < dictBeans.size(); i++) {
                            textSelectReturn.append(dictBeans.get(i).getType()+" "+dictBeans.get(i).getChineseWord()+"\r\n");//添加文本内容
                        }
                    }
                    break;
                }
            }
        }
    }

创建回调的实现类

    private class SearchWordCallBackimpl implements ISearchWordCallBack{
        @Override
        public void onResult(List<DictBean> result) {
            //得到主线程
            EventRunner runner = EventRunner.getMainEventRunner();
            MyEventHandler eventHandler = new MyEventHandler(runner,result);
            eventHandler.sendEvent(SEARCH_RESULT);
            runner = null;
        }
    }

image.png

此时运行发现还是会无法访问,这是因为网络权限没有打开

image.png


相关文章
|
8月前
|
IDE JavaScript API
HarmonyOS开发第一步,熟知开发工具DevEco Studio
本文主要以常见的功能点作为概述希望可以帮助到学习HarmonyOS的开发者。
215 0
|
8月前
|
开发框架 API 开发者
HarmonyOS学习路之方舟开发框架—学习ArkTS语言(基本语法 二)
在ArkUI中,UI显示的内容均为组件,由框架直接提供的称为系统组件,由开发者定义的称为自定义组件。在进行 UI 界面开发时,通常不是简单的将系统组件进行组合使用,而是需要考虑代码可复用性、业务逻辑与UI分离,后续版本演进等因素。因此,将UI和部分业务逻辑封装成自定义组件是不可或缺的能力。
|
2月前
|
存储 JavaScript 前端开发
【HarmonyOS 4.0 应用开发实战】TypeScript入门之元组详讲
【HarmonyOS 4.0 应用开发实战】TypeScript入门之元组详讲
40 0
|
2月前
|
JavaScript 前端开发
【HarmonyOS 4.0 应用开发实战】TypeScript入门之模块化详讲
【HarmonyOS 4.0 应用开发实战】TypeScript入门之模块化详讲
30 0
|
2月前
|
JavaScript 前端开发 索引
【HarmonyOS 4.0 应用开发实战】TypeScript入门之接口详讲
【HarmonyOS 4.0 应用开发实战】TypeScript入门之接口详讲
37 0
|
2月前
|
JavaScript
【HarmonyOS 4.0 应用开发实战】TypeScript入门之声明、数据类型、函数、类的详讲
【HarmonyOS 4.0 应用开发实战】TypeScript入门之声明、数据类型、函数、类的详讲
44 0
|
3月前
|
数据管理 API 调度
【华为鸿蒙系统学习】- HarmonyOS4.0开发|自学篇
【华为鸿蒙系统学习】- HarmonyOS4.0开发|自学篇
204 0
|
3月前
|
前端开发 JavaScript 开发者
鸿蒙2.0!用 JavaScript 开发鸿蒙应用
鸿蒙2.0!用 JavaScript 开发鸿蒙应用
|
3月前
|
开发者 索引 容器
【鸿蒙软件开发】Stage模型开发概述应用/组件级配置
【鸿蒙软件开发】Stage模型开发概述应用/组件级配置
109 0
【鸿蒙软件开发】Stage模型开发概述应用/组件级配置
|
3月前
|
人工智能 安全 开发者
中国移动APP启动鸿蒙原生应用开发,鸿蒙生态迎来通信领域民生应用
近日,在“鸿蒙生态全面合作签约暨开发启动仪式“上,中国移动通信有限公司在线营销服务中心宣布将与鸿蒙生态在技术互补、成果共享、商业共赢等方向进行合作,以共同推动鸿蒙智能化的移动开放生态业务发展,并正式启动中国移动APP鸿蒙原生应用及元服务开发。