HarmonyOS 项目实战之通讯录(Java)
Posted 柒柒Java
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HarmonyOS 项目实战之通讯录(Java)相关的知识,希望对你有一定的参考价值。
1 简介
通讯录demo主要分为联系人界面、设置紧急联系人、服务卡片3个模块,分为Java和JS两个版本,本篇主要讲解用尽可能的用Java去实现。
1.1 原型
感兴趣的小伙伴,可以自己根据原型效果自己尝试着去实现【通讯录demo简易原型】
1.2 场景示例
通过学习与练习本demo,可以延伸至以下场景
1.3 项目实战
《HarmonyOS 项目实战之通讯录Demo(JS)》
《HarmonyOS 项目实战之通讯录(Java)》
《HarmonyOS 项目实战之新闻头条(ArkUI-TS》
2 功能开发
2.1 联系人列表
2.1.1 实现效果
2.1.2 核心代码
参考:ListContainer-常用组件开发指导-Java UI框架-UI-开发-HarmonyOS应用开发
- ListContainer设置StickyContactProvider适配器
- HeaderDecor头部联动效果设置
- ContactData数据处理相关类,sortContactData方法用于排序等数据处理
ContactData categoryData = ContactData.get(); categoryData.sortContactData(); contactList = (ListContainer) findComponentById(ResourceTable.Id_contactList); Text headerText = (Text) findComponentById(ResourceTable.Id_sticky_text); List<ContactBean> dataList = categoryData.getResultList(); mStickyContactProvider = new StickyContactProvider(this, dataList); contactList.setItemProvider(mStickyContactProvider); HeaderDecor headerDecor = new HeaderDecor(contactList, headerText);
sortContactData方法数据处理,排序,字母索引:
public void sortContactData() List<ContactBean> mContactList = new ArrayList<>(); Map<String, String> map = new HashMap<>(); for (ContactBean contactBean : mContactBeans) String pinyin = Utils.getPingYin(contactBean.getName()); map.put(pinyin, contactBean.getName()); contactBean.setNamepy(pinyin); mContactList.add(contactBean); mContactList.sort(new ContactComparator()); characterList = new ArrayList<>(); resultList = new ArrayList<>(); for (ContactBean contactBean : mContactList) String namepy = contactBean.getNamepy(); String character = (namepy.charAt(0) + "").toUpperCase(Locale.ENGLISH); if (!characterList.contains(character)) if (character.hashCode() >= "A".hashCode() && character.hashCode() <= "Z".hashCode()) // 是字母 characterList.add(character); resultList.add(new ContactBean(character, ContactBean.ITEM_TYPE.ITEM_TYPE_CHARACTER.ordinal())); else if (!characterList.contains("#")) characterList.add("#"); resultList.add(new ContactBean("#", ContactBean.ITEM_TYPE.ITEM_TYPE_CHARACTER.ordinal())); resultList.add(new ContactBean(contactBean.getName(), contactBean.getTelephone(), map.get(namepy), ContactBean.ITEM_TYPE.ITEM_TYPE_CONTACT.ordinal()));
2.2 数据的增删改查
2.2.1 实现效果
2.2.2 增删改查实现
ListContainer删除实现
categoryData.deleteContactBeans(item); categoryData.sortContactData(); mStickyContactProvider.setDataListChanged(categoryData.getResultList());
随机添加一个联系人
categoryData.addContactBean("胡六一", "15269856587"); categoryData.sortContactData(); mStickyContactProvider.setDataListChanged(categoryData.getResultList());
ContactData数据处理效果类,实现数据增删改查
// Generate the javaBean of ContactData public static ContactData get() return new ContactData(); public List<ContactBean> getDefaultContactBeans() return mDefaultContactBeans; public List<ContactBean> getContactBeans() return mContactBeans; public void addContactBean(String name, String phone) mContactBeans.add(new ContactBean(name, phone)); public List<ContactBean> deleteContactBeans(ContactBean item) mContactBeans.removeIf(contactBean -> contactBean.getName().equals(item.getName())); return mContactBeans; public List<ContactBean> getResultList() return resultList; public List<String> getCharacterList() return characterList; public int getScrollPosition(String character) if (characterList.contains(character)) for (int i = 0; i < resultList.size(); i++) if (resultList.get(i).getCharacter().equals(character)) return i; return -1; // -1不会滑动
2.2.3 紧急联系人数据存储
轻量级数据存储:轻量级数据存储概述-轻量级数据存储-数据管理-开发-HarmonyOS应用开发
Key-Value数据结构
一种键值结构数据类型。Key是不重复的关键字,Value是数据值。
运作机制
- 本模块提供轻量级数据存储的操作类,应用通过这些操作类完成数据库操作。
- 借助DatabaseHelper API,应用可以将指定文件的内容加载到Preferences实例,每个文件最多有一个Preferences实例,系统会通过静态容器将该实例存储在内存中,直到应用主动从内存中移除该实例或者删除该文件。
- 获取到文件对应的Preferences实例后,应用可以借助Preferences API,从Preferences实例中读取数据或者将数据写入Preferences实例,通过flush或者flushSync将Preferences实例持久化。
核心代码实现
添加紧急联系人,并通知java卡片更新
ZSONObject zsonObject = new ZSONObject(); zsonObject.put("urgent1", nameTf1.getText()); zsonObject.put("urgentPhone1", phoneTf1.getText()); zsonObject.put("urgent2", nameTf2.getText()); zsonObject.put("urgentPhone2", phoneTf2.getText()); PreferenceUtils.putString(getContext(),"urgentPerson", ZSONObject.toZSONString(zsonObject)); FormBindingData formBindingData = new FormBindingData(zsonObject); ((ContactPersonAbility) getAbility()).confirmUpdateForm(formBindingData);
PreferenceUtils封装工具类,实现数据存储
public class PreferenceUtils private static String PREFERENCE_FILE_NAME = "prefrence_file"; private static Preferences preferences; private static DatabaseHelper databaseHelper; private static Preferences.PreferencesObserver mPreferencesObserver; private static void initPreference(Context context) if (databaseHelper == null) databaseHelper = new DatabaseHelper(context); if (preferences == null) preferences = databaseHelper.getPreferences(PREFERENCE_FILE_NAME); //存放、获取时传入的context必须是同一个context,否则存入的数据无法获取 public static void putString(Context context, String key, String value) initPreference(context); preferences.putString(key, value); preferences.flush(); /** * @param context 上下文 * @param key 键 * @return 获取的String 默认值为:null */ public static String getString(Context context, String key) initPreference(context); return preferences.getString(key, null); public static String getString(Context context, String key, String d) initPreference(context); return preferences.getString(key, d); public static void putInt(Context context, String key, int value) initPreference(context); preferences.putInt(key, value); preferences.flush(); /** * @param context 上下文 * @param key 键 * @return 获取int的默认值为:-1 */ public static int getInt(Context context, String key) initPreference(context); return preferences.getInt(key, -1); public static void putLong(Context context, String key, long value) initPreference(context); preferences.putLong(key, value); preferences.flush(); /** * @param context 上下文 * @param key 键 * @return 获取long的默认值为:-1 */ public static long getLong(Context context, String key) initPreference(context); return preferences.getLong(key, -1L); public static void putBoolean(Context context, String key, boolean value) initPreference(context); preferences.putBoolean(key, value); preferences.flush(); /** * @param context 上下文 * @param key 键 * @return 获取boolean的默认值为:false */ public static boolean getBoolean(Context context, String key) initPreference(context); return preferences.getBoolean(key, false); public static void putFloat(Context context, String key, float value) initPreference(context); preferences.putFloat(key, value); preferences.flush(); /** * @param context 上下文 * @param key 键 * @return 获取float的默认值为:0.0 */ public static float getFloat(Context context, String key) initPreference(context); return preferences.getFloat(key, 0.0F); public static void putStringSet(Context context, String key, Set<String> set) initPreference(context); preferences.putStringSet(key, set); preferences.flush(); /** * @param context 上下文 * @param key 键 * @return 获取set集合的默认值为:null */ public static Set<String> getStringSet(Context context, String key) initPreference(context); return preferences.getStringSet(key, null); public static boolean deletePreferences(Context context) initPreference(context); boolean isDelete = databaseHelper.deletePreferences(PREFERENCE_FILE_NAME); return isDelete; public static void registerObserver(Context context, Preferences.PreferencesObserver preferencesObserver) initPreference(context); mPreferencesObserver = preferencesObserver; preferences.registerObserver(mPreferencesObserver); public static void unregisterObserver() if (mPreferencesObserver != null) // 向preferences实例注销观察者 preferences.unregisterObserver(mPreferencesObserver);
2.3 第三方跳转
2.3.1 实现效果
2.3.2 拨打电话与发送短信
/** * 跳转系统短信 */ private void doMessage(String telephone) Intent intent = new Intent(); Operation operation = new Intent.OperationBuilder() // .withAction("android.intent.action.SENDTO") // Android写法 android.intent.action.SENDTO .withAction(IntentConstants.ACTION_SEND_SMS) .withUri(Uri.parse("smsto:" + telephone)) // 设置号码 .withFlags(Intent.FLAG_NOT_OHOS_COMPONENT) .build(); intent.setOperation(operation); context.startAbility(intent, 11); /** * 申请拨打电话权限 */ private boolean requestPermissions() if (context.verifySelfPermission("android.permission.CALL_PHONE") != IBundleManager.PERMISSION_GRANTED) // 应用未被授予权限 if (context.canRequestPermission("android.permission.CALL_PHONE")) // 是否可以申请弹框授权(首次申请或者用户未选择禁止且不再提示) context.requestPermissionsFromUser(new String[]"android.permission.CALL_PHONE", 100); return false; else // 权限已被授予 return true; /** * 直接拨打电话 * 需要申请权限 */ private void doCall(String destinationNum) if (!requestPermissions()) return; Intent intent = new Intent(); Operation operation = new Intent.OperationBuilder() .withAction("android.intent.action.CALL") // 系统应用拨号盘 .withUri(Uri.parse("tel:" + destinationNum)) // 设置号码 .withFlags(2) .build(); intent.setOperation(operation); // 启动Ability context.startAbility(intent, 10); /** * 跳转系统拨打电话界面 */ private void doDial(String destinationNum) Intent intent = new Intent(); Operation operation = new Intent.OperationBuilder() .withAction(IntentConstants.ACTION_DIAL) // 系统应用拨号盘 // .withBundleName(context.getCallingBundle()) // 应用拨号选择器 .withUri(Uri.parse("tel:" + destinationNum)) // 设置号码 .withFlags(2) .build(); intent.setOperation(operation); // 启动Ability context.startAbility(intent, 10);
2.4 JS服务卡片
2.4.1 实现效果
2.4.2 创建卡片模板
使用DevEco Studio创建卡片工程
创建成功后,在config.json的module中会生成js模块,用于对应卡片的js相关资源,配置示例如下:
"js": [ "pages": [ "pages/index/index" ], "name": "widget", "window": "designWidth": 720, "autoDesignWidth": true , "type": "form" ]
config.json文件“abilities”配置forms模块细节如下:
"name": "com.huhu.contact.ContactPersonAbility", "icon": "$media:icon", "description": "$string:contactpersonability_description", "formsEnabled": true, "label": "$string:contact_ContactPersonAbility", "type": "page", "forms": [ "jsComponentName": "widget", "isDefault": true, "scheduledUpdateTime": "10:30", "defaultDimension": "2*2", "name": "widget", "description": "This is a service widget", "colorMode": "auto", "type": "JS", "supportDimensions": [ "2*2" ], "updateEnabled": true, "updateDuration": 1 ]
创建一个ContactPersonAbility,覆写卡片相关回调函数。
- onCreateForm(Intent intent)
- onUpdateForm(long formId)
- onDeleteForm(long formId)
- onCastTempForm(long formId)
- onEventNotify(Map
- onTriggerFormEvent(long formId, String message)
- onAcquireFormState(Intent intent)
当卡片使用方请求获取卡片时,卡片提供方会被拉起并调用onCreateForm(Intent intent)回调,intent中会带有卡片ID、卡片名称和卡片外观规格信息,可按需获取使用。
开发JS卡片时,FormAbility可以继承AceAbility或Ability,继承Ability时,需在onStart()方法中额外设置路由信息。
2.4.3 卡片数据绑定
@Override public ProviderFormInfo bindFormData() HiLog.info(TAG, "bind form data"); ProviderFormInfo providerFormInfo = new ProviderFormInfo(); String urgentPersonStr = PreferenceUtils.getString(context, "urgentPerson", ""); ZSONObject zsonObject = ZSONObject.stringToZSON(urgentPersonStr); if (dimension == DEFAULT_DIMENSION_2X2) if (zsonObject != null) providerFormInfo.setJsBindingData(new FormBindingData(zsonObject)); return providerFormInfo;
2.4.4 卡片数据更新
public void confirmUpdateForm(FormBindingData formBindingData) FormControllerManager formControllerManager = FormControllerManager.getInstance(this); List<Long> allFormIdFromSharePreference = formControllerManager.getAllFormIdFromSharePreference(); if (allFormIdFromSharePreference == null || allFormIdFromSharePreference.isEmpty()) return; Long formId = allFormIdFromSharePreference.get(0); try updateForm(formId,formBindingData); catch (FormException e) e.printStackTrace();
2.4.5 卡片事件处理
"data": "text_content": "Name", "cardPrimaryText": "Contacts", "cardSecondaryText": "+8612345678912", "urgent1": "无", "urgent2": "无", "urgentPhone1": "+8612345678912", "urgentPhone2": "+8612345678915" , "actions": "urgentCall1": "action": "message", "params": "action": "urgentCall1", "phoneNumber": "10086" , "urgentCall2": "action": "message", "params": "action": "urgentCall2", "phoneNumber": "15565339857" , "startMainRouter": "action": "router", "abilityName": "com.huhu.contact.ContactPersonAbility"
卡片支持触发事件,覆写onTriggerFormEvent方法实现对事件的触发,
doCall就是前面的播打电话的方法
@Override protected void onTriggerFormEvent(long formId, String message) super.onTriggerFormEvent(formId, message); HiLog.info(loglabel, "onTriggerFormEvent: " + message); FormControllerManager formControllerManager = FormControllerManager.getInstance(this); FormController formController = formControllerManager.getController(formId); formController.onTriggerFormEvent(formId, message); ZSONObject params = ZSONObject.stringToZSON(message); String action = params.getString("action"); String phoneNumber = params.getString("phoneNumber"); HiLog.info(loglabel, "onTriggerFormEvent: action:" + action); String urgentPersonStr = PreferenceUtils.getString(this, "urgentPerson", ""); ZSONObject zsonObject = ZSONObject.stringToZSON(urgentPersonStr); switch (action) case "urgentCall1": String urgentPhone1 = zsonObject.getString("urgentPhone1"); doCall(urgentPhone1); break; case "urgentCall2": String urgentPhone2 = zsonObject.getString("urgentPhone2"); doCall(urgentPhone2); break; default: break;
3 注意事项
Demo还有很多需要完善的地方
滑动时,上滑头部联动效果,索引有时会错乱;
紧急联系人没有和列表数据联动。
搜索功能未实现;
4 总结
有不对或者更优的处理技术方案请多多指教,共同学习,共同进步。
代码地址: https://gitee.com/hu-lingqing/contact-person.git
以上是关于HarmonyOS 项目实战之通讯录(Java)的主要内容,如果未能解决你的问题,请参考以下文章
王姨劝我学HarmonyOS鸿蒙2.0系列教程之六自定义View&&涂鸦项目实战!