创建默认工程
创建工程时注意这里
service是不会在本地安装APP的
所以在选择service 时你在调试设备时时桌面时不会有图标的
通过下面这个位置我们可以启动自己的鸿蒙环境
然后看下我们的配置文件夹
找到main文件夹,其中config.json是我们的配置文件
具体可以查看
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>
我们看到这里引用了select_border.xml这个文件
<?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;
}
}
此时运行发现还是会无法访问,这是因为网络权限没有打开