From time to time, we see some developers struggle with understanding the principles of asynchronous work with Backendless. In this post we’ll try to shed more light on this aspect: describe what async calls are, why you need them and how to properly perform such calls and process the results. This post will be specific to Java and Android, but most of the principles apply to any language and environment.
To better understand what the asynchronous API call is, let’s begin with the opposite. Let’s say you’re trying to keep it simple and familiar, and in your MainActivity’s onCreate method you’re loading a bunch of users to display:
List<BackendlessUser> users = Backendless.Data.of( BackendlessUser.class ).find();
// here goes the code for displaying the users list
The problem is that in Android, you’ll immediately get a NetworkOnMainThreadException thrown when this code is executed. As the name implies, it happens because you’re performing a network call (a call to your Backendless app) on the main thread. Android environment does not allow such calls on the main thread to avoid negative user experience in your app: the main thread is the one where the UI is being rendered, and because the network calls usually take some noticeable time, the UI will be unresponsive for the duration of the call.
This StackOverflow question lists the options which you should implement to avoid the aforementioned exception.
To avoid the exception you need to shift the execution of the network call to another, non-main, thread. This is what the asynchronous call in a nutshell is — merely executing the call in another thread, which won’t block the thread you’re currently working in. If you’re familiar with multithreading in Java, you should see that there are multiple ways to do that: create a new thread manually, submit a task to a ThreadPoolExecutor, etc. The aforementioned StackOverflow question also lists a few more Android-specific solutions to that problem. All of these solutions stay viable for Backendless API calls, too, but still it may be hard to process the results of the call after they are received.
Thus, the Backendless Android SDK implements an approach which is easier to use without getting into multithreading too heavily. The SDK duplicates most of its methods with synchronous and asynchronous versions. The async version can be recognized by an additional parameter of generified type AsyncCallback . Under the hood, the Backendless Android SDK uses a thread pool to delegate the async calls, and when the result is available — the corresponding method in the AsyncCallback argument is called depending on whether the request was successful or not.
So with this approach, the example of getting the users from the backend mentioned at the beginning will look like the following:
Backendless.Data.of( BackendlessUser.class ).find( new AsyncCallback<List<BackendlessUser>>()
public void handleResponse( List<BackendlessUser> response )
// this method is called as soon as the result in received
// the result is already in the argument `response`
// here you process the result
// for example, you can log it to Logcat:
Log.i( "MyLog", response.toString() );
public void handleFault( BackendlessFault fault )
// this method will be called in the request fails
// the information about the failure is in the argument `fault`
Log.e( "MyLog", fault.toString() );
Here are the few things you need to remember when working with AsyncCallback in Backendless Android SDK.
- There is no return value. Since the method is asynchronous, the main thread essentially just “launches” the request and proceeds without waiting for the response, therefore the return type of the async methods are void .
- The generic parameter for AsyncCallback is the type of the result you’re expecting to get. This is exactly the same as the type of the variable you use to store the result of the sync method. For example, if, like above, it’s a request to find all users, then you use AsyncCallback<List<BackendlessUser>> because you’re expecting List<BackendlessUser> in response. Similarly, if it’s a call to Backendless.UserService.isValidLogin() , the expected result is boolean and thus with the async call the AsyncCallback parameter should have a corresponding generic parameter AsyncCallback<Boolean> .
- Do not ignore error handling. When using sync calls, the errors are automatically “handled”, because the exception is thrown in the same thread where you’re performing a call. But with async calls, if you leave the handleFault method empty, the error will just be ignored and you’ll probably wonder why you got no results (the handleResponse is obviously not called when the error happens).
- Results can arrive at any time. Never try to use the results outside of the handleResponse callback, because they may be missing at the moment. This is actually the main thing to remember when working with multiple threads: always be aware of the thread you’re currently in.
With the asynchronous approach you’ll definitely have to rethink how you build interactions in your applications, since you now have to keep in mind that the data is not available immediately and to deal with callbacks to process the results at a proper time. But this will actually only improve your app users’ experience since it makes you explicitly think about problems that do not disappear when you write the easier synchronous code. And fortunately, if you dig a bit deeper into it, Android provides many tools to make the needed integration smoother in your code.