创建默认工程
创建工程时注意这里
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; } }
此时运行发现还是会无法访问,这是因为网络权限没有打开