概述

此示例应用演示了如何快速的使用Cloud DB构建简单的图书管理服务。通过快速入门和示例应用,您将会了解到如下信息:

  • 如何使用Cloud DB进行应用开发。
  • 应用数据如何写入到Cloud DB。
  • 如何实现数据的查询。
  • 实时侦听数据的更改。
  • 体验端云数据同步等功能。

开发准备

使用Cloud DB构建应用服务,需要完成以下准备工作:

  • 您已经在开发者联盟官网注册帐号并通过实名认证,详细请参见帐号注册认证
  • 您已经在AppGallery Connect控制台上创建项目和应用,详细请参见创建项目
  • 示例应用使用了认证用户的相关权限,需要开通AppGallery Connect认证服务中“匿名帐号”服务,详细请参见认证服务
  • 您已经获取到示例代码,请从示例代码获取。
  • 您已在本地安装Android Studio。

启用服务

使用Cloud DB服务前,您需要先启用服务。

  1. 登录AppGallery Connect网站,选择“我的项目”。

  2. 在项目列表页面中选择项目,单击项目下需要启用云数据库服务的应用。

  3. 在导航树上选择“构建 > 云数据库”。

  4. 单击“立即开通”,开通云数据库服务。
    在这里插入图片描述

  5. 如您还未选择数据处理位置,需要您先设置数据处理位置,Cloud DB支持多个数据处理位置,您可以设置一个数据处理位置,也可以设置多个数据处理位置,具体操作请参见设置数据处理位置
    在这里插入图片描述

  6. 服务初始化成功后,即启用云数据库服务成功。

说明:
您进入云数据库界面后展现的是默认数据处理位置的云数据库,当您的应用需要支持多个数据处理位置时,请在“数据处理位置”选择其他存储地后再分别进行操作。
在这里插入图片描述

新增和导出对象类型

您需要基于AppGallery Connect控制台创建对象类型,请您遵循操作步骤创建示例中涉及的对象类型,并导出用于Android应用开发的java格式对象类型文件。

  1. 登录AppGallery Connect网站,选择“我的项目”。

  2. 在项目列表页面中选择项目,单击项目下需要创建对象类型的应用。

  3. 在导航树上选择“构建 > 云数据库”。

  4. 单击“新增”,进入创建对象类型页面。
    在这里插入图片描述

  5. 输入对象类型名为“BookInfo”后,单击“下一步”。

  6. 单击 + 新增如下字段后,单击“下一步”。

表1 字段定义表

字段类型类型主键非空加密默认值
idinteger--
bookNameString----
authorString----
priceDouble----
pulisherString----
shadowFlagBoolean---true
  1. 单击+ 新增索引,设置索引名为“bookName”,索引字段为“bookName”后,单击“下一步”。
  2. 按照如下要求设置各角色权限后,单击“下一步”。

表2 权限配置表

角色queryupsertdelete
所有人--
认证用户
数据创建者
管理员
  1. 单击“确定”。
    创建完成后返回对象类型列表中,可以查看已创建的对象类型。

  2. 单击“导出”。
    在这里插入图片描述

  3. 选择导出文件格式,选择“java格式”。

  4. 选择java文件类型,选择“android”。

  5. 输入包名称,即java文件中的package名称。
    包名称只能包含以下3种类型:
    字母(A-Z或a-z)
    数字(0-9)
    特殊字符:_和.

  6. 单击“导出”。
    文件将会导出至本地,其内包含该版本中所有的对象类型。导出的java格式文件在后续步骤用于添加至本地开发环境。

新增存储

您可基于AppGallery Connect控制台在云侧创建数据存储区,请您遵循操作步骤创建一个存储区名称为“QuickStartDemo”的存储区。

  1. 登录AppGallery Connect网站,选择“我的项目”。

  2. 在项目列表页面中选择项目,单击项目下需要创建存储区的应用。

  3. 在导航树上选择“构建 > 云数据库”。

  4. 选择“存储区”页签。

  5. 单击“新增”,进入创建存储区页面。
    在这里插入图片描述

  6. 输入存储区名称为“QuickStartDemo”。

  7. 单击“确定”。
    创建完成后返回存储区列表中,可以查看已创建的存储区。

配置开发环境

  1. 使用Android Studio打开示例项目。
  2. 集成AGC SDK,详细请参见集成AGC SDK
  3. 添加Cloud DB SDK至应用级build.gradle文件。
    在<项目名>/app/build.gradle文件中dependencies部分添加Cloud DB SDK。
dependencies {
    // 添加Cloud DB SDK
    implementation 'com.huawei.agconnect:agconnect-cloud-database:1.5.0.300'
    implementation 'com.huawei.agconnect:agconnect-core:1.5.0.300'
}

4.在应用级build.gradle文件中设置Java源码兼容模式为JDK1.8版本。

compileOptions {
    sourceCompatibility = 1.8
    targetCompatibility = 1.8
}

添加对象类型文件

在开发应用时,可直接将AppGallery Connect控制台上导出的java格式文件添加至本地开发环境,并通过AGConnectCloudDB类中的createObjectType()方法实现对象类型的定义和创建。您在进行本地应用开发时,无需再次创建对象类型。

  1. 将已在AppGallery Connect控制台上导出的全部java格式文件添加至本地开发环境,如已存在,请覆盖原文件。文件位置:/app/src/main/java/com/huawei/agc/clouddb/quickstart/model。
  2. 初始化Cloud DB,通过AGConnectCloudDB类中的createObjectType()方法实现对象类型的定义和创建,详细请参见初始化。

初始化

在添加对象类型文件后,您就可以使用云数据库进行应用开发。您开发应用时,需要先执行初始化操作,初始化对应数据处理位置的AGConnectCloudDB、创建Cloud DB zone和对象类型。

  1. 通过initialize()方法初始化AGConnectCloudDB。

Java:

public static void initAGConnectCloudDB(Context context) {
    AGConnectCloudDB.initialize(context);
}

Kotlin:

fun initAGConnectCloudDB(context: Context?) {
    AGConnectCloudDB.initialize(context!!)
}
  1. 通过setRoutePolicy设置数据处理位置、buildInstance指定配置生成新的AGConnectInstance实例、getInstance(AGConnectInstance connectInstance, AGConnectAuth auth)方法获取对应数据处理位置的AGConnectCloudDB实例,并使用createObjectType()创建对象类型。
    Java:
AGConnectInstance instance = AGConnectInstance.buildInstance(new AGConnectOptionsBuilder().setRoutePolicy(AGCRoutePolicy.CHINA).build(mContext));
mCloudDB = AGConnectCloudDB.getInstance(instance, AGConnectAuth.getInstance(instance));
mCloudDB.createObjectType(ObjectTypeInfoHelper.getObjectTypeInfo());

Kotlin:

var instance = AGConnectInstance.buildInstance(AGConnectOptionsBuilder().setRoutePolicy(AGCRoutePolicy.CHINA).build(context));
mCloudDB = AGConnectCloudDB.getInstance(instance, AGConnectAuth.getInstance(instance))
mCloudDB.createObjectType(ObjectTypeInfoHelper.getObjectTypeInfo())
  1. 创建Cloud DB zone配置对象,并打开该Cloud DB zone(以Cloud DB zone的同步属性为缓存模式、访问属性为公共存储区为例),详细请参考CloudDBZoneConfig

Java:

mConfig = new CloudDBZoneConfig("QuickStartDemo",
    CloudDBZoneConfig.CloudDBZoneSyncProperty.CLOUDDBZONE_CLOUD_CACHE,
    CloudDBZoneConfig.CloudDBZoneAccessProperty.CLOUDDBZONE_PUBLIC);
mConfig.setPersistenceEnabled(true);
Task<CloudDBZone> openDBZoneTask = mCloudDB.openCloudDBZone2(mConfig, true);
openDBZoneTask.addOnSuccessListener(new OnSuccessListener<CloudDBZone>() {
    @Override
    public void onSuccess(CloudDBZone cloudDBZone) {
        Log.i(TAG, "open cloudDBZone success");
        mCloudDBZone = cloudDBZone;
        // Add subscription after opening cloudDBZone success
        addSubscription();
    }
}).addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(Exception e) {
        Log.w(TAG, "open cloudDBZone failed for " + e.getMessage());
    }
});

Kotlin:

mConfig = CloudDBZoneConfig("QuickStartDemo",
        CloudDBZoneConfig.CloudDBZoneSyncProperty.CLOUDDBZONE_CLOUD_CACHE,
        CloudDBZoneConfig.CloudDBZoneAccessProperty.CLOUDDBZONE_PUBLIC)
mConfig!!.persistenceEnabled = true
val task = mCloudDB.openCloudDBZone2(mConfig!!, true)
task.addOnSuccessListener {
    Log.i(TAG, "Open cloudDBZone success")
    mCloudDBZone = it
    // Add subscription after opening cloudDBZone success
    addSubscription()
}.addOnFailureListener {
    Log.w(TAG, "Open cloudDBZone failed for " + it.message)
}

写入数据

在本节主要介绍如何在应用程序中进行数据写入操作,以便您了解如何使用Cloud DB SDK实现数据的写入。在应用界面中,增加了“添加”按钮,用于用户新增数据,并在代码中通过executeUpsert()实现数据的写入。

Java:

public void upsertBookInfos(BookInfo bookInfo) {
    if (mCloudDBZone == null) {
        Log.w(TAG, "CloudDBZone is null, try re-open it");
        return;
    }
    Task<Integer> upsertTask = mCloudDBZone.executeUpsert(bookInfo);
    upsertTask.addOnSuccessListener(new OnSuccessListener<Integer>() {
        @Override
        public void onSuccess(Integer cloudDBZoneResult) {
            Log.i(TAG, "Upsert " + cloudDBZoneResult + " records");
        }
    }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(Exception e) {
            mUiCallBack.updateUiOnError("Insert book info failed");
        }
    });
}

Kotlin:

fun upsertBookInfos(bookInfo: BookInfo?) {
    if (mCloudDBZone == null) {
        Log.w(TAG, "CloudDBZone is null, try re-open it")
        return
    }
    val upsertTask = mCloudDBZone!!.executeUpsert(bookInfo!!)
    upsertTask.addOnSuccessListener { cloudDBZoneResult ->
        Log.i(TAG, "Upsert $cloudDBZoneResult records")
    }.addOnFailureListener {
        mUiCallBack.updateUiOnError("Insert book info failed")
    }
}

查看数据

获取数据变化
用户在应用界面中新增的数据,将会被存储在云侧。在端侧注册数据变化侦听器,当云侧数据发生变化时,端侧能够感知数据变化,及时刷新本地应用数据。通过查询条件与subscribeSnapshot()方法组合使用,可以指定侦听对象,当侦听对象的数据发生变化时,端侧会收到通知,根据快照获取变化的数据信息,从云侧同步数据至端侧应用。

Java:

private OnSnapshotListener<BookInfo> mSnapshotListener = new OnSnapshotListener<BookInfo>() {
    @Override
    public void onSnapshot(CloudDBZoneSnapshot<BookInfo> cloudDBZoneSnapshot, AGConnectCloudDBException e) {
        if (e != null) {
            Log.w(TAG, "onSnapshot: " + e.getMessage());
            return;
        }
        CloudDBZoneObjectList<BookInfo> snapshotObjects = cloudDBZoneSnapshot.getSnapshotObjects();
        List<BookInfo> bookInfos = new ArrayList<>();
        try {
            if (snapshotObjects != null) {
                while (snapshotObjects.hasNext()) {
                    BookInfo bookInfo = snapshotObjects.next();
                    bookInfos.add(bookInfo);
                    updateBookIndex(bookInfo);
                }
            }
            mUiCallBack.onSubscribe(bookInfos);
        } catch (AGConnectCloudDBException snapshotException) {
            Log.w(TAG, "onSnapshot:(getObject) " + snapshotException.getMessage());
        } finally {
            cloudDBZoneSnapshot.release();
        }
    }
};

public void addSubscription() {
    if (mCloudDBZone == null) {
        Log.w(TAG, "CloudDBZone is null, try re-open it");
        return;
    }

    try {
        CloudDBZoneQuery<BookInfo> snapshotQuery = CloudDBZoneQuery.where(BookInfo.class)
            .equalTo(BookEditFields.SHADOW_FLAG, true);
        mRegister = mCloudDBZone.subscribeSnapshot(snapshotQuery,
            CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY, mSnapshotListener);
    } catch (AGConnectCloudDBException e) {
        Log.w(TAG, "subscribeSnapshot: " + e.getMessage());
    }
}

Kotlin:

private val mSnapshotListener = OnSnapshotListener<BookInfo> { cloudDBZoneSnapshot, e ->
    if (e != null) {
        Log.w(TAG, "onSnapshot: " + e.message)
        return@OnSnapshotListener
    }
    val snapshotObjects = cloudDBZoneSnapshot.snapshotObjects
    val bookInfoList: MutableList<BookInfo> = ArrayList()
    try {
        if (snapshotObjects != null) {
            while (snapshotObjects.hasNext()) {
                val bookInfo = snapshotObjects.next()
                bookInfoList.add(bookInfo)
                updateBookIndex(bookInfo)
            }
        }
        mUiCallBack.onSubscribe(bookInfoList)
    } catch (snapshotException: AGConnectCloudDBException) {
        Log.w(TAG, "onSnapshot:(getObject) " + snapshotException.message)
    } finally {
        cloudDBZoneSnapshot.release()
    }
}
private fun addSubscription() {
    if (mCloudDBZone == null) {
        Log.w(TAG, "CloudDBZone is null, try re-open it")
        return
    }
    try {
        val snapshotQuery = CloudDBZoneQuery.where(BookInfo::class.java)
                .equalTo(BookEditFields.SHADOW_FLAG, true)
        mRegister = mCloudDBZone!!.subscribeSnapshot(snapshotQuery,
                CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY, mSnapshotListener)
    } catch (e: AGConnectCloudDBException) {
        Log.w(TAG, "subscribeSnapshot: " + e.message)
    }
}

数据查询和排序
在应用界面中,增加了“查询”按钮和排序功能,通过executeQuery()addOnSuccessListener()addOnFailureListener()方法组合,实现异步方式查询数据。

Java:

public void queryBooks(CloudDBZoneQuery<BookInfo> query) {
    if (mCloudDBZone == null) {
        Log.w(TAG, "CloudDBZone is null, try re-open it");
        return;
    }

    Task<CloudDBZoneSnapshot<BookInfo>> queryTask = mCloudDBZone.executeQuery(query,
    CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY);
    queryTask.addOnSuccessListener(new OnSuccessListener<CloudDBZoneSnapshot<BookInfo>>() {
        @Override
        public void onSuccess(CloudDBZoneSnapshot<BookInfo> snapshot) {
            processQueryResult(snapshot);
        }
    }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(Exception e) {
            mUiCallBack.updateUiOnError("Query failed");
        }
    });
}

Kotlin:

fun queryBooks(query: CloudDBZoneQuery<BookInfo>) {
    if (mCloudDBZone == null) {
        Log.w(TAG, "CloudDBZone is null, try re-open it")
        return
    }

    val queryTask = mCloudDBZone!!.executeQuery(query,
            CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY)
    queryTask.addOnSuccessListener { snapshot -> processQueryResult(snapshot) }
        .addOnFailureListener { mUiCallBack.updateUiOnError("Query failed") }
}

通过查询与limit()方法组合,实现限制查询数据显示条数的功能;与orderByAsc()方法或者orderByDesc()方法组合来实现数据的排序功能。
Java:

private void queryWithOrder() {
    invalidateViewInNormalMode();
    CloudDBZoneQuery<BookInfo> query = CloudDBZoneQuery.where(BookInfo.class);
    if (!mQueryInfo.bookName.isEmpty()) {
        query.contains(BookEditFields.BOOK_NAME, mQueryInfo.bookName);
    }
    query.greaterThanOrEqualTo(BookEditFields.PRICE, mQueryInfo.lowestPrice);
    if (mQueryInfo.lowestPrice != mQueryInfo.highestPrice || mQueryInfo.lowestPrice != 0.0) {
        query.lessThanOrEqualTo(BookEditFields.PRICE, mQueryInfo.highestPrice);
    }
    if (mQueryInfo.showCount > 0) {
        query.limit(mQueryInfo.showCount);
    }
    if (mSortState.state == SortState.State.UP) {
        query.orderByAsc(mSortState.field);
    } else {
        query.orderByDesc(mSortState.field);
    }
    mHandler.post(() -> mCloudDBZoneWrapper.queryBooks(query));
}

Kotlin:

private fun queryWithOrder() {
    invalidateViewInNormalMode()
    val query = CloudDBZoneQuery.where(BookInfo::class.java)
    if (mQueryInfo.bookName!!.isNotEmpty()) {
        query.contains(BookEditFields.BOOK_NAME, mQueryInfo.bookName!!)
    }
    query.greaterThanOrEqualTo(BookEditFields.PRICE, mQueryInfo.lowestPrice)
    if (mQueryInfo.lowestPrice != mQueryInfo.highestPrice || mQueryInfo.lowestPrice != 0.0) {
        query.lessThanOrEqualTo(BookEditFields.PRICE, mQueryInfo.highestPrice)
    }
    if (mQueryInfo.showCount > 0) {
        query.limit(mQueryInfo.showCount)
    }
    if (mSortState.state == SortState.State.UP) {
        query.orderByAsc(mSortState.field!!)
    } else {
        query.orderByDesc(mSortState.field!!)
    }
    mHandler.post { mCloudDBZoneWrapper.queryBooks(query) }
}

应用编译运行

到此,您已经了解了示例应用的开发流程。您可以编译并生成APK包,在Android手机上安装、运行示例应用。如需体验示例应用,您可以在A手机上打开应用,并新增数据;然后您可以在B手机上打开应用,查看在A手机上写入的数据。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐