| mainability | mainactivity | 入口页。鸿蒙中将四大组件的概念统一成ability
|
| mainabilitylistslice | xxxfragment | slice
类似fragment,ui的基本组成单元 |
| component | view | component
类相当于view,后文介绍 |
| config.json | androidmanifest.xml | 鸿蒙使用json替代xml进行manifest配置,配置项目差不多 |
| resources/base/… | res/… | 包括layout文件在内的各种资源文件依旧使用xml |
| resources/rawfile/ | assets/ | rawfile存储任意格式原始资源,相当于assets |
| build.gradle | build.gradle | 编译脚本,两者一样 |
| build/outpus/…/*.hap | build/outputs/…/*.apk | 鸿蒙的产物是hap(harmony application package)
解压后里面有一个同名的.apk文件,
这后续是因为鸿蒙需要同时支持apk安装的兼容方案 |
ability
ability是应用所具备能力的抽象,harmony支持应用以ability为单位进行部署。一个应用由一个或多个fa(feature ability)或pa(particle ability)组成。fa有ui界面,提供与用户交互的能力;而pa无ui界面,提供后台运行任务的能力以及统一的数据访问抽象
- fa支持page ability:
- page ability用于提供与用户交互的能力。一个page可以由一个或多个abilityslice构成,abilityslice之间可以进行页面导航
- pa支持service ability和data ability:
- service ability:用于提供后台运行任务的能力。
- data ability:用于对外部提供统一的数据访问抽象。
可以感觉到,各种ability可以对照android的四大组件来理解
harmony | android |
---|---|
page ability (fa) | activity |
service ability (pa) | service |
data ability(pa) | contentprovider |
abilityslice | fragment |
代码一览
mainability
以预置的news feature ability为例子,这是一个拥有两个slice的page ability,通过router注册两个slice
public class mainability extends ability {
@override
public void onstart(intent intent) {
super.onstart(intent);
super.setmainroute(mainabilitylistslice.class.getname()); //添加路由:listslice
addactionroute(“action.detail”, mainabilitydetailslice.class.getname());//detailslice
…
}
}
以下是在模拟器中运行两个slice的页面效果
mainabilitylistslice | mainabilitydetailslice |
---|---|
![]() | ![]() |
mainabilitylistslice
主要看一下列表的显示逻辑
public class mainabilitylistslice extends abilityslice {
…
@override
public void onstart(intent intent) {
super.onstart(intent);
super.setuicontent(resourcetable.layout_news_list_layout);
initview();
initdata(); //加载数据
initlistener();
newslistcontainer.setitemprovider(newslistadapter); //adatper设置到view
newslistadapter.notifydatachanged(); //刷新数据
}
private void initlistener() {
newslistcontainer.setitemclickedlistener((listcontainer, component, i, l) -> {
//路由跳转"action.detail"
logutil.info(tag, “onitemclicked is called”);
intent intent = new intent();
operation operation = new intent.operationbuilder()
.withbundlename(getbundlename())
.withabilityname(“com.example.myapplication.mainability”)
.withaction(“action.detail”)
.build();
intent.setoperation(operation);
startability(intent);
});
}
private void initdata() {
…
totalnewsdatas = new arraylist<>();
newsdatas = new arraylist<>();
initnewsdata();//填充newsdatas
newslistadapter = new newslistadapter(newsdatas, this);//设置到adapter
}
…
}
类似listview
的用法,通过adatper加载数据; setitemclickedlistener
中通过路由跳转mainabilitydetailslice。
layout_news_list_layout
布局文件定义如下,listcontainer
即listview,是comopnent的一个子类,component
就是harmonyos中的view
看一下adapter的实现, 继承自baseitemprovider
/**
- news list adapter
*/
public class newslistadapter extends baseitemprovider {
private list newsinfolist;
private context context;
public newslistadapter(list listbasicinfo, context context) {
this.newsinfolist = listbasicinfo;
this.context = context;
}
@override
public int getcount() {
return newsinfolist == null ? 0 : newsinfolist.size();
}
@override
public object getitem(int position) {
return optional.of(this.newsinfolist.get(position));
}
@override
public long getitemid(int position) {
return position;
}
@override
public component getcomponent(int position, component componentp, componentcontainer componentcontainer) {
viewholder viewholder = null;
component component = componentp;
if (component == null) {
component = layoutscatter.getinstance(context).parse(resourcetable.layout_item_news_layout, null, false);
viewholder = new viewholder();
component componenttitle = component.findcomponentbyid(resourcetable.id_item_news_title);
component componentimage = component.findcomponentbyid(resourcetable.id_item_news_image);
if (componenttitle instanceof text) {
viewholder.title = (text) componenttitle;
}
if (componentimage instanceof image) {
viewholder.image = (image) componentimage;
}
component.settag(viewholder);
} else {
if (component.gettag() instanceof viewholder) {
viewholder = (viewholder) component.gettag();
}
}
if (null != viewholder) {
viewholder.title.settext(newsinfolist.get(position).gettitle());
viewholder.image.setscalemode(image.scalemode.stretch);
}
return component;
}
/**
- viewholder which has title and image
*/
private static class viewholder {
text title;
image image;
}
}
基本上就是标准的listadatper,把view替换成component而已。
关于模拟器
代码完成后可以再模拟器中运行。关于模拟器有几点想说的:
-
harmony的模拟器启动非常快,无需下载镜像,因为这个模拟器并非本地运行,而只是一个远端设备的vnc,因此必须在线使用,而且不够流畅时有丢帧现象。虽然真机调试效果更好,但不是人人都买得起p40的
-
模拟器嵌入到ide窗口显示(像preview窗口一样),非独立窗口,这会带来一个问题,当同时打开多个ide时,模拟器可能会显示在另一个ide中(就像logcat跑偏一样)。
-
想使用模拟器必须进过开发者认证,官方推荐使用银行卡认证。模拟器远端链接的是一台真实设备,难道是为未来租用设备要计费??
记得以前看过一篇文章,如果是来自国外地区的注册账号可以免认证使用模拟器,但是懒得折腾了
3. 开发js应用
除了java,鸿蒙还支持基于js开发应用,借助前端技术完善其跨平台能力。
鸿蒙为js工程提供了多种常用ui组件,但是没有采用当下主流的react、vue那样js组件,仍然是基于css3/html5/js这种传统方式进行开发。js工程结构如下
目录 | 说明 |
---|---|
common | 可选,用于存放公共资源文件,如媒体资源、自定义组件和js文档等 |
i18n | 可选,用于存放多语言的json文件 |
pages/index/index.hml | hml文件定义了页面的布局结构,使用到的组件,以及这些组件的层级关系 |
pages/index/index.css | css文件定义了页面的样式与布局,包含样式选择器和各种样式属性等 |
pages/index/index.js | js文件描述了页面的行为逻辑,此文件里定义了页面里所用到的所有的逻辑关系,比如数据、事件等 |
resources | 可选,用于存放资源配置文件,比如:全局样式、多分辨率加载等配置文件 |
app.js | 全局的javascript逻辑文件和应用的生命周期管理。 |
4. 跨设备迁移
通过前面的介绍,可能感觉和android大同小异,但是harmonyos最牛逼之处是多端协作能力,例如可以将page在同一用户的不同设备间迁移,实现无缝切换。
以page从设备a迁移到设备b为例,迁移动作主要步骤如下:
- 设备a上的page请求迁移。
- harmonyos回调设备a上page的保存数据方法,用于保存迁移必须的数据。
- harmonyos在设备b上启动同一个page,并回调其恢复数据方法。
通过调用continueability()
请求迁移。如下,获取设备列表,配对成功后请求迁移
doconnectimg.setclickedlistener(
clickedview -> {
// 通过flag_get_online_device标记获得在线设备列表
list deviceinfolist = devicemanager.getdevicelist(deviceinfo.flag_get_online_device);
if (deviceinfolist.size() < 1) {
widgethelper.showtips(this, “无在网设备”);
} else {
deviceselectdialog dialog = new deviceselectdialog(this);
// 点击后迁移到指定设备
dialog.setlistener(
deviceinfo -> {
logutil.debug(tag, deviceinfo.getdevicename());
logutil.info(tag, “continue button click”);
try {
// 开始任务迁移
continueability();
logutil.info(tag, “continue button click end”);
} catch (illegalstateexception | unsupportedoperationexception e) {
widgethelper.showtips(this, resourcetable.string_tips_mail_continue_failed);
}
dialog.hide();
});
dialog.show();
}
});
page迁移涉及到数据传递,此时需要借助iabilitycontinuation
进行通信。
跨设备通信 iabilitycontinuation
跨设备迁移的page需要实现iabilitycontinuation
接口。
public class mainability extends ability implements iabilitycontinuation {
…
@override
public void oncompletecontinuation(int code) {}
@override
public boolean onrestoredata(intentparams params) {
return true;
}
@override
public boolean onsavedata(intentparams params) {
return true;
}
@override
public boolean onstartcontinuation() {
return true;
}
设计模式学习笔记
设计模式系列学习视频
《android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,,即可获取!
rams) {
return true;
}
@override
public boolean onstartcontinuation() {
return true;
}
设计模式学习笔记
[外链图片转存中…(img-nkmpww0g-1715435723744)]
设计模式系列学习视频
[外链图片转存中…(img-cqs6ippk-1715435723745)]
《android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,,即可获取!
发表评论