此示例应用演示了如何快速的使用Cloud DB构建简单的图书管理服务。通过快速入门和示例应用,您将会了解到如下信息:
使用Cloud DB构建应用服务,需要完成以下准备工作:
使用Cloud DB服务前,您需要先启用服务。
登录AppGallery Connect网站,选择“我的项目”。
在项目列表页面中选择项目,单击项目下需要启用云数据库服务的应用。
在导航树上选择“构建 > 云数据库”。
如您还未选择数据处理位置,需要您先设置数据处理位置,Cloud DB支持多个数据处理位置,您可以设置一个数据处理位置,也可以设置多个数据处理位置,具体操作请参见设置数据处理位置。
服务初始化成功后,即启用云数据库服务成功。
说明:
您进入云数据库界面后展现的是默认数据处理位置的云数据库,当您的应用需要支持多个数据处理位置时,请在“数据处理位置”选择其他存储地后再分别进行操作。
您需要基于AppGallery Connect控制台创建对象类型,请您遵循操作步骤创建示例中涉及的对象类型,并导出用于Android应用开发的java格式对象类型文件。
登录AppGallery Connect网站,选择“我的项目”。
在项目列表页面中选择项目,单击项目下需要创建对象类型的应用。
在导航树上选择“构建 > 云数据库”。
输入对象类型名为“BookInfo”后,单击“下一步”。
单击 + 新增如下字段后,单击“下一步”。
表1 字段定义表
字段类型 | 类型 | 主键 | 非空 | 加密 | 默认值 |
---|---|---|---|---|---|
id | integer | √ | √ | - | - |
bookName | String | - | - | - | - |
author | String | - | - | - | - |
price | Double | - | - | - | - |
pulisher | String | - | - | - | - |
shadowFlag | Boolean | - | - | - | true |
表2 权限配置表
角色 | query | upsert | delete |
---|---|---|---|
所有人 | √ | - | - |
认证用户 | √ | √ | √ |
数据创建者 | √ | √ | √ |
管理员 | √ | √ | √ |
单击“确定”。
创建完成后返回对象类型列表中,可以查看已创建的对象类型。
选择导出文件格式,选择“java格式”。
选择java文件类型,选择“android”。
输入包名称,即java文件中的package名称。
包名称只能包含以下3种类型:
字母(A-Z或a-z)
数字(0-9)
特殊字符:_和.
单击“导出”。
文件将会导出至本地,其内包含该版本中所有的对象类型。导出的java格式文件在后续步骤用于添加至本地开发环境。
您可基于AppGallery Connect控制台在云侧创建数据存储区,请您遵循操作步骤创建一个存储区名称为“QuickStartDemo”的存储区。
登录AppGallery Connect网站,选择“我的项目”。
在项目列表页面中选择项目,单击项目下需要创建存储区的应用。
在导航树上选择“构建 > 云数据库”。
选择“存储区”页签。
输入存储区名称为“QuickStartDemo”。
单击“确定”。
创建完成后返回存储区列表中,可以查看已创建的存储区。
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()方法实现对象类型的定义和创建。您在进行本地应用开发时,无需再次创建对象类型。
在添加对象类型文件后,您就可以使用云数据库进行应用开发。您开发应用时,需要先执行初始化操作,初始化对应数据处理位置的AGConnectCloudDB、创建Cloud DB zone和对象类型。
Java:
public static void initAGConnectCloudDB(Context context) {
AGConnectCloudDB.initialize(context);
}
Kotlin:
fun initAGConnectCloudDB(context: Context?) {
AGConnectCloudDB.initialize(context!!)
}
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())
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手机上写入的数据。