鸿蒙应用:多设备闹钟开发教程(8)

PA定时拉起闹钟FA

本节前,我们分别开发完了闹钟设置entry FA和闹钟clock FA的功能开发,本节我们将完成最后的逻辑定时拉起。这块设计的思路是在闹钟设置entry FA的里再新增一个Service Ability的PA,里面通过定时任务触发闹钟,并跨设备拉起闹钟FA里的闹钟界面。

1.闹钟设置entry FA里新增Service Ability,触发定时拉起

1.1 在公共common har包中增加常量Constants,定义公共消息关闭闹钟代码。 Constants.java

public class Constants {
    public static final int CLOSE_CLOCK = 1001;
}

1.2 闹钟设置entry FA里新增Service Ability为ScheduleServiceAbility。通过ScheduledExecutorService触发定时器,判断是否有闹钟触发。 ScheduleServiceAbility.java

    @Override
    public void onStart(Intent intent) {
        LogUtil.info(TAG, "ScheduleServiceAbility::onStart");
        super.onStart(intent);
​
        // 按分钟定时检查
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
        scheduledExecutorService.scheduleAtFixedRate(() -> {
                    doAlarm();
                    LogUtil.info(TAG, "ScheduleServiceAbility::onBackground");
                }
                , 0, 30, TimeUnit.SECONDS);
​
    }
​
    private void doAlarm() {
        LogUtil.info(TAG, "doAlarm isInAlarm=" + isInAlarm);
        if (isInAlarm) {
            return;
        }
//        Clock clock = new Clock();
//        clock.setBell(2);
//        startClockAlarmAbility(clock);
        Optional<Clock> optionClock = getAlarmClock();
        if (optionClock.isPresent()) {
            startClockAlarmAbility(optionClock.get());
        }
    }
    
    private Optional<Clock> getAlarmClock() {
        Calendar calendar = Calendar.getInstance();
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        int minute = calendar.get(Calendar.MINUTE);
        List<Clock> clockList = ClockManager.getInstance(this.getApplicationContext()).getAllClocks();
        for (Clock clock : clockList) {
            if (clock.isEnable() && clock.getHour() == hour && clock.getMinute() == minute) {
                return Optional.of(clock);
            }
        }
        return Optional.empty();
    }    

1.3 ScheduleServiceAbility里使用startAbility方法,分别拉起本地和其他设备的闹钟FA. ScheduleServiceAbility.java

    private void startClockAlarmAbility(Clock clock) {
        isInAlarm = true;
        startLocalClockAlarmAbility(clock);
        startRemoteClockAlarmAbility(clock);
    }
​
    private void startRemoteClockAlarmAbility(Clock clock) {
        Intent intent = new Intent();
        intent.setParam("bell", DataConstants.getBell(clock.getBell()));
​
        List<DeviceInfo> deviceInfos =
                DeviceManager.getDeviceList(ohos.distributedschedule.interwork.DeviceInfo.FLAG_GET_ONLINE_DEVICE);
        for (DeviceInfo deviceInfo : deviceInfos) {
            Operation operation = new Intent.OperationBuilder()
                    .withDeviceId(deviceInfo.getDeviceId())
                    .withBundleName(getBundleName())
                    .withAbilityName("com.madixin.clock.clock.ClockAlarmAbility")
                    .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
                    .build();
            intent.setOperation(operation);
            startAbility(intent);
        }
    }
​
    private void startLocalClockAlarmAbility(Clock clock) {
        Intent intent = new Intent();
        intent.setParam("bell", DataConstants.getBell(clock.getBell()));
        intent.setParam("deviceLocal", "local");
        Operation operation = new Intent.OperationBuilder()
                .withDeviceId("")
                .withBundleName(getBundleName())
                .withAbilityName("com.madixin.clock.clock.ClockAlarmAbility")
                .build();
​
        intent.setOperation(operation);
        startAbility(intent);
    }

1.4 ScheduleServiceAbility里增加RemoteObject,接收闹钟FA关闭的事件,把是否闹钟的状态置为false,后续可继续定时触发闹钟。 ScheduleServiceAbility.java

    private boolean isInAlarm = false;
​
    private ScheduleServiceAbility.MyRemote remote = new ScheduleServiceAbility.MyRemote();
​
   @Override
    public IRemoteObject onConnect(Intent intent) {
        super.onConnect(intent);
        return remote.asObject();
    }
​
    @Override
    public void onDisconnect(Intent intent) {
    }
    class MyRemote extends RemoteObject implements IRemoteBroker {
​
        MyRemote() {
            super("MyService_MyRemote");
        }
​
        @Override
        public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) {
            LogUtil.info(TAG, "onRemoteRequest:" + code);
            switch (code) {
                case Constants.CLOSE_CLOCK:
                    isInAlarm = false;
                    return true;
                default:
                    return true;
​
​
            }
        }
        @Override
        public IRemoteObject asObject() {
            return this;
        }
    }

2.闹钟clock FA里新增Service Ability拉起闹钟界面

2.1 修改ClockAlarmAbilitySlice,在onstart启动时,连接ScheduleServiceAbility,并在关闭按钮触发时,发送消息给ScheduleServiceAbility重置闹钟状态。 ClockAlarmAbilitySlice.java

package com.madixin.clock.clock.slice;
​
import com.madixin.clock.clock.ResourceTable;
import com.madixin.clock.clock.util.PlayerManager;
import com.madixin.clock.clock.util.PlayerStateListener;
import com.madixin.clock.common.util.Constants;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.ability.IAbilityConnection;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.components.Button;
import ohos.bundle.ElementName;
import ohos.rpc.IRemoteObject;
import ohos.rpc.MessageOption;
import ohos.rpc.MessageParcel;
import ohos.rpc.RemoteException;
​
public class ClockAlarmAbilitySlice extends AbilitySlice {
​
    private PlayerManager playerManager;
​
    private IRemoteObject scheduleServiceAbility;
​
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_clock_alarm);
​
        Button btnClose = (Button) findComponentById(ResourceTable.Id_btn_close);
        btnClose.setClickedListener((button) -> {
            if (scheduleServiceAbility != null) {
                MessageParcel data = MessageParcel.obtain();
                MessageParcel reply = MessageParcel.obtain();
                MessageOption option = new MessageOption(MessageOption.TF_SYNC);
                try {
                    scheduleServiceAbility.sendRequest(Constants.CLOSE_CLOCK, data, reply, option);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            if (playerManager.isPlaying()) {
                playerManager.releasePlayer();
            }
            this.terminate();//暂时直接关闭
        });
​
        String bell = "Canon";
        if (intent != null) {
            Object obj = intent.getStringParam("bell");
            if (obj instanceof String) {
                bell = (String) obj;
            }
            obj = intent.getStringParam("deviceLocal");
            if (obj instanceof String) {
                Intent connectPaIntent = new Intent();
                Operation operation = new Intent.OperationBuilder()
                        .withBundleName(getBundleName())
                        .withAbilityName("com.madixin.clock.setting.ability.ScheduleServiceAbility")
                        .build();
                connectPaIntent.setOperation(operation);
                IAbilityConnection conn = new IAbilityConnection() {
                    @Override
                    public void onAbilityConnectDone(ElementName elementName, IRemoteObject remote, int resultCode) {
                        scheduleServiceAbility = remote;
                    }
​
                    @Override
                    public void onAbilityDisconnectDone(ElementName elementName, int i) {
                        scheduleServiceAbility = null;
                        disconnectAbility(this);
                    }
                };
                this.connectAbility(connectPaIntent, conn);
            }
        }
        initMedia(bell);
    }
​
    @Override
    public void onActive() {
        super.onActive();
    }
​
    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }
​
    private void initMedia(String bell) {
        playerManager = new PlayerManager(this, "resources/rawfile/" + bell + ".mp3");
        playerManager.setPlayerStateListener(new PlayerStateListener() {
            @Override
            public void onPlaySuccess(int totalTime) {
​
            }
​
            @Override
            public void onPauseSuccess() {
​
            }
​
            @Override
            public void onPositionChange(int currentTime) {
​
            }
​
            @Override
            public void onMusicFinished() {
​
            }
​
            @Override
            public void onUriSet(String name) {
​
            }
        });
        playerManager.init();
​
        playerManager.play();
    }
​
}

3.闹钟设置entry启动时拉起ScheduleServiceAbility

3.1 在MainAbilitySlice的onstart方法中启动ScheduleServiceAbility。

    /**
     * 启动后台PA触发定时
     */
    private void initClockService() {
        Intent intent = new Intent();
        Operation operation = new Intent.OperationBuilder()
                .withDeviceId("")
                .withBundleName(getBundleName())
                .withAbilityName("com.madixin.clock.setting.ability.ScheduleServiceAbility")
                .build();
        intent.setOperation(operation);
        startAbility(intent);
    }

3.2 由于主机功能跨越两个FA,在DevEco Studio中选择Deploy multi hap packages后,部署到真机P40上验证,如果有多台,其他设备只需要单独部署clock闹钟这1个FA,但需要保证使用同一个华为账号登陆以及同一个网络。

4.总结

到本节为止,多设备的闹钟开发已经告一段落,该工程覆盖了如下知识点:

  • DevEco Studio创建多个har,hap包,最终打包成APP

  • java ui布局

  • 基础控件的使用Button,Image,ListContainer,Tablist,Switch

  • 使用Hilog输出日志

  • Data Ability关系型数据库的增删改查

  • 分布式设备权限配置和设备发现

  • 分布式连接ServiceAbility,分布式启动Page Ability

因这是本人第一个HarmonyOs应用,自己也感觉有很多不足之处,希望大家理解:

  • 界面简单

  • 闹钟时长未实现

  • 需求未想清楚:关闭闹钟时,是否需要等每个闹钟都关闭才允许停止,是否要显示已关闭了多少个闹钟。 所有代码归档在github中,欢迎大家拍砖。

5.代码地址:

github,提交记录:9ed91f1e05ade0347a30e2ccbb735899c5bb9c1d

猜你喜欢

转载自blog.csdn.net/sd2131512/article/details/117572373