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 app based on the AppGallery Connect Cloud DB, where data can be written and viewed and synchronized between the device and cloud.
A device running Android 4.2 or a later version
To integrate the AppGallery Connect 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.5.0.300'
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="@dimen/layout_margin"
android:layout_marginRight="@dimen/layout_margin">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/field_bookname"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:visibility="visible"
android:weightSum="7"
app:layout_constraintTop_toBottomOf="parent">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="@string/book_name" />
<EditText
android:id="@+id/edit_bookname"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_weight="5"
android:importantForAutofill="no"
android:inputType="text"
android:labelFor="@id/edit_bookname"
android:maxLength="20" />
</LinearLayout>
<LinearLayout
android:id="@+id/field_author"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:visibility="gone"
android:weightSum="7"
app:layout_constraintTop_toBottomOf="parent">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="@string/author" />
<EditText
android:id="@+id/edit_author"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_weight="5"
android:importantForAutofill="no"
android:inputType="text"
android:labelFor="@id/edit_author"
android:maxLength="20" />
</LinearLayout>
<LinearLayout
android:id="@+id/field_price"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:visibility="gone"
android:weightSum="7"
app:layout_constraintTop_toBottomOf="parent">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="@string/price" />
<EditText
android:id="@+id/edit_price"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_weight="5"
android:importantForAutofill="no"
android:inputType="numberDecimal"
android:labelFor="@id/edit_price"
android:maxLength="20" />
</LinearLayout>
<LinearLayout
android:id="@+id/field_search_price"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:visibility="gone"
android:weightSum="7"
app:layout_constraintTop_toBottomOf="parent">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="@string/price" />
<EditText
android:id="@+id/lowest_price"
android:layout_width="45dp"
android:layout_height="wrap_content"
android:layout_weight="2.5"
android:importantForAutofill="no"
android:inputType="numberDecimal"
android:labelFor="@id/lowest_price"
android:maxLength="20" />
<View
android:layout_width="15dp"
android:layout_height="2dp"
android:layout_gravity="center"
android:background="@android:color/black"
android:gravity="center" />
<EditText
android:id="@+id/highest_price"
android:layout_width="45dp"
android:layout_height="wrap_content"
android:layout_weight="2.5"
android:importantForAutofill="no"
android:inputType="numberDecimal"
android:labelFor="@id/highest_price"
android:maxLength="20" />
</LinearLayout>
<LinearLayout
android:id="@+id/field_publisher"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:visibility="gone"
android:weightSum="7"
app:layout_constraintTop_toBottomOf="parent">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="@string/publisher" />
<EditText
android:id="@+id/edit_publisher"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_weight="5"
android:importantForAutofill="no"
android:inputType="text"
android:labelFor="@id/edit_publisher"
android:maxLength="20" />
</LinearLayout>
<LinearLayout
android:id="@+id/field_publish_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:visibility="gone"
android:weightSum="7"
app:layout_constraintTop_toBottomOf="parent">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="@string/publish_time" />
<EditText
android:id="@+id/edit_publish_time"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_weight="5"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:importantForAutofill="no"
android:labelFor="@id/edit_publish_time"
android:maxLength="20" />
</LinearLayout>
<LinearLayout
android:id="@+id/field_show_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:visibility="gone"
android:weightSum="7"
app:layout_constraintTop_toBottomOf="parent">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="@string/show_count" />
<EditText
android:id="@+id/edit_show_count"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_weight="5"
android:importantForAutofill="no"
android:inputType="phone"
android:labelFor="@id/edit_show_count"
android:maxLength="20" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_marginBottom="@dimen/layout_margin"
android:gravity="center"
android:orientation="horizontal">
<Button
android:id="@+id/add"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/add" />
<Button
android:id="@+id/search"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/query" />
<Button
android:id="@+id/cancel"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/cancel" />
</LinearLayout>
</RelativeLayout>
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 |
Click , set Index Name to bookName and Index Field to bookName, and click Next.
Role |
query |
upsert |
delete |
Everyone |
✓ |
– |
– |
Authenticated users |
✓ |
✓ |
✓ |
Data creator |
✓ |
✓ |
✓ |
Administrator |
✓ |
✓ |
✓ |
During application development, you can directly add the JAVA files
exported from the AppGallery Connect 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 app 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());
}
});
}
The following mainly describes how to write data to an application using the Cloud DB SDK. On the application screen, the Add button is added 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<Integer> upsertTask = mCloudDBZone.executeUpsert(bookInfo);
upsertTask.addOnSuccessListener(new OnSuccessListener<Integer>() {
@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<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");
}
});
}
Data added 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<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());
}
}
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<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();
}
}
};
|
|
Congratulations! You have successfully built your first app that integrates the App Gallery Connect Cloud DB and learned how to add data from the device to the cloud through the App Gallery Connect Cloud DB.
For details about the APIs of AppGallery Connect Cloud DB, see the Cloud DB API Reference.