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

数据库开发及联调

本节之前,我们已经完成了所有设置页面的开发,本节我们将开发ClockManager关系型数据库的操作,实现clock的增删改查持久化,并联调之前所有的界面,在真机上验证闹钟的创建,修改,显示和删除。

1.完善ClockManager类,实现闹钟的增删改查数据库

1.HarmonyOs内置关系型数据库,因为这个应用只需要主机设置和实现定时操作,所以只需要实现关系型数据库,而不需要使用分布式数据库。首先需要新增一个Data Ability名命为ClockDataAbility,里面定义闹钟表的表名,列,以及在onCreate中写入建表SQL。

public class ClockDataAbility extends Ability {
    private static final String TAG = ClockDataAbility.class.getName();
​
    public static final String DB_NAME = "crazyclock.db";
​
    public static final String DB_TAB_NAME = "crazyclock";
​
    public static final String DB_COLUMN_ID = "id";
​
    public static final String DB_COLUMN_NAME = "name";
​
    public static final String DB_COLUMN_BELL = "bell";
​
    public static final String DB_COLUMN_HOUR = "hour";
​
    public static final String DB_COLUMN_MINUTE = "minute";
​
    public static final String DB_COLUMN_DURATION = "duration";
​
    public static final String DB_COLUMN_ENABLE = "enable";
​
    private static final int DB_VERSION = 1;
​
    private StoreConfig config = StoreConfig.newDefaultConfig(DB_NAME);
​
    private RdbStore rdbStore;
​
    private RdbOpenCallback rdbOpenCallback = new RdbOpenCallback() {
        @Override
        public void onCreate(RdbStore store) {
            store.executeSql("create table if not exists "
                    + DB_TAB_NAME + " ("
                    + DB_COLUMN_ID + " integer primary key, "
                    + DB_COLUMN_NAME + " text not null, "
                    + DB_COLUMN_BELL + " integer not null, "
                    + DB_COLUMN_HOUR + " integer not null, "
                    + DB_COLUMN_MINUTE + " integer not null, "
                    + DB_COLUMN_DURATION + " integer not null, "
                    + DB_COLUMN_ENABLE + " boolean)");
        }
​
        private int duration;
​
        private int strategy;
​
        private boolean isEnable;
​
        @Override
        public void onUpgrade(RdbStore store, int oldVersion, int newVersion) {
        }
    };
    
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        LogUtil.info(TAG, "ClockDataAbility onStart");
​
        DatabaseHelper databaseHelper = new DatabaseHelper(this);
        rdbStore = databaseHelper.getRdbStore(config, DB_VERSION, rdbOpenCallback, null);
    }
}
  1. 在ClockDataAbility中增加函数,实现关系型数据库的增删改查持久化,可以参考官方文档

   @Override
    public int insert(Uri uri, ValuesBucket value) {
        LogUtil.info(TAG, "ClockDataAbility insert");
        String path = uri.getLastPath();
        if (!DB_TAB_NAME.equals(path)) {
            LogUtil.info(TAG, "DataAbility insert path is not matched");
            return -1;
        }
        ValuesBucket values = new ValuesBucket();
        values.putString(DB_COLUMN_NAME, value.getString(DB_COLUMN_NAME));
        values.putInteger(DB_COLUMN_BELL, value.getInteger(DB_COLUMN_BELL));
        values.putInteger(DB_COLUMN_HOUR, value.getInteger(DB_COLUMN_HOUR));
        values.putInteger(DB_COLUMN_MINUTE, value.getInteger(DB_COLUMN_MINUTE));
        values.putInteger(DB_COLUMN_DURATION, value.getInteger(DB_COLUMN_DURATION));
        values.putBoolean(DB_COLUMN_ENABLE, value.getBoolean(DB_COLUMN_ENABLE));
        int index = (int) rdbStore.insert(DB_TAB_NAME, values);
        DataAbilityHelper.creator(this, uri).notifyChange(uri);//todo ?
        return index;
    }
​
    @Override
    public int delete(Uri uri, DataAbilityPredicates predicates) {
        RdbPredicates rdbPredicates = DataAbilityUtils.createRdbPredicates(predicates, DB_TAB_NAME);
        int index = rdbStore.delete(rdbPredicates);
        DataAbilityHelper.creator(this, uri).notifyChange(uri);
        return index;
    }
​
    @Override
    public int update(Uri uri, ValuesBucket value, DataAbilityPredicates predicates) {
        RdbPredicates rdbPredicates = DataAbilityUtils.createRdbPredicates(predicates, DB_TAB_NAME);
        int index = rdbStore.update(value, rdbPredicates);
        LogUtil.info(TAG, "update: " + index);
        DataAbilityHelper.creator(this, uri).notifyChange(uri);
        return index;
    }
​
    @Override
    public FileDescriptor openFile(Uri uri, String mode) {
        return null;
    }
​
    @Override
    public String[] getFileTypes(Uri uri, String mimeTypeFilter) {
        return new String[0];
    }
​
    @Override
    public PacMap call(String method, String arg, PacMap extras) {
        return null;
    }
​
    @Override
    public String getType(Uri uri) {
        return null;
    }

1.3 ClockManager实现对ClockDataAbility的封装,以Clock为对象进行操作,对外提供单例对象。其中BASE_URI要与ClockDataAbility的完整类名一致。

ClockDataAbility.java

package com.madixin.clock.setting.manager;
​
import com.madixin.clock.common.util.LogUtil;
import com.madixin.clock.setting.ability.ClockDataAbility;
import com.madixin.clock.setting.model.Clock;
import ohos.aafwk.ability.DataAbilityHelper;
import ohos.aafwk.ability.DataAbilityRemoteException;
import ohos.app.Context;
import ohos.data.dataability.DataAbilityPredicates;
import ohos.data.rdb.ValuesBucket;
import ohos.data.resultset.ResultSet;
import ohos.utils.net.Uri;
​
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
​
public class ClockManager {
    private static final String TAG = ClockManager.class.getName();
​
    private static ClockManager instance;
​
    private static final String BASE_URI = "dataability:///com.madixin.clock.setting.ability.ClockDataAbility";
​
    private Context context;
​
    private DataAbilityHelper databaseHelper;
​
    private static final String DATA_PATH = "/crazyclock";
​
    private ClockManager(Context context) {
        this.context = context;
        this.databaseHelper = DataAbilityHelper.creator(context);
    }
​
    private List<Clock> clockList = new LinkedList<>();
​
    public static ClockManager getInstance(Context context) {
        if (instance == null) {
            instance = new ClockManager(context);
        }
        return instance;
    }
​
    /**
     * 获取所有闹钟
     * @return 闹钟列表
     */
    public List<Clock> getAllClocks() {
        this.clockList = new LinkedList<>();
​
        String[] columns = new String[]{ClockDataAbility.DB_COLUMN_ID,
                ClockDataAbility.DB_COLUMN_NAME, ClockDataAbility.DB_COLUMN_BELL, ClockDataAbility.DB_COLUMN_HOUR,
                ClockDataAbility.DB_COLUMN_MINUTE, ClockDataAbility.DB_COLUMN_DURATION, ClockDataAbility.DB_COLUMN_ENABLE};
        // 构造查询条件
        DataAbilityPredicates predicates = new DataAbilityPredicates();
        //predicates.between(DB_COLUMN_AGE, 15, 40);
        try {
            ResultSet resultSet = databaseHelper.query(Uri.parse(BASE_URI + DATA_PATH),
                    columns, predicates);
            if (resultSet == null || resultSet.getRowCount() == 0) {
                LogUtil.info(TAG, "query: resultSet is null or no result found");
                return this.clockList;
            }
            resultSet.goToFirstRow();
            do {
                Clock clock = new Clock();
                clock.setId(resultSet.getInt(resultSet.getColumnIndexForName(ClockDataAbility.DB_COLUMN_ID)));
                clock.setName(resultSet.getString(resultSet.getColumnIndexForName(ClockDataAbility.DB_COLUMN_NAME)));
                clock.setBell(resultSet.getInt(resultSet.getColumnIndexForName(ClockDataAbility.DB_COLUMN_BELL)));
                clock.setHour(resultSet.getInt(resultSet.getColumnIndexForName(ClockDataAbility.DB_COLUMN_HOUR)));
                clock.setMinute(resultSet.getInt(resultSet.getColumnIndexForName(ClockDataAbility.DB_COLUMN_MINUTE)));
                clock.setDuration(resultSet.getInt(resultSet.getColumnIndexForName(ClockDataAbility.DB_COLUMN_DURATION)));
                clock.setEnable(resultSet.getInt(resultSet.getColumnIndexForName(ClockDataAbility.DB_COLUMN_ENABLE)) == 1);
                this.clockList.add(clock);
                LogUtil.info(TAG, "query: clock :" + clock);
            } while (resultSet.goToNextRow());
        } catch (DataAbilityRemoteException | IllegalStateException exception) {
            LogUtil.error(TAG, "query: dataRemote exception | illegalStateException" + exception.getMessage());
        }
​
        LogUtil.info(TAG, "getAllClocks : size= " + this.clockList.size());
        return this.clockList;
    }
​
    /**
     * 创建新闹钟
     * @param clock clock
     */
    public void createNewClock(Clock clock) {
        ValuesBucket valuesBucket = new ValuesBucket();
        valuesBucket.putString(ClockDataAbility.DB_COLUMN_NAME, clock.getName());
        valuesBucket.putInteger(ClockDataAbility.DB_COLUMN_BELL, clock.getBell());
        valuesBucket.putInteger(ClockDataAbility.DB_COLUMN_HOUR, clock.getHour());
        valuesBucket.putInteger(ClockDataAbility.DB_COLUMN_MINUTE, clock.getMinute());
        valuesBucket.putInteger(ClockDataAbility.DB_COLUMN_DURATION, clock.getDuration());
        valuesBucket.putBoolean(ClockDataAbility.DB_COLUMN_ENABLE, clock.isEnable());
​
        try {
            int id = databaseHelper.insert(Uri.parse(BASE_URI + DATA_PATH), valuesBucket);
            if (id == -1) {
                LogUtil.error(TAG, "fail to insert");
            } else {
                LogUtil.info(TAG, "success to insert id=" + id);
            }
        } catch (DataAbilityRemoteException | IllegalStateException exception) {
            LogUtil.error(TAG, "insert: dataRemote exception | illegalStateException" + exception.getMessage());
        }
    }
​
    /**
     * 删除闹钟
     * @param clock clock
     * @return
     */
    public int deleteClock(Clock clock) {
        DataAbilityPredicates predicates = new DataAbilityPredicates();
        predicates.contains(ClockDataAbility.DB_COLUMN_ID, String.valueOf(clock.getId()));
        try {
            return databaseHelper.delete(Uri.parse(BASE_URI + DATA_PATH), predicates);
        } catch (DataAbilityRemoteException e) {
            LogUtil.error(TAG, "delete: dataRemote exception | illegalStateException" + e.getMessage());
        }
        return -1;
    }
​
    /**
     * 返回列表第几个的闹钟数据
     *
     * @param itemId 列表项
     * @return Optional<Clock>
     */
    public Optional<Clock> getClockByItemId(int itemId) {
        if (itemId > this.clockList.size() || this.clockList.size() == 0) {
            return Optional.empty();
        }
​
        return Optional.ofNullable(this.clockList.get(itemId));
    }
​
    /**
     * 更新闹钟
     * @param clock clock
     * @return
     */
    public int updateClock(Clock clock) {
        DataAbilityPredicates predicates = new DataAbilityPredicates();
        predicates.contains(ClockDataAbility.DB_COLUMN_ID, String.valueOf(clock.getId()));
​
        ValuesBucket valuesBucket = new ValuesBucket();
        valuesBucket.putString(ClockDataAbility.DB_COLUMN_NAME, clock.getName());
        valuesBucket.putInteger(ClockDataAbility.DB_COLUMN_BELL, clock.getBell());
        valuesBucket.putInteger(ClockDataAbility.DB_COLUMN_HOUR, clock.getHour());
        valuesBucket.putInteger(ClockDataAbility.DB_COLUMN_MINUTE, clock.getMinute());
        valuesBucket.putInteger(ClockDataAbility.DB_COLUMN_DURATION, clock.getDuration());
        valuesBucket.putBoolean(ClockDataAbility.DB_COLUMN_ENABLE, clock.isEnable());
​
        try {
            int id = databaseHelper.update(Uri.parse(BASE_URI + DATA_PATH), valuesBucket, predicates);
            if (id == -1) {
                LogUtil.error(TAG, "fail to insert");
            } else {
                LogUtil.info(TAG, "success to insert id=" + id);
                return id;
            }
        } catch (DataAbilityRemoteException | IllegalStateException exception) {
            LogUtil.error(TAG, "insert: dataRemote exception | illegalStateException" + exception.getMessage());
        }
        return -1;
    }
}

2.实现主页面列表开关控制闹钟是否开启

2.1.在ListViewClockItemProvider中增加自定义接口SwitchStateChangedListener。

    public interface SwitchStateChangedListener {
        public void onSwitchStateChanged(Button button, boolean isEnable, int position);
    }
​
    private SwitchStateChangedListener switchStateChangedListener;

2.2 将Switch的改变事件向slice发布出去。

        viewHolder.switchState.setCheckedStateChangedListener((button, isEnable) -> {
            switchStateChangedListener.onSwitchStateChanged(button, isEnable, position);
        });

2.3 在MainAbilitySlice.java的initListContainer方法中监听Switch切换事件,并更新数据库。

        // Switch切换按钮
        listViewClockItemProvider.setSwitchStateChangedListener(((button, isEnable, position) -> {
            Optional<Clock> clockOptional = ClockManager.getInstance(this.getApplicationContext()).getClockByItemId(position);
            if (clockOptional.isPresent()) {
                Clock curClock = clockOptional.get();
                curClock.setEnable(isEnable);
                ClockManager.getInstance(this.getApplicationContext()).updateClock(curClock);
            }
        }));

3.小结

本节完成了数据库的联调操作后,整个应用的设置闹钟功能已经全部开发完了。在模拟器上调试后,建议使用真机P40调试来验证功能,在真机中每次操作后的数据都会保存在真机的数据库里。真机调试需要签名等步骤,可参考官方文档

下一步我们将在闹钟FA中开发闹钟界面。

4.代码地址:

github,提交记录:e6611286ebf042ec060ef999d0c12f9f77a2b965

猜你喜欢

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