This tutorial is focused on retrieving data from your backend into our sample Backendless Android application (Restaurant – to – Go application which you can easily download from the Backendless github repository).
We assume that you have already configured the modules for user registration and subsequent logging in. These steps have been covered in our previous tutorials so we highly recommend you to review them before you start this one:
- Configuring a Development Environment for a Backendless Android App
- Developing a Backendless Android App – User Registration Screen and the Registration API
- Developing a Backendless Android App – Login Screen and the Login API
For your convenience, the tutorial below is also available in a video on Backendless YouTube channel here.
Now we proceed to the restaurant_list module which includes all the code we have reviewed previously.
To remind how the UI for the restaurant list looks like:
- step into the project’s Structure section in Android Studio
- go to restaurant_list – > res – > layout
- open activity_restaurant_listing.xml and the UI of the restaurant listing screen will appear. It contains a collection of individual items.
To review what each item of the list contains, you should switch to the list_item_restaurant.xml by clicking it in the project’s Structure section.
The list_item_restaurant screen will appear in the center of the window. Here we have a restaurant name, a cuisine which is served in this restaurant and a number of locations with the button to navigate to the specific location listing.
Consequently, the code in activity_restaurant_listing should retrieve all the restaurants for the project and render them accordingly.
How can your data be loaded and displayed in the UI?
To see the data in your backend, switch to Backendless developer console. Click the Data icon and select the Restaurants table.
There are six restaurants here with the values which have been imported into your backend in the previous Backendless tutorial.
To get to the activity responsible for loading all the restaurants from the code perspective you should go to LoginActivity.
Reviewing the code here you can see that it contains the login button (loginButton) in the login activity (LoginActivity) after which the login button listener is created (createLoginButtonListener).
When we’re logging in a user we create a login сallback (createLoginCallback). If the login request is successful the server notifies us that the user is logged in.
At this point we need to advance the user to the restaurant listing. It happens inside the login сallback (loginCallback).
Inside the login сallback (loginCallback) you can see the handle response method (handleResponse) that occurs when the server responds that this user is logged in. Then we create the Intent to show restaurantListingActivity (restaurantListing Intent). The final step is the start of this activity (startActivity).
After reviewing these essential issues we can proceed directly to the review of the RestaurantListingActivity class: Step into the RestaurantListingActivity class holding the Ctrl button and clicking on the class link:
When the activity is started the very first thing we should do is to make a query which loads all the data from the restaurant table.
How to create a query that loads all the data from the restaurant table to the UI?
- Make an API call that loads all the data.
- Backendless.Data is your individual gateway to all persistence tasks. The method of() returns an instance of IDataStore. On the screenshot below you can see there is the IDataStore generic for the Restaurant class.
The Restaurant class contains all the getters, setters and the private fields where each field corresponds to a specific column in the Restaurant table. Notice that here we have a collection of locations, a cuisine, a name and some system level properties (updated, created, an objectID and an ownerID).
Let’s have a look how it is represented in the Backendless developer console:
- Switch to Backendless developer console
- Go to the Restaurant table on Data screen
- Click the Table Schema and Permission button
The schema with a collection of columns appears on the screen. We have an owner, a cuisine and a name in the schema.
All the other columns in the Restaurant table of the Console’s Restaurant table, such as objectId, created, updated or the system level columns always will be added to each table that you create with the Backendless Data Service.
So it is obvious that our Restaurant class corresponds one to one to the Restaurant table from the backend.
Let’s return to the RestaurantListingActivity to continue reviewing the process of data retrieving from the code perspective.
IDataStore returned from of() method contains all the methods that you can use to work with your backend. Here we have find(), findById(), findFirst(), findLast(), loadRelations(), remove(), save() – the entire CRUD (create,retrieve, update and delete) set of methods to work with the Restaurant objects.
In our case we are using find() because we send a request to a server to ask it to return all the restaurants in order for us to show them in the UI. This is exactly what the method find() does. Notice that there are two arguments for the methods find():
- The query
- The callback.
The query argument
The query is an instance of the Backendless.DataQuery. Backendless.DataQuery constructor expects three objects. We need the query object here because we specify that we also want to load all related entities for each restaurant.
Specifically the entities are referenced by the locations column. This means that whenever we request a collection of the Restaurant objects we let the server know that every single related location also needs to be populated and returned back to the client.
If we switch to Backendless developer console and review our Restaurant table in the Data screen we’ll see that we have a list of restaurants here. Some of them have locations. So the code which we’ve just reviewed says: “Server, return not only the restaurant but all the related locations need to be included into the response”. This way we get the entire closure for all the restaurants and all the locations.
The callback argument
The second argument in the find() method is the callback.This is an implementation of the LoadingCallback that extends Asynchronous Callback. This class is used whenever a response is available from the server.
Also there is a method handleResponse() which gets the actual response. Notice that the argument of this method is BackendlessCollection that is a generic for the restaurant class.
BackendlessCollection will include a collection of restaurants where each object represents a record from the database. This is actually very cool because we make a request to the database and get back a strongly typed implementation of the Restaurant objects where all the properties, getters and setters are available for your immediate use. You do not need to do any parsing or process any aximilary JSON documents. You get live Java objects which you can start to use in your application.
Exactly the same approach is applicable to all client environments that are supported by the Backendless Platform. If you were to build an iOS app, then you’d be getting a collection of strongly typed Objective-C or Swift objects.
Now we have the data retrieved from the backend in our application and it is being delivered to the callback. Let’s take a look at how this data is rendered in the list view (ListView).
Go to activity_restaurant_listing.xml and get to the ListView in the Component Tree in the top right corner on the window (Device Screen – > LinearLayout -> ListView).
Let’s take a look at the code of the activity class. The class name is RestaurantListingActivity, it extends ListActivity – one of the Android classes which assists you with rendering the list-based data:
Also there are a list collection called totalRestaurants and RestaurantAdapter which contains this list collection.
The totalRestaurants collection is passed into the adapter. Then the adapter is sent as a ListAdapter for the current activity.
Once we get an answer from the server, this collection of the restaurants is sent into the adapter through the addMoreItems() method.
So we’re populating the totalRestaurants which is now linked with the adapter. Then we notify the adapter about the changes.
At this point everything is being returned back and rendered to the list component.
The adapter itself is actually responsible for populating individual ListItems.
Let’s take a look at the adapter implementation stepping into the RestaurantAdapter holding Ctrl button and clicking on the class link.
In the adapter we get the view, extract the data from the collection for the specific index and populate the individual elements in the ListItem with the data received from the server.
For an individual ListView item we have a restaurant name, a cuisine and a number of locations. We get a Restaurant object for the specific position and populate the data from that Restaurant object in the individual ListView items.
How to proceed from the restaurant listing to the location listing?
For the most part we have exactly the same code except for one difference.
There is the onListItemClick() in this method.This method is the Callback that occurs whenever you click on а restaurant. Notice that this method overrides the base method in ListActivity. Therefore it has a built-in functionality that the ListActivity will provide whenever you click on an item in the list. Whenever you click on the restaurant we pass on control to the LocationListingActivity which is a new activity added to the location_listing module. In order for the LocationListingActivity to display the data we have to pass in the specific restaurant that contains the locations. That is done by putting extra information into the Intent.
Let’s switch to the LocationListingActivity class holding Ctrl button and clicking on the class link.
In here we take the restaurant that is being passed through the Intent and render the information about the locations. Remember that the locations were already pre-initialized for the restaurant. And now we can initialize the adapter that we have here for the current restaurant.
LocationAdapter is responsible for rendering of the individual locations in the list exactly in the same manner in RestaurantAdapter. Before we review LocationAdapter let’s review what location listing looks like in the UI.
Here we have a listing of locations which mimics the UI for the restaurants almost one-to-one.
Switch back to the LocationListingActivity to see how the Adapter for the location_listing works. Enter the Adapter by holding Ctrl button and clicking on the class link.
Once the Adapter is initialized rendering an individual location requires getting the text view for the city and the address. Then it is necessary to get the location object and initialize these items in the list view.
USING BACKENDLESS CODE GENERATOR
In this tutorial we‘ll also review the process of generating code for the classes which represent the records in the database.
These classes are located in the entities package. They are Restaurant, Order, MenuItem, Menu, Location.
Switching to Backendless developer console you can see that these classes correspond one to one to the tables which we have in the backend. The structure of those classes is exactly the same as the schema of the corresponding tables.
As I mentioned, you could write these classes by yourself. But they follow pretty much exactly the same pattern where a property in the class represents a column in the table. And there are appropriate getters and setters. Since the pattern is exactly the same we added a code generator that can create all these classes for you without writing a single line of code. In fact the code that is included into our sample project and every single module here was created by the Backendless Code Generator.
How to generate the code?
- Switch to Backendless developer console and select your application.
2. Click on the Code Generator icon.
3. Select Android for a client of your choice as we are building the Android app.
4. Select the checkbox in the Data Management section – in our case this the checkbox for “Java classes for defined data tables”. If this is what you select then the code generator will know that the goal here is to generate classes that would be mapped to the tables.
5. Select an IDE – for this example we select IntelliJ IDEA since our development environment is the Android Studio and is based on IntelliJ IDEA.
6. Click on the Download project button at the bottom of the window.
The Backendless Platform creates a zip-file and returns it to you. In the zip – file you will find a project with all the project files and the source code which represents the actual classes.