鸿蒙HarmonyOS应用开发初体验,HarmonyOS鸿蒙进阶学习资料

60 阅读5分钟
  • Page Ability用于提供与用户交互的能力。一个Page可以由一个或多个AbilitySlice构成,AbilitySlice之间可以进行页面导航

image.png

  • PA支持Service Ability和Data Ability:
  • Service Ability:用于提供后台运行任务的能力。
  • Data Ability:用于对外部提供统一的数据访问抽象。

可以感觉到,各种Ability可以对照Android的四大组件来理解

HarmonyAndroid
Page Ability (FA)Activity
Service Ability (PA)Service
Data Ability(PA)ContentProvider
AbilitySliceFragment

代码一览

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的页面效果

MainAbilityListSliceMainAbilityDetailSlice
image.pngimage.png
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而已。

关于模拟器

代码完成后可以再模拟器中运行。关于模拟器有几点想说的:

  1. Harmony的模拟器启动非常快,无需下载镜像,因为这个模拟器并非本地运行,而只是一个远端设备的VNC,因此必须在线使用,而且不够流畅时有丢帧现象。虽然真机调试效果更好,但不是人人都买得起P40的

  2. 模拟器嵌入到IDE窗口显示(像Preview窗口一样),非独立窗口,这会带来一个问题,当同时打开多个IDE时,模拟器可能会显示在另一个IDE中(就像Logcat跑偏一样)。

  3. 想使用模拟器必须进过开发者认证,官方推荐使用银行卡认证。模拟器远端链接的是一台真实设备,难道是为未来租用设备要计费??image.png记得以前看过一篇文章,如果是来自国外地区的注册账号可以免认证使用模拟器,但是懒得折腾了

3. 开发JS应用


除了Java,鸿蒙还支持基于JS开发应用,借助前端技术完善其跨平台能力。

鸿蒙为JS工程提供了多种常用UI组件,但是没有采用当下主流的react、vue那样JS组件,仍然是基于CSS3/HTML5/JS这种传统方式进行开发。JS工程结构如下

image.png

目录说明
common可选,用于存放公共资源文件,如媒体资源、自定义组件和JS文档等
i18n可选,用于存放多语言的json文件
pages/index/index.hmlhml文件定义了页面的布局结构,使用到的组件,以及这些组件的层级关系
pages/index/index.csscss文件定义了页面的样式与布局,包含样式选择器和各种样式属性等
pages/index/index.jsjs文件描述了页面的行为逻辑,此文件里定义了页面里所用到的所有的逻辑关系,比如数据、事件等
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接口。

Note: 一个应用可能包含多个Page,仅需要在支持迁移的Page中通过以下方法实现IAbilityContinuation接口。同时,此Page所包含的所有AbilitySlice也需要实现此接口。

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; } } public class MailEditSlice extends AbilitySlice implements IAbilityContinuation { ... @Override public boolean onStartContinuation() { LogUtil.info(TAG, "is start continue"); return true; }

@Override public boolean onSaveData(IntentParams params) { ... LogUtil.info(TAG, "begin onSaveData:" + mailData); ... LogUtil.info(TAG, "end onSaveData"); return true; }

@Override public boolean onRestoreData(IntentParams params) { LogUtil.info(TAG, "begin onRestoreData"); ... LogUtil.info(TAG, "end onRestoreData, mail data: " + cachedMailData); return true; }

img img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!