AppGallery Connect (AGC) Cloud DB Service provides collaborative management of device-cloud data, unified data models, and abundant data management APIs. It ensures data availability, reliability, consistency, and security, implements seamless data synchronization between the client and cloud, and provides offline support for applications, helping developers quickly build device-cloud and multi-device collaborative applications.
In this codelab, you will create an Android application based on the AGC Cloud DB. Your application will be able to add, modify, and delete data, and synchronize between the device and cloud.
Prepare a device running Android 4.4 or later version.
To integrate the AGC Cloud DB service, you need to complete the following preparations:
Before integrating the Cloud DB SDK, you need to enable the Cloud DB service. The procedure is as follows:
If you are using Android Studio, you need to integrate the Cloud DB SDK into your Android Studio project before development.
dependencies {
// Add the Cloud DB SDK.
implementation 'com.huawei.agconnect:agconnect-cloud-database:1.4.7.300'
}
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
The sample code in this codelab uses the anonymous sign-in mode. Therefore, you need to enable the anonymous account authentication mode of Auth Service in AGC. Otherwise, the sign-in fails.
implementation 'com.huawei.agconnect:agconnect-auth:1.5.0.300'
public void login() {
AGConnectAuth auth = AGConnectAuth.getInstance();
auth.signInAnonymously().addOnSuccessListener(mActivity, signInResult -> {
Log.w(TAG, "addOnSuccessListener: " + signInResult.getUser().getDisplayName());
for (OnLoginEventCallBack loginEventCallBack : mLoginCallbacks) {
loginEventCallBack.onLogin(true, signInResult);
}
}).addOnFailureListener(mActivity, e -> {
Log.w(TAG, "sign in for agc failed: " + e.getMessage());
for (OnLoginEventCallBack loginEventCallBack : mLoginCallbacks) {
loginEventCallBack.onLogOut(false);
}
});
}
Field Name | Type | Primary Key | Not Null | Encryption | Default Value |
id | Integer | √ | √ | – | – |
bookName | String | – | – | – | – |
author | String | – | – | – | – |
price | Double | – | – | – | – |
publisher | String | – | – | – | – |
publishTime | Date | – | – | – | – |
shadowFlag | Boolean | – | – | – | true |
Role | query | upsert | delete |
Everyone | √ | – | – |
Authenticated users | √ | √ | √ |
Data creator | √ | √ | √ |
Administrator | √ | √ | √ |
During application development, you can directly add the JAVA files exported from the AGC console to the local development environment, and use the createObjectType() method in the AGConnectCloudDB class to define and create object types. Then you do not need to create object types for local application development.
Add all exported files to the local development environment. If the files exist, replace them. The file is stored in the < agc-clouddb-demo-java >/app/src/main/java/com/huawei/agc/clouddb/quickstart/model directory.
After adding the object type file, you can use the Cloud DB for application development. Before developing an application, you need to initialize AGConnectCloudDB and create a Cloud DB zone and object type. The key code for each initialization step is as follows:
public static void initAGConnectCloudDB(Context context) {
AGConnectCloudDB.initialize(context);
}
public CloudDBZoneWrapper() {
mCloudDB = AGConnectCloudDB.getInstance();
}
public void createObjectType() {
try {
mCloudDB.createObjectType(ObjectTypeInfoHelper.getObjectTypeInfo());
} catch (AGConnectCloudDBException e) {
Log.w(TAG, "createObjectType: " + e.getMessage());
}
}
public void openCloudDBZoneV2() {
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.w(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());
}
});
}
This section mainly describes how to write data to an application using the Cloud DB SDK. On the application screen, the Add button is added for users to add data and use executeUpsert() to write data in the CloudDBZoneWrapper. The executeUpsert() method is encapsulated. You can directly use the upsertBookInfos() method to write data. The key code is as follows:
public void upsertBookInfos(BookInfo bookInfo) {
if (mCloudDBZone == null) {
Log.w(TAG, "CloudDBZone is null, try re-openit");
return;
}
Task upsertTask = mCloudDBZone.executeUpsert(bookInfo);
upsertTask.addOnSuccessListener(new OnSuccessListener() {
@Override
public void onSuccess(Integer cloudDBZoneResult) {
Log.w(TAG, "upsert " + cloudDBZoneResult + " records");
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
mUiCallBack.updateUiOnError("Insert book info failed");
}
});
}
}
This section describes how to view data in an application, including displaying all data and obtaining updated data.
All data is displayed each time you enter the main screen of the application. Call executeQuery(). Set the first parameter to CloudDBZoneQuery.where(BookInfo.class). When the query is successful, execute addOnSuccessListener(). All queried data is transferred through the snapshot parameter. The key code is as follows:
public void queryAllBooks() {
if (mCloudDBZone == null) {
Log.w(TAG, "CloudDBZone is null, try re-open it");
return;
}
Task> queryTask = mCloudDBZone.executeQuery(
CloudDBZoneQuery.where(BookInfo.class),
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY);
queryTask.addOnSuccessListener(new OnSuccessListener>() {
@Override
public void onSuccess(CloudDBZoneSnapshot snapshot) {
processQueryResult(snapshot);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
mUiCallBack.updateUiOnError("Query book list from cloud failed");
}
});
}
Data added by users on the application screen will be synchronized to the cloud. You can add a listener on the device to listen to the objects that meet the conditions. When the object data that meets the conditions changes, the data is pushed to the device. The device can receive the changed object data in the listener callback.
When the application is started, you can use the subscribeSnapshot() method to register the listening of data changes and use the listener mSnapshotListener to obtain data changes in real time.
public void addSubscription() {
if (mCloudDBZone == null) {
Log.w(TAG, "CloudDBZone is null, try re-open it");
return;
}
try {
CloudDBZoneQuery 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());
}
}
Obtain the updated data by defining the listener mSnapshotListener. You can use getSnapshotObjects() to obtain the latest data, use next() to traverse specific objects, and use mUiCallBack.onSubscribe(bookInfos) to update the UI.
private OnSnapshotListener mSnapshotListener = new OnSnapshotListener() {
@Override
public void onSnapshot(CloudDBZoneSnapshot cloudDBZoneSnapshot, AGConnectCloudDBException e) {
if (e != null) {
Log.w(TAG, "onSnapshot: " + e.getMessage());
return;
}
CloudDBZoneObjectList snapshotObjects = cloudDBZoneSnapshot.getSnapshotObjects();
List 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();
}
}
};
In this section, we'll focus on how to sort data and filter queries in an application.
On the application screen, click titles such as the book name, author, and unit price to sort existing data. Use orderByAsc() to sort data in ascending order and orderByDesc() to sort data in descending order. The input parameter is the field name in the column, for example, BookEditFields .BOOK_NAME. The key code is as follows:
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));
}
The button is added to the application screen. Click the button to query a book. Filter and query data by book name, unit price range, and number of displayed records. Use the executeQuery() API to query data. The first parameter in executeQuery() is the query condition, and the second parameter is the data source to be queried. POLICY_QUERY_FROM_CLOUD_ONLY is used to query data on the cloud. The key code is as follows:
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");
}
});
}
The query parameter is used to set the query conditions, such as the book name, unit price range, and number of records to be displayed.
private void processSearchAction(Intent data) {
CloudDBZoneQuery<BookInfo> query = CloudDBZoneQuery.where(BookInfo.class);
String bookName = data.getStringExtra(BookEditFields.BOOK_NAME);
if (!TextUtils.isEmpty(bookName)) {
query.contains(BookEditFields.BOOK_NAME, bookName);
mQueryInfo.bookName = bookName;
}
double lowestPrice = data.getDoubleExtra(BookEditFields.LOWEST_PRICE, 0);
double highestPrice = data.getDoubleExtra(BookEditFields.HIGHEST_PRICE, 0);
if (lowestPrice > highestPrice) {
double temp = lowestPrice;
lowestPrice = highestPrice;
highestPrice = temp;
}
mQueryInfo.lowestPrice = lowestPrice;
mQueryInfo.highestPrice = highestPrice;
query.greaterThanOrEqualTo(BookEditFields.PRICE, lowestPrice);
if (mQueryInfo.lowestPrice != mQueryInfo.highestPrice || mQueryInfo.lowestPrice != 0.0) {
query.lessThanOrEqualTo(BookEditFields.PRICE, mQueryInfo.highestPrice);
}
int showCount = data.getIntExtra(BookEditFields.SHOW_COUNT, 0);
if (showCount > 0) {
query.limit(showCount);
mQueryInfo.showCount = showCount;
}
toggleShowAllState(true);
mHandler.post(() -> mCloudDBZoneWrapper.queryBooks(query));
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
mActivity = (MainActivity) getActivity();
mHandler = new Handler(Looper.getMainLooper());
mBookInfoAdapter = new BookInfoAdapter(getContext());
mHandler.post(() -> {
LoginHelper loginHelper = mActivity.getLoginHelper();
loginHelper.addLoginCallBack(this);
loginHelper.login();
});
}
Congratulations! You have successfully built your first application that integrates the AGC Cloud DB service and learned how to build an application for device-cloud collaborative data management through the AGC Cloud DB.
For details about the APIs of AGC Cloud DB, see the Cloud DB API Reference.
Download the demo source code used in this codelab: