[Huawei Developers] devwithzachary:
Part 3 - More CloudDB​

Last time we looked at the basic setup of the CloudDB service, how to get things configured and how you can get started with the service. Now this is in place lets take a look at the service in more detail. We started working on a CloudDBManager that was going to handle all the communication between the CloudDB service and the rest of the app. This was a great start but before we dig any deep lets look at a few improvements to this.

Listen for Database Changes​

In the current CloudDBManager if we want to check for any changes to the database we had to manually call getAllUsers(). This is fine if we aren't really interested in when changes are made to the database, however if we do want to keep an up to date local copy of the data (for example posts in a feed) we need to look at adding a Snapshot Listener. This will tell the CloudDB service to execute a given query and process the results in real time.

Lets start by defining a new OnSnapShotListener for the Class User when the listener is given a snapshot we pass this into the processResults method we created last week.

private final OnSnapshotListener<User> snapshotListener = (cloudDBZoneSnapshot, e) -> processResults(cloudDBZoneSnapshot);

Next we create a method that will subscribe that Snapshot Listener to the CloudDBZone with an applied query, in this instance just the simple query to return all Users

public void addSubscription() {
CloudDBZoneQuery < User > snapshotQuery = CloudDBZoneQuery.where(User.class).equalTo("uid", "");
try {
ListenerHandler handler = cloudDBZone.subscribeSnapshot(snapshotQuery,
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY,
snapshotListener);
} catch (Exception e) {
toaster.sendErrorToast(context, e.getLocalizedMessage());
}
}

With this in place we can now tweak the openCloudDBZone method, by using a task based approach we are able to add an onSuccessListener. So long as the zone is successfully opened we can called the addSubscription() method and start listening for new data.

public void openCloudDBZoneV2() {
CloudDBZoneConfig config = new CloudDBZoneConfig("Barker",
CloudDBZoneConfig.CloudDBZoneSyncProperty.CLOUDDBZONE_CLOUD_CACHE,
CloudDBZoneConfig.CloudDBZoneAccessProperty.CLOUDDBZONE_PUBLIC);
config.setPersistenceEnabled(true);

Task < CloudDBZone > task = cloudDB.openCloudDBZone2(config, true);
task.addOnSuccessListener(zone - > {
cloudDBZone = zone;
addSubscription();
}).addOnFailureListener(e - > toaster.sendErrorToast(context, e.getLocalizedMessage()));
}

Use userList​

In the processResults method from last week we took the data snapshot and converted it into a list of User objects. We didn't then do anything with this nor did we have a method to pass that data onto somewhere else in the app. Lets change that!

We will start by creating a new public interface called UserCallBack this will be implemented by any class that wants to use an instance of the CloudDBManager. Currently the interface is pretty simple with just three methods:

public interface UserCallBack {
void onAddOrQuery(List < User > userList);

void onDelete(List < User > userList);

void onError(String errorMessage);
}

We create a variable for this Call back within the CloudDBManager like:

private final UserCallBack callBack;

And finally as part of the CloudDBManager init method we require an instance of the UserCallBack

public CloudDBManager(Context context, UserCallBack callBack) {
cloudDB = AGConnectCloudDB.getInstance();
this.context = context;
this.callBack = callBack;
}

Now when we have processed the result of a query we can pass that data back to the calling class using the callback. For example the processResult method now looks like:

private void processResults(CloudDBZoneSnapshot < User > userCloudDBZoneSnapshot) {
CloudDBZoneObjectList < User > userCursor = userCloudDBZoneSnapshot.getSnapshotObjects();
List < User > userList = new ArrayList < > ();

try {
while (userCursor.hasNext()) {
User user = userCursor.next();
updateMaxUserID(user);
userList.add(user);
}
callBack.onAddOrQuery(userList);
} catch (AGConnectCloudDBException e) {
callBack.onError(e.getLocalizedMessage());
toaster.sendErrorToast(context, e.getLocalizedMessage());
} finally {
userCloudDBZoneSnapshot.release();
}
}

We now have a way to both pass back the user list and also any error message that might be given during the processing!

The final CloudDBManager should look something like:

A manager class for the AGC CloudDB service

A manager class for the AGC CloudDB service. GitHub Gist: instantly share code, notes, and snippets.

gist.github.com

Authentication Manager​

With the changes made above lets take a look at how we can use this to gain access to the database data. Specifically within the `AuthenticationManager`.

First we must now implement the new interface like so:

public class AuthenticationManager implements CloudDBManager.UserCallBack{
...
@Override
public void onAddOrQuery(List<User> userList) {

}

@Override
public void onDelete(List<User> userList) {

}

@Override
public void onError(String errorMessage) {

}
...
}

The onAddOrQuery method will be given the userList returned when a snapshot is processed, we can implement code here to update the UI or confirm if a user is already registered for example.

In this Classes init method we will also need to pass itself in as the UserCallBack. The setup of the CloudDBManager object will now look like:

dbManager = new CloudDBManager(context, this);
dbManager.createObjectType();
dbManager.openCloudDBZoneV2();

We are now in a good position to query data, view it and upsert it! Join us next week when we start configuring the other Objects we are going to be using, expand the User object and make the CloudDBManager generic for any CloudDB Object!