Intelligent Assistant
Chat with our virtual assistant to get answers promptly.
Cloud DB provides the capability of mapping object type files. When developing a local app integrated with the SDK for Android, you can directly add the object type file in Java format exported from AppGallery Connect to the local development environment. If the object type file contains object type names (class names) or field names (attribute names) that do not comply with the Java specifications, you can modify the object type names and field names, add annotations to establish object type mappings between the cloud and local development environment, and use the mapped object type names and field names to meet the language specifications. In object type mappings, ObjectTypeMapping maps classes (object types) and FieldMapping maps attributes (fields) in Java files.
Precautions:
Read the precautions carefully.
Procedure:
If any file already exists, replace it.
@PrimaryKeys({"id"})
public final class book_info extends CloudDBZoneObject {
private Long id;
private Date publish_time;
public book_info() {
super(book_info.class);
}
public void setId(Long id) {
this.id= id;
}
public String getId() {
return id;
}
public void setPublish_time(Date publish_time) {
this.publish_time = publish_time
}
public String getPublish_time() {
return publish_time;
}
}@PrimaryKeys({"id"})
@ObjectTypeMapping("book_info")
public final class BookInfo extends CloudDBZoneObject {
private Long id;
private Date publish_time;
public BookInfo() {
super(BookInfo.class);
}
public void setId(Long id) {
this.id= id;
}
public String getId() {
return id;
}
public void setPublish_time(Date publish_time) {
this.publish_time = publish_time
}
public String getPublish_time() {
return publish_time;
}
}@PrimaryKeys({"id"})
@ObjectTypeMapping("book_info")
public final class BookInfo extends CloudDBZoneObject {
private Long id;
@FieldMapping("publish_time")
private Date publishTime;
public BookInfo() {
super(BookInfo.class);
}
public void setId(Long id) {
this.id= id;
}
public String getId() {
return id;
}
public void setPublishTime(Date publishTime) {
this.publishTime = publishTime
}
public String getPublishTime() {
return publishTime;
}
}You can use executeUpsert() to write one object or a group of objects to the current Cloud DB zone. If an object with the same primary key exists in the Cloud DB zone, the existing object will be updated. Otherwise, a new object is written. The written data can be obtained from a new object or an object queried from the Cloud DB zone.
When you write a group of objects, the write operation is atomic. That is, all objects in the object list either are successfully written or fail to be written.
After the data write method is called, a Task object is returned. The object encapsulates the status, result, and exception information of the write operation. The Task object can be used to asynchronously listen to the execution result. If the execution succeeds, you can obtain the number of written objects. Otherwise, you can obtain the corresponding exception information. For details, please refer to Tasks.
Precautions:
Read the precautions carefully.
Sample code:
Write the BookInfo object into the Cloud DB zone. If the write operation succeeds, the number of written data records is returned. Otherwise, an exception will be thrown.
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("Upsert book info failed");
}
});
}fun upsertBookInfo(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("Upsert book info failed")
}
}Cloud DB uses the executeQuery() method to query objects and provides various query predicates, such as equalTo(), notEqualTo(), and in(). By using one or more chain query conditions, you can query objects that meet the specific query conditions from a Cloud DB zone, or sort query results or limit the number of returned query results by using the corresponding predicates. For details about the query conditions, please refer to CloudDBZoneQuery.
There are two Cloud DB data synchronization modes: cache mode and local mode. The data query policy varies according to the data synchronization mode. The data sources are as follows in different modes:
Call the getResult() method of the Task<TResult> class to obtain the CloudDBZoneSnapshot object that is stored in the returned objects. When obtaining the object, you can also use some auxiliary methods to perform different operations as needed. For example, use the subscribeSnapshot() method to add a listener for changes of the query result set, use the hasPendingWrites() method to determine whether there are objects that are not synchronized to the cloud, and use the isFromCloud() method to determine the object source in the query results. For details, please refer to CloudDBZoneSnapshot.
In addition to basic query, Cloud DB supports querying the average value of a field and objects in the local cache that are not synchronized to Cloud DB.
Precautions:
Read the precautions carefully.
You can obtain all objects of an object type when no query conditions are set. You can also specify a query condition to obtain desired objects.
public void queryAllBooks() {
if (mCloudDBZone == null) {
Log.w(TAG, "CloudDBZone is null, try re-open it");
return;
}
Task<CloudDBZoneSnapshot<BookInfo>> queryTask = mCloudDBZone.executeQuery(
CloudDBZoneQuery.where(BookInfo.class),
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 book list from cloud failed");
}
});
}fun queryAllBooks() {
if (mCloudDBZone == null) {
Log.w(TAG, "CloudDBZone is null, try re-open it")
return
}
val queryTask = mCloudDBZone!!.executeQuery(
CloudDBZoneQuery.where(BookInfo::class.java),
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY)
queryTask.addOnSuccessListener {snapshot -> processQueryResult(snapshot) }
.addOnFailureListener {
mUiCallBack.updateUiOnError("Query book list from cloud failed")
}
}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");
}
});
}
private void processQueryResult(CloudDBZoneSnapshot<BookInfo> snapshot) {
CloudDBZoneObjectList<BookInfo> bookInfoCursor = snapshot.getSnapshotObjects();
List<BookInfo> bookInfoList = new ArrayList<>();
try {
while (bookInfoCursor.hasNext()) {
BookInfo bookInfo = bookInfoCursor.next();
bookInfoList.add(bookInfo);
}
} catch (AGConnectCloudDBException e) {
Log.w(TAG, "processQueryResult: " + e.getMessage());
}
snapshot.release();
mUiCallBack.onAddOrQuery(bookInfoList);
}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")}
}
private fun processQueryResult(snapshot: CloudDBZoneSnapshot<BookInfo>) {
val bookInfoCursor = snapshot.snapshotObjects
val bookInfoList: MutableList<BookInfo> = ArrayList()
try {
while (bookInfoCursor.hasNext()) {
val bookInfo = bookInfoCursor.next()
bookInfoList.add(bookInfo)
}
} catch (e: AGConnectCloudDBException) {
Log.w(TAG, "processQueryResult: " + e.message)
} finally {
snapshot.release()
}
mUiCallBack.onAddOrQuery(bookInfoList)
}CloudDBZoneQuery<BookInfo> query = CloudDBZoneQuery.where(BookInfo.class).equalTo(BookEditFields.BOOK_NAME, "A Tale of Two Cities"); queryBooks(query);
val query = CloudDBZoneQuery.where(BookInfo::class.java).equalTo(BookEditFields.BOOK_NAME, "A Tale of Two Cities") queryBooks(query)
You can use multiple chain query conditions to obtain desired objects. By default, multiple chain conditions are connected using the AND operation, that is, and().
CloudDBZoneQuery<BookInfo> query = CloudDBZoneQuery.where(BookInfo.class).contains(BookEditFields.BOOK_NAME, "Database").greaterThan(BookEditFields.PRICE, 20.0).and().lessThan(BookEditFields.PRICE, 50.0); queryBooks(query);
val query = CloudDBZoneQuery.where(BookInfo::class.java).contains(BookEditFields.BOOK_NAME,
"Database").greaterThan(BookEditFields.PRICE, 20.0).and().lessThan(BookEditFields.PRICE, 50.0)
queryBooks(query)CloudDBZoneQuery<BookInfo> query = CloudDBZoneQuery.where(BookInfo.class).contains(BookEditFields.BOOK_NAME, "Database").lessThan(BookEditFields.PRICE, 20.0).or().greaterThan(BookEditFields.PRICE, 50.0); queryBooks(query);
val query = CloudDBZoneQuery.where(BookInfo::class.java).contains(BookEditFields.BOOK_NAME,
"Database").lessThan(BookEditFields.PRICE, 20.0).or().greaterThan(BookEditFields.PRICE, 50.0)
queryBooks(query)CloudDBZoneQuery<BookInfo> query = CloudDBZoneQuery.where(BookInfo.class).contains(BookEditFields.BOOK_NAME, "A Tale of Two Cities").equalTo(BookEditFields.AUTHOR, "Charles Dickens").greaterThan(BookEditFields.PRICE, 60.0); queryBooks(query);
val query = CloudDBZoneQuery.where(BookInfo::class.java).contains(BookEditFields.BOOK_NAME,
"A Tale of Two Cities").equalTo(BookEditFields.AUTHOR, "Charles Dickens").greaterThan(BookEditFields.PRICE, 60.0)
queryBooks(query)CloudDBZoneQuery<BookInfo> query = CloudDBZoneQuery.where(BookInfo.class).contains(BookEditFields.BOOK_NAME, "Autobiography").beginGroup().equalTo(BookEditFields.AUTHOR, "William Shakespeare").or().equalTo(BookEditFields.AUTHOR, "Charles Dickens").endGroup().greaterThan(BookEditFields.PRICE, 60.0); queryBooks(query);
val query = CloudDBZoneQuery.where(BookInfo::class.java).contains(BookEditFields.BOOK_NAME,
"Autobiography").beginGroup().equalTo(BookEditFields.AUTHOR, "William Shakespeare").or().equalTo(BookEditFields.AUTHOR, "Charles Dickens").endGroup().greaterThan(BookEditFields.PRICE, 60.0);
queryBooks(query)When querying data, you can use aggregate queries to query the average value, sum, maximum value, minimum value, and number of statistics records.
Querying the Average Value
You can call executeAverageQuery() to query objects that meet a specific query condition and calculate the average value of a specified field in the objects.
CloudDBZoneQuery<BookInfo> query = CloudDBZoneQuery.where(BookInfo.class);
Task<Double> averageQueryTask = mCloudDBZone.executeAverageQuery(query, BookEditFields.PRICE,
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY);
averageQueryTask.addOnSuccessListener(new OnSuccessListener<Double>() {
@Override
public void onSuccess(Double cloudDBZoneResult) {
Log.i(TAG, "Average price is " + cloudDBZoneResult);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception ex) {
Log.w(TAG, "Average query is failed: " + Log.getStackTraceString(ex));
}
});val query = CloudDBZoneQuery.where(BookInfo::class.java)
val averageQueryTask = mCloudDBZone!!.executeAverageQuery(query, BookEditFields.PRICE,
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY)
averageQueryTask.addOnSuccessListener {cloudDBZoneResult ->
Log.i(TAG, "Average price is $cloudDBZoneResult")
}.addOnFailureListener {
Log.w(TAG, "Average query is failed: " + Log.getStackTraceString(it))
}Querying the Sum
You can use executeSumQuery() to search for eligible objects and return the sum of the data record values of the specified fields.
CloudDBZoneQuery<BookInfo> query = CloudDBZoneQuery.where(BookInfo.class);
Task<Number> sumQueryTask = mCloudDBZone.executeSumQuery(query, BookEditFields.PRICE,
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY);
sumQueryTask.addOnSuccessListener(new OnSuccessListener<Number>() {
@Override
public void onSuccess(Number number) {
Log.i(TAG, "The sum of prices is " + number);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.w(TAG, "Sum query is failed: " + Log.getStackTraceString(e));
}
});val query = CloudDBZoneQuery.where(BookInfo::class.java)
val sumQueryTask = mCloudDBZone!!.executeSumQuery(query, BookEditFields.PRICE,
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY)
sumQueryTask.addOnSuccessListener { number ->
Log.i(TAG, "The sum of prices is $number")
}.addOnFailureListener {
Log.w(TAG, "Sum query is failed: " + Log.getStackTraceString(it))
}Querying the Maximum and Minimum Values
You can use executeMaximumQuery() or executeMinimalQuery() to search for eligible objects and obtain the maximum or minimum value in the data record values of the specified fields.
CloudDBZoneQuery<BookInfo> query = CloudDBZoneQuery.where(BookInfo.class);
Task<Number> maxQueryTask = mCloudDBZone.executeMaximumQuery(query, BookEditFields.PRICE,
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY);
maxQueryTask.addOnSuccessListener(new OnSuccessListener<Number>() {
@Override
public void onSuccess(Number number) {
Log.i(TAG, "The most expensive price is " + number);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.w(TAG, "Maximum query is failed: " + Log.getStackTraceString(e));
}
});val query = CloudDBZoneQuery.where(BookInfo::class.java)
val maxQueryTask = mCloudDBZone!!.executeMaximumQuery(query, BookEditFields.PRICE,
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY)
maxQueryTask.addOnSuccessListener { number ->
Log.i(TAG, "The most expensive price is $number")
}.addOnFailureListener {
Log.w(TAG, "Maximum query is failed: " + Log.getStackTraceString(it))
}CloudDBZoneQuery<BookInfo> query = CloudDBZoneQuery.where(BookInfo.class);
Task<Number> minQueryTask = mCloudDBZone.executeMinimalQuery(query, BookEditFields.PRICE,
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY);
minQueryTask.addOnSuccessListener(new OnSuccessListener<Number>() {
@Override
public void onSuccess(Number number) {
Log.i(TAG, "The cheapest price is " + number);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.w(TAG, "Minimal query is failed: " + Log.getStackTraceString(e));
}
});val query = CloudDBZoneQuery.where(BookInfo::class.java)
val minQueryTask = mCloudDBZone!!.executeMinimalQuery(query, BookEditFields.PRICE,
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY)
minQueryTask.addOnSuccessListener { number ->
Log.i(TAG, "The cheapest price is $number")
}.addOnFailureListener {
Log.w(TAG, "Minimal query is failed: " + Log.getStackTraceString(it))
}Querying the Number of Data Records
You can use executeCountQuery() to search for eligible objects and obtain the number of data records of the specified fields. During statistics collection, if the value of a field is not empty, count 1. Otherwise, count 0.
CloudDBZoneQuery<BookInfo> query = CloudDBZoneQuery.where(BookInfo.class);
Task<Long> countQueryTask = mCloudDBZone.executeCountQuery(query, BookEditFields.BOOK_ID,
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY);
countQueryTask.addOnSuccessListener(new OnSuccessListener<Long>() {
@Override
public void onSuccess(Long aLong) {
Log.i(TAG, "The total number of books is " + aLong);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.w(TAG, "Count query is failed: " + Log.getStackTraceString(e));
}
});val query = CloudDBZoneQuery.where(BookInfo::class.java)
val countQueryTask = mCloudDBZone!!.executeCountQuery(query, BookEditFields.BOOK_ID,
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY)
countQueryTask.addOnSuccessListener { aLong ->
Log.i(TAG, "The total number of books is $aLong")
}.addOnFailureListener {
Log.w(TAG, "Count query is failed: " + Log.getStackTraceString(it))
}You can use orderByAsc() or orderByDesc() to sort objects in the query result set by field in ascending or descending order.
When using orderByAsc() or orderByDesc() to sort fields, you are advised to create indexes for the sorted fields. Otherwise, when the number of data records of the object type reaches a certain value, the query may time out or fail due to low query efficiency, affecting user experience. For details about how to create an index, please refer to Adding and Exporting the Object Type File. After creating an index, you need to update the local object type file.
When sorting objects in query results, the sorting predicate must be placed after other query predicates and before the predicate that limits the number of returned query results.
Construct query conditions, call the queryBooks method to query books, and sort the books in descending order of price. Here, books cheaper than 50.0 are queried.
CloudDBZoneQuery<BookInfo> query = CloudDBZoneQuery.where(BookInfo.class); query.lessThan(BookEditFields.PRICE, 50.0).orderByDesc(BookEditFields.PRICE); queryBooks(query);
val query = CloudDBZoneQuery.where(BookInfo::class.java) query.lessThan(BookEditFields.PRICE, 50.0).orderByDesc(BookEditFields.PRICE) queryBooks(query)
You can use the startAt(), startAfter(), endAt(), or endBefore() method to specify the start or end position for data query.
Obtaining a Group of Data Records After a Specified Record
BookInfo book = new BookInfo(); book.setId(5); CloudDBZoneQuery<BookInfo> query = CloudDBZoneQuery.where(BookInfo.class).startAt(book); queryBooks(query);
val book = BookInfo() book.id = 5 val query = CloudDBZoneQuery.where(BookInfo::class.java).startAt(book) queryBooks(query)
Performing Intersection Processing on the Queried Data
// Query books whose BOOK_ID value range is [5,10). BookInfo book = new BookInfo(); book.setId(5); CloudDBZoneQuery<BookInfo> query = CloudDBZoneQuery.where(BookInfo.class) .lessThan(BookEditFields.BOOK_ID, 10) .orderByAsc(BookEditFields.BOOK_ID) .startAt(book); queryBooks(query);
// Query books whose BOOK_ID value range is [5,10).
val book = BookInfo()
book.id = 5
val query = CloudDBZoneQuery.where(BookInfo::class.java)
.lessThan(BookEditFields.BOOK_ID, 10)
.orderByAsc(BookEditFields.BOOK_ID)
.startAt(book);
queryBooks(query);Obtaining Data Records Before a Specified Record in Query Results Sorted by Multiple Fields
Call endAt() and orderByAsc() to sort the queried data by multiple specified fields and return the data before the specified end position. The returned result contains the specified data record at the end position.
// Query the books whose BookName is The Red and the Black and Price is 10.0 until the record with BOOK_ID set to 5 is found.
BookInfo book = new BookInfo();
book.setId(5);
book.setBookName("The Red and the Black");
book.setPrice(10.0);
CloudDBZoneQuery<BookInfo> query = CloudDBZoneQuery.where(BookInfo.class)
.orderByAsc(BookEditFields.BOOK_NAME)
.orderByAsc(BookEditFields.PRICE)
.endAt(book);
queryBooks(query);// Query the books whose BookName is The Red and the Black and Price is 10.0 until the record with BOOK_ID set to 5 is found.
val book = BookInfo()
book.id = 5
book.bookName = "The Red and the Black"
book.price = 10.0
val query = CloudDBZoneQuery.where(BookInfo::class.java)
.orderByAsc(BookEditFields.BOOK_NAME)
.orderByAsc(BookEditFields.PRICE)
.endAt(book)
queryBooks(query)You can use the limit() method separately or together with tuple query to implement pagination query. You can also call equalTo(), orderByAsc(), orderByDesc(), greaterThan(), greaterThanOrEqualTo(), lessThan(), lessThanOrEqualTo(), or(), beginGroup(), and endGroup() to construct query conditions.
To ensure the performance of pagination query, you need to create the index required by Cloud DB before constructing the pagination query conditions. If no index is created, you may receive an exception message. You need to create the missing index based on the exception message. For details about how to create an index, please refer to Adding and Exporting the Object Type File. After creating an index, you need to update the local object type file.
Using Tuple Query and the limit() Method Together
Call the startAt() method to define the start position of the query and call limit() and orderByAsc() to implement pagination. The last record in the first query result is used as the start point of the next query.
// Query 10 records on the first page.
CloudDBZoneQuery<BookInfo> queryFirst = CloudDBZoneQuery.where(BookInfo.class)
.equalTo(BookEditFields.PUBLISHER, "People's Press")
.orderByAsc(BookEditFields.BOOK_ID)
.limit(10);
Task<CloudDBZoneSnapshot<BookInfo>> queryTask = zone.executeQuery(queryFirst,
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_DEFAULT);
// Wait for the query result.
CloudDBZoneSnapshot<BookInfo> result = null;
queryTask.addOnSuccessListener(new OnSuccessListener<CloudDBZoneSnapshot<BookInfo>>() {
@Override
public void onSuccess(CloudDBZoneSnapshot<BookInfo> snapshot) {
// Use the 10th record as the start point of the next query to obtain data records (excluding the record at the start point) on the next page.
try {
BookInfo nextBook = snapshot.getSnapshotObjects().get(snapshot.getSnapshotObjects().size() - 1);
CloudDBZoneQuery<BookInfo> queryNext = CloudDBZoneQuery.where(BookInfo.class)
.equalTo(BookEditFields.PUBLISHER, "People's Press")
.startAfter(nextBook)
.orderByAsc(BookEditFields.BOOK_ID)
.limit(10);
Task<CloudDBZoneSnapshot<BookInfo>> queryTaskNext = zone.executeQuery(
queryNext,
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_DEFAULT);
} catch (AGConnectCloudDBException e) {
Log.w(TAG, "Exception occurred, info:" + e.getMessage());
} finally {
snapshot.release();
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, "Query failed, info:" + Log.getStackTracesString(e));
}
});// Query 10 records on the first page.
val queryFirst = CloudDBZoneQuery.where(BookInfo::class.java)
.equalTo(BookEditFields.PUBLISHER, "People's Press")
.orderByAsc(BookEditFields.BOOK_ID)
.limit(10);
val queryTask = mCloudDBZone!!.executeQuery(queryFirst,
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_DEFAULT)
// Wait for the query result.
queryTask.addOnSuccessListener { snapshot ->
// Use the 10th record as the start point of the next query to obtain data records (excluding the record at the start point) on the next page.
try {
val nextBook = snapshot.snapshotObjects.get(snapshot.snapshotObjects.size() - 1)
val queryNext = CloudDBZoneQuery.where(BookInfo::class.java)
.equalTo(BookEditFields.PUBLISHER, "People's Press")
.startAfter(nextBook)
.orderByAsc(BookEditFields.BOOK_ID)
.limit(10)
val queryTaskNext = mCloudDBZone!!.executeQuery(queryNext,
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_DEFAULT)
} catch (e: AGConnectCloudDBException) {
Log.w(TAG, "Exception occurred, info:" + e.message)
} finally {
snapshot.release()
}
}.addOnFailureListener { e ->
Log.e(TAG, "Query failed, info:" + Log.getStackTracesString(e))
}Using the limit Method Separately
// Query the first 10 books cheaper than 50.
int pageNo = 1; // Page number.
int pageSize = 10 // Total number of records on each page.
CloudDBZoneQuery<BookInfo> queryFirst = CloudDBZoneQuery.where(BookInfo.class)
.lessThan(BookEditFields.PRICE, 50.0)
.orderByAsc(BookEditFields.BOOK_ID)
.limit(pageSize, (pageNo - 1) * pageSize);
Task<CloudDBZoneSnapshot<BookInfo>> queryTask = zone.executeQuery(queryFirst,
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_DEFAULT);
// Wait for the query result.
CloudDBZoneSnapshot<BookInfo> result = null;
queryTask.addOnSuccessListener(new OnSuccessListener<CloudDBZoneSnapshot<BookInfo>>() {
@Override
public void onSuccess(CloudDBZoneSnapshot<BookInfo> snapshot) {
// Use the 10th record as the start point of the next query to obtain data records (excluding the record at the start point) on the next page.
pageNo++;
try {
BookInfo nextBook = snapshot.getSnapshotObjects().get(snapshot.getSnapshotObjects().size() - 1);
CloudDBZoneQuery<BookInfo> queryNext = CloudDBZoneQuery.where(BookInfo.class)
.lessThan(BookEditFields.PRICE, 50.0)
.orderByAsc(BookEditFields.BOOK_ID)
.limit(pageSize, (pageNo - 1) * pageSize);
Task<CloudDBZoneSnapshot<BookInfo>> queryTaskNext = zone.executeQuery(
queryNext,
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_DEFAULT);
} catch (AGConnectCloudDBException e) {
Log.w(TAG, "Exception occurred, info:" + e.getMessage());
} finally {
snapshot.release();
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, "Query failed, info:" + Log.getStackTracesString(e));
}
});// Query the first 10 books cheaper than 50.
val pageNo = 1; // Page number.
val pageSize = 10 // Total number of records on each page.
val queryFirst = CloudDBZoneQuery.where(BookInfo::class.java)
.lessThan(BookEditFields.PRICE, 50)
.orderByAsc(BookEditFields.BOOK_ID)
.limit(pageSize, (pageNo - 1) * pageSize)
val queryTask = mCloudDBZone!!.executeQuery(queryFirst,
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_DEFAULT)
// Wait for the query result.
queryTask.addOnSuccessListener { snapshot ->
// Use the 10th record as the start point of the next query to obtain data records (excluding the record at the start point) on the next page.
pageNo++
try {
val nextBook = snapshot.snapshotObjects.get(snapshot.snapshotObjects.size() - 1)
val queryNext = CloudDBZoneQuery.where(BookInfo::class.java)
.lessThan(BookEditFields.PRICE, 50)
.orderByAsc(BookEditFields.BOOK_ID)
.limit(pageSize, (pageNo - 1) * pageSize)
val queryTaskNext = mCloudDBZone!!.executeQuery(queryNext,
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_DEFAULT)
} catch (e: AGConnectCloudDBException) {
Log.w(TAG, "Exception occurred, info:" + e.message)
} finally {
snapshot.release()
}
}.addOnFailureListener { e ->
Log.e(TAG, "Query failed, info:" + Log.getStackTracesString(e))
}You can use the executeDelete() method to delete a single object or a group of objects. When deleting data, Cloud DB will delete the corresponding data based on the input object primary key and does not check whether other attributes of the object are consistent with the stored data. The delete operation is atomic. That is, all objects in the list either are deleted successfully or fail to be deleted.
Precautions:
Read the precautions carefully.
Sample code:
When you delete objects, the number of deleted objects will be returned if the deletion succeeds; otherwise, an exception will be returned.
// bookInfoList is the dataset returned by the query operation or listener.
public void deleteBookInfosAsync(List<BookInfo> bookInfoList) {
if (mCloudDBZone == null) {
Log.w(TAG, "CloudDBZone is null, try re-open it");
return;
}
Task<Integer> deleteTask = mCloudDBZone.executeDelete(bookInfoList);
deleteTask.addOnSuccessListener(new OnSuccessListener<Integer>() {
@Override
public void onSuccess(Integer integer) {
mUiCallBack.onDelete(bookInfoList);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
mUiCallBack.updateUiOnError("Delete book info failed");
}
});
}// bookInfoList is the dataset returned by the query operation or listener.
fun deleteBookInfosAsync(bookInfoList: List<BookInfo?>?) {
if (mCloudDBZone == null) {
Log.w(TAG, "CloudDBZone is null, try re-open it")
return
}
val deleteTask = mCloudDBZone!!.executeDelete(bookInfoList!!)
deleteTask.addOnSuccessListener {
mUiCallBack.onDelete(bookInfoList)
}.addOnFailureListener {
mUiCallBack.updateUiOnError("Delete book info failed")
}
}You can use the subscribeSnapshot() method to listen to data changes that meet the specified query conditions. When data changes, Cloud DB will trigger your custom callback function and transfer the data to the callback function as snapshots for you to process based on the service logic.
When a data query policy is executed, the registered snapshot listener is immediately called when you add, delete, or modify data locally, instead of waiting for data synchronization to the cloud.
You can call the getUpsertedObjects() method in the CloudDBZoneSnapshot class to obtain the objects added or modified, the getDeletedObjects() method for objects deleted, compared with the last snapshot, and the release() method to free up resources occupied by the snapshot.
Prerequisites:
The Cloud DB zone uses cache for data synchronization.
Precautions:
Read the precautions carefully.
Listening to Data Changes on the Cloud
Add a listener for cloud data changes. When data on the cloud changes, a snapshot is generated so that you can obtain data change information through the snapshot. After the snapshot is used, resources must be freed up by explicitly calling release() of the CloudDBZoneSnapshot class; otherwise, the latest snapshot object cannot be obtained and the snapshot listener cannot be deregistered.
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();
}
}
};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()
}
}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());
}
}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)
}
}Deregistering a Listener
A listener can be deregistered by calling remove() in the ListenerHandler class.
mRegister.remove();
mRegister!!.remove()
Cloud DB can manage data in the Cloud DB zone on the cloud by calling runTransaction(), including adding, deleting, modifying, and querying data. You can add, delete, modify, and query data of multiple object types in a transaction at the same time. Transactions are atomic. Operations in a transaction either all succeed or all fail to be executed. If concurrent writes occur during transaction execution, Cloud DB will attempt to execute the entire transaction again to ensure the consistency of the entire transaction.
Prerequisites:
The Cloud DB zone uses cache for data synchronization.
Precautions:
Read the precautions carefully.
Sample code:
// Define a transaction that encapsulates the query and delete operations.
public void deleteOverdueBooks(CloudDBZoneQuery<BookInfo> query) {
Transaction.Function function = new Transaction.Function() {
@Override
public boolean apply(Transaction transaction) {
try {
List<BookInfo> bookInfos = transaction.executeQuery(query);
transaction.executeDelete(bookInfos);
} catch (AGConnectCloudDBException e) {
e.printStackTrace();
return false;
}
return true;
}
};
mCloudDBZone.runTransaction(function);
}
// Construct a query condition and call the defined transaction to complete the delete operation.
try {
CloudDBZoneQuery<BookInfo> query = CloudDBZoneQuery.where(BookInfo.class)
.lessThan(BookEditFields.PUBLISH_TIME, DateUtils.parseDate("1990-01-01"));
deleteOverdueBooks(query);
} catch (AGConnectCloudDBException e) {
e.printStackTrace();
}// Define a transaction that encapsulates the query and delete operations.
fun deleteOverdueBooks(query: CloudDBZoneQuery<BookInfo>) {
val function = Transaction.Function(fun(transaction): Boolean {
try {
val bookInfos = transaction.executeQuery(query)
transaction.executeDelete(bookInfos)
} catch (e: AGConnectCloudDBException) {
Log.w(TAG, "Transaction error, info: " + Log.getStackTraceString(e))
return false
}
return true
})
mCloudDBZone!!.runTransaction(function)
}
// Construct a query condition and call the defined transaction to complete the delete operation.
try {
val query = CloudDBZoneQuery.where(BookInfo::class.java)
.lessThan(BookEditFields.PUBLISH_TIME, DateUtils.parseDate("1990-01-01"))
deleteOverdueBooks(query)
} catch (e: AGConnectCloudDBException) {
Log.w(TAG, "Exception occurred, info: " + Log.getStackTraceString(e))
}Cloud DB provides full-process encryption management for private or sensitive data. After this function is enabled, user data is encrypted on the device, sent in ciphertext, and stored on the cloud. Only the user who enters the password can obtain information about their key and access their encrypted data. In this way, user data security is effectively improved, and user data on the cloud is prevented from being leaked.
You can create an object type and set an encryption field in AppGallery Connect to enable the full-process encryption function for the field. After importing an object type file to the local development environment, you need to use the setUserKey() method to set a user password. Cloud DB uses the password to derive information about the key and saves the encrypted information and user data in ciphertext on the cloud. The encryption key is bound to the user account. Only the user who enters the password can obtain information about the key and access the encrypted data. User passwords are saved by users and will not be synchronized to the cloud.
Precautions:
Read the precautions carefully.
Task<Boolean> setUserKeyTask = mCloudDB.setUserKey("xxxxxxxxx", null, true);
setUserKeyTask.addOnCompleteListener(task -> {
StringBuilder builder = new StringBuilder();
if (task.getException() != null) {
builder.append("exception : ").append(task.getException());
mResultInfo.setText(builder.toString());
return;
}
boolean isSuccess = task.getResult();
if (isSuccess) {
updateUi("set user key success.");
} else {
updateUi("set user key fail.");
}
});val setUserKeyTask = mCloudDB.setUserKey("xxxxxxxxx", null, true)
setUserKeyTask.addOnCompleteListener { task ->
val builder = StringBuilder()
if (task.exception != null) {
builder.append("exception : ").append(task.exception)
mResultInfo.setText(builder.toString())
return@addOnCompleteListener
}
val isSuccess = task.result
if (isSuccess) {
updateUi("set user key success.")
} else {
updateUi("set user key fail.")
}
}String userReKey = "xxxxxxxxx";
mCloudDB.addEventListener(new AGConnectCloudDB.EventListener() {
@Override
public void onEvent(AGConnectCloudDB.EventType eventType) {
if (eventType.equals(AGConnectCloudDB.EventType.USER_KEY_CHANGED)) {
Task<Boolean> setUserKeyTask = mCloudDB.setUserKey(userReKey, null, true);
setUserKeyTask.addOnCompleteListener(task -> {
StringBuilder builder = new StringBuilder();
if (task.getException() != null) {
builder.append("exception : ").append(task.getException());
mResultInfo.setText(builder.toString());
return;
}
boolean isSuccess = task.getResult();
if (isSuccess) {
updateUi("set user key success.");
} else {
updateUi("set user key fail.");
}
});
}
}
});val userReKey = "xxxxxxxxx"
mCloudDB.addEventListener { eventType ->
if (eventType == AGConnectCloudDB.EventType.USER_KEY_CHANGED) {
val setUserKeyTask = mCloudDB.setUserKey(userReKey, null, true)
setUserKeyTask.addOnCompleteListener { task ->
val builder = StringBuilder()
if (task.exception != null) {
builder.append("exception : ").append(task.exception)
mResultInfo.setText(builder.toString())
return@addOnCompleteListener
}
val isSuccess = task.result
if (isSuccess) {
updateUi("set user key success.")
} else {
updateUi("set user key fail.")
}
}
}
}Task<Boolean> updateDataEncryptionKeyTask = mCloudDB.updateDataEncryptionKey();
updateDataEncryptionKeyTask.addOnCompleteListener(task -> {
StringBuilder builder = new StringBuilder();
if (task.getException() != null) {
builder.append("exception : ").append(task.getException());
mResultInfo.setText(builder.toString());
return;
}
boolean isSuccess = task.getResult();
if (isSuccess) {
updateUi("update data key success.");
} else {
updateUi("update data key fail.");
}
});val updateDataEncryptionKeyTask = mCloudDB.updateDataEncryptionKey();
updateDataEncryptionKeyTask.addOnCompleteListener { task ->
val builder = StringBuilder()
if (task.exception != null) {
builder.append("exception : ").append(task.exception)
mResultInfo.setText(builder.toString())
return@addOnCompleteListener
}
val isSuccess = task.result
if (isSuccess) {
updateUi("update data key success.")
} else {
updateUi("update data key fail.")
}
}mCloudDB.addDataEncryptionKeyListener(new AGConnectCloudDB.OnDataEncryptionKeyChangeListener() {
@Override
public boolean needFetchDataEncryptionKey() {
return true;
}
});mCloudDB.addDataEncryptionKeyListener( fun(): Boolean {
return true
})Cloud DB provides a function to encrypt local data by Cloud DB zone. You can set the encryption key when creating a CloudDBZoneConfig object to meet your needs. You can call setEncryptedKey() to set or change the encryption key.
Precautions:
The encryption mode cannot be changed. If a Cloud DB zone is encrypted when opened for the first time, the encryption key will be required every time the Cloud DB zone is opened. Similarly, if a Cloud DB zone is not encrypted when opened for the first time, it will not be encrypted every time it is opened in the future.
Sample code:
The initial key is xxxxxxxxx, which is passed through setEncryptedKey(). Then open the Cloud DB zone.
mConfig = new CloudDBZoneConfig("QuickStartDemo",
CloudDBZoneConfig.CloudDBZoneSyncProperty.CLOUDDBZONE_CLOUD_CACHE,
CloudDBZoneConfig.CloudDBZoneAccessProperty.CLOUDDBZONE_PUBLIC);
// The first parameter indicates the initial key xxxxxxxxx, and the second parameter indicates the new key. If the second parameter is left empty, the key is not changed.
mConfig.setEncryptedKey("xxxxxxxxx", "");
mConfig.setPersistenceEnabled(true);
...
Task<CloudDBZone> openDBZoneTask = mCloudDB.openCloudDBZone2(mConfig, true);
openDBZoneTask.addOnSuccessListener( cloudDBZone -> {
Log.i(TAG, "Open cloudDBZone success");
mCloudDBZone = cloudDBZone;
}).addOnFailureListener( e -> {
Log.w(TAG, Objects.requireNonNull(e.getMessage()));
});mConfig = CloudDBZoneConfig("QuickStartDemo",
CloudDBZoneConfig.CloudDBZoneSyncProperty.CLOUDDBZONE_CLOUD_CACHE,
CloudDBZoneConfig.CloudDBZoneAccessProperty.CLOUDDBZONE_PUBLIC)
// The first parameter indicates the initial key xxxxxxxxx, and the second parameter indicates the new key. If the second parameter is left empty, the key is not changed.
mConfig!!.setEncryptedKey("xxxxxxxxx", "")
mConfig!!.persistenceEnabled = true
...
val openDBZoneTask = mCloudDB.openCloudDBZone2(mConfig!!, true)
openDBZoneTask.addOnSuccessListener { cloudDBZone ->
Log.i(TAG, "Open cloudDBZone success")
mCloudDBZone = cloudDBZone
}.addOnFailureListener { e ->
Log.w(TAG, Objects.requireNonNull(e.message))
}The first parameter of setEncryptedKey() is the initial key, and the second parameter is the new key. After the change, open the Cloud DB zone again.
mConfig = new CloudDBZoneConfig("QuickStartDemo",
CloudDBZoneConfig.CloudDBZoneSyncProperty.CLOUDDBZONE_CLOUD_CACHE,
CloudDBZoneConfig.CloudDBZoneAccessProperty.CLOUDDBZONE_PUBLIC);
// Change the key from xxxxxxxxx to xxxxxxxxx.
mConfig.setEncryptedKey("xxxxxxxxx", "xxxxxxxxx");
mConfig.setPersistenceEnabled(true);
...
Task<CloudDBZone> openDBZoneTask = mCloudDB.openCloudDBZone2(mConfig, true);
openDBZoneTask.addOnSuccessListener( cloudDBZone -> {
Log.i(TAG, "Open cloudDBZone success");
mCloudDBZone = cloudDBZone;
}).addOnFailureListener( e -> {
Log.w(TAG, Objects.requireNonNull(e.getMessage()));
});mConfig = CloudDBZoneConfig("QuickStartDemo",
CloudDBZoneConfig.CloudDBZoneSyncProperty.CLOUDDBZONE_CLOUD_CACHE,
CloudDBZoneConfig.CloudDBZoneAccessProperty.CLOUDDBZONE_PUBLIC)
// Change the key from xxxxxxxxx to xxxxxxxxx.
mConfig!!.setEncryptedKey("xxxxxxxxx", "xxxxxxxxx")
mConfig!!.persistenceEnabled = true
...
val openDBZoneTask = mCloudDB.openCloudDBZone2(mConfig!!, true);
openDBZoneTask.addOnSuccessListener { cloudDBZone ->
Log.i(TAG, "Open cloudDBZone success")
mCloudDBZone = cloudDBZone
}.addOnFailureListener { e ->
Log.w(TAG, Objects.requireNonNull(e.message))
}Each Cloud DB zone is a data storage zone that is independent of each other. Data in different Cloud DB zones is not associated. Multiple Cloud DB zones can be created in a Cloud DB instance.
Cloud DB synchronizes data in cache or local mode by Cloud DB zone. When developing an app, you can select a data synchronization mode for each Cloud DB zone based on app requirements. The data that can be managed varies according to the data synchronization mode.
In this mode, you can implement device-cloud data synergy management so that data can be synchronized between the device and cloud or among multiple devices. App data is stored on the cloud, and data on the device is a subset of data on the cloud. If persistent cache is allowed, Cloud DB supports the automatic caching of query results on the device. When data is cached, the local data that is not synchronized will not be overwritten.
In this mode, users can only operate the local device data, and data cannot be synchronized between the device and cloud or among multiple devices.
Multiple object types can be defined in a Cloud DB zone to support different service requirements. Each Cloud DB zone has the same object type definition. You can customize the objects stored in the Cloud DB zone based on app requirements.
If any Cloud DB zone is not required, you can close it temporarily. You can also delete the Cloud DB zone to free up resources.
Precautions:
Read the precautions carefully.
Sample code:
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( cloudDBZone -> {
Log.i(TAG, "Open cloudDBZone success");
mCloudDBZone = cloudDBZone;
}).addOnFailureListener( e -> {
Log.w(TAG, "Open cloudDBZone failed for " + e.getMessage());
});mConfig = CloudDBZoneConfig("QuickStartDemo",
CloudDBZoneConfig.CloudDBZoneSyncProperty.CLOUDDBZONE_CLOUD_CACHE,
CloudDBZoneConfig.CloudDBZoneAccessProperty.CLOUDDBZONE_PUBLIC)
mConfig!!.persistenceEnabled = true
val openDBZoneTask = mCloudDB.openCloudDBZone2(mConfig!!, true)
openDBZoneTask.addOnSuccessListener { cloudDBZone ->
Log.i(TAG, "Open cloudDBZone success")
mCloudDBZone = cloudDBZone
}.addOnFailureListener { e ->
Log.w(TAG, "Open cloudDBZone failed for " + e.message)
}mConfig = new CloudDBZoneConfig("QuickStartDemo",
CloudDBZoneConfig.CloudDBZoneSyncProperty.CLOUDDBZONE_LOCAL_ONLY,
CloudDBZoneConfig.CloudDBZoneAccessProperty.CLOUDDBZONE_PUBLIC);
mConfig.setPersistenceEnabled(true);
Task<CloudDBZone> openDBZoneTask = mCloudDB.openCloudDBZone2(mConfig, true);
openDBZoneTask.addOnSuccessListener( cloudDBZone -> {
Log.i(TAG, "Open cloudDBZone success");
mCloudDBZone = cloudDBZone;
}).addOnFailureListener( e -> {
Log.w(TAG, "Open cloudDBZone failed for " + e.getMessage());
});mConfig = CloudDBZoneConfig("QuickStartDemo",
CloudDBZoneConfig.CloudDBZoneSyncProperty.CLOUDDBZONE_LOCAL_ONLY,
CloudDBZoneConfig.CloudDBZoneAccessProperty.CLOUDDBZONE_PUBLIC)
mConfig!!.persistenceEnabled = true
val openDBZoneTask = mCloudDB.openCloudDBZone2(mConfig!!, true)
openDBZoneTask.addOnSuccessListener { cloudDBZone ->
Log.i(TAG, "Open cloudDBZone success")
mCloudDBZone = cloudDBZone
}.addOnFailureListener {
Log.w(TAG, "Open cloudDBZone failed for " + it.message)
}mCloudDB.closeCloudDBZone(mCloudDBZone);
mCloudDB.closeCloudDBZone(mCloudDBZone)
This method will also delete local data. Confirm the operation before a call.
mCloudDB.deleteCloudDBZone(mConfig.getCloudDBZoneName());
mCloudDB.deleteCloudDBZone(mConfig!!.cloudDBZoneName)
During an app update, you can export the corresponding version file from AppGallery Connect and add it to the local development environment. Call the createObjectType() method in the AGConnectCloudDB class to create an object type, and call the openCloudDBZone2() method to open the specified Cloud DB zone and update the object type version. After the on-device version is updated, new fields in the object type are left empty or use the default values, while data of the existing fields remains unchanged. In cache mode, when the device queries data on the cloud, the latest data is updated to the local device based on the query result. If the device does not query data on the cloud, then data on the cloud will not be updated to the device. In this case, data on the device will remain unchanged after the update. That is, new fields are left empty or use the default values, while data of the existing fields remains unchanged.