Writing a Serverless Android app (ft. Huawei's AppGallery Connect) - Part 3 - More CloudDB
Tags: android, java, serverless, appgallery
Published: 2021-08-04 13:30:48

Not read part 2? Read it first! {% link https://dev.to/devwithzachary/writing-a-serverless-android-app-ft-huawei-s-appgallery-connect-part-2-clouddb-4562 %}

Over the next couple of months I will be releasing a complete end to end guide to creating an Android app using serverless functionality to completely remove the need for any backend server/hosting etc.

At the bottom of this post you will find my twitch channel where we live stream every Thursday at 2pm BST and the GitHub repo for this project!.

{% youtube T17W-Xi8afY %}

But for those that would rather a written guide, lets get into it!

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.

```java
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

```java
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.

```java
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:

```java
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:

```java
private final UserCallBack callBack;
``` 

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

```java
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:

```java
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:

{% gist https://gist.github.com/devwithzachary/649c94c1de9407a218d782c182f8c0e2 %}

##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:

```java
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:

```java
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!

#Twitch Account

{% twitch devwithzachary%}

#Github Repo

{% github devwithzachary/Barker%}

We will be back with the next part next week!