Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
claudiapacheco
Product and Topic Expert
Product and Topic Expert

This blog covers how to use the SMP OData SDK to handle OData services that limit the number of items sent in a response. It will explain how Android native apps can deal with these partial responses and what methods are required to get the rest of the results.

If mobile apps don’t restrict the amount of data they requests from the server, your OData services will be overloaded and their response time will be impacted. That’s why some services implement the server-side paging, also called “pagination”, provided by the OData protocol. More details about how to implement OData services using pagination can be found here: Mobile Application Development Platform - Integration

For simplicity purposes, this blog will use the Northwind OData service as an example: http://services.odata.org/V2/Northwind/Northwind.svc/

The Northwind example contains a collection called “Customers”:

When a client app sends a GET request to get all customers, the service returns a partial response of 20 customers. At the end of the response, you will find an URL that includes $skiptoken, which allows the server to return the next set of customers.

<link rel="next" href="http://services.odata.org/V2/Northwind/Northwind.svc/Customers?$skiptoken='ERNSH'" />

Let’s assume you are using HCPms and that the Android client app has already registered with the mobile services. The OData SDK provides two ways to access the data: online or offline store.

The offline store can be used to develop applications that require infrequent updates of back-end data and the connectivity may become unreliable. When the client app open an offline store that points to an OData service that uses pagination, the mobile services (in SMP 3.0 on premise or HCPms) does all the work automatically. Assuming there are 100 rows in the “Customers” entityset and the $skiptoken is set for 20; it automatically makes 5 calls (each call brings back 20 rows based on $skiptoken) to the backend to get all the 100 rows and populates the database. Once the offline store is opened, the client app will have access to all the data locally in the device.

The online store, on the other hands, is more suitable to develop applications that require up to date back-end data and have reliable connectivity. In this case, it’s up to the client app to handle the partial results. In a nutshell, the client app must check whether the getNextResourcePath returns an URL. If getNextResourcePath is null, it means there’s no more customers to fetch. Otherwise, the client app can continue to send GET request to the nextResourcePath URL to obtain the complete list of customers.

Synchronous

if you want to consolidate the partial results using synchronous calls, you can use the following code snippet as a starting point

Synchronous GET request
try {
    String nextResourcePath = collection;
   
while (nextResourcePath != null) {
        ODataRequestParamSingle request =
new ODataRequestParamSingleDefaultImpl();
        request.setMode(ODataRequestParamSingle.Mode.
Read);
        request.setResourcePath(nextResourcePath);
        request.setCustomTag(customTag);

        ODataResponseSingle response = (ODataResponseSingle) store.executeRequest(request);
       
//Get the response payload
       
ODataEntitySet feed = (ODataEntitySet) response.getPayload();
        List<ODataEntity> entities = feed.getEntities();
       
// Store customers
       
customers.addAll(entities);
        nextResourcePath = feed.getNextResourcePath();
    }
}
catch (Exception e) {
   
throw new OnlineGenericException(e);
}

Asynchronous:

Another option is to display partial results and allow the user to control when it wants to download the next set of customers. In this example, the client app displayed the first 20 customers and provided with an icon to allow the user to get the next 20 items on the list:

You can use the following code snippet as a starting point

1. Send an asynchronous GET request to get the list of customers.

Asynchronous GET request

/**
* Send GET request to the offline store
* @Param
collection URL of the collection, for example “Customers”
* @Param
customTag description of the request
* @Param
requestListener request listener
* @throws OnlineGenericException
*/
public static void sendGETRequest(String collection, String customTag,

         ODataRequestListener requestListener) throws OnlineGenericException {

     OnlineStoreListener openListener = OnlineStoreListener.getInstance();
     OnlineODataStore store = openListener.getStore();

    
if (store!=null){
       
try {
           ODataRequestParamSingle request =
new ODataRequestParamSingleDefaultImpl();
           request.setMode(ODataRequestParamSingle.Mode.
Read);
           request.setResourcePath(collection);
           request.setCustomTag(customTag);

           store.scheduleRequest(request, requestListener);
        }
catch (Exception e) {
          
throw new OnlineGenericException(e);
        }
     }
}

2. Receive the partial response through a class that implements the ODataRequestListener interface. The ODataRequestListener interface defined several methods that are called upon reaching each stage of the request.

    1. requestStarted: Request has been started.
    2. requestServerResponse: Server response has been received
    3. requestFailed: OData request has been failed.
    4. requestFinished: OData request has been finished

In the requestServerResponse, we can store the list of customers (The first 20 customers) and the link to get the next set of customers by using getNextResourcePath method.

String nextURL = ((ODataEntitySet) response.getPayload()).getNextResourcePath();

Receive partial response - code snippet

@Override
public void requestServerResponse(ODataRequestExecution oDataRequestExecution) {
Log.d(
TAG, "requestServerResponse");
    
if (oDataRequestExecution!=null && oDataRequestExecution.getResponse() !=null) {
        String customTag = oDataRequestExecution.getRequest().getCustomTag();
       
//Parse the response
       
ODataResponseSingle response = (ODataResponseSingle) oDataRequestExecution.getResponse();

        //Get the http status code
       
Map<ODataResponse.Headers, String> headerMap = response.getHeaders();
        String code = headerMap.get(ODataResponse.Headers.
Code);
        Log.d(
TAG, "requestServerResponse - status code " + code);

        CustomerEntityCollection customerCollection =
CustomerEntityCollection.getInstance();


//Get the response payload
ODataEntitySet feed = (ODataEntitySet) response.getPayload();
//Store the URL required to get the next set of customers
customerCollection.setNextResourcePath(feed.getNextResourcePath());

//Get the list of ODataEntity
List<ODataEntity> entities = feed.getEntities();
customerCollection.setCustomersCache(entities);

notifySuccessToListener(
"success");

} else {
notifyErrorToListener(
new OnlineGenericException("no response"));

      }

}

Once the user click on the next icon, the client app will send a GET request to the nextResourcePath URL. When the nextResourcePath URL is null, you can hide the next icon or send a GET request to the customer collection to start over.

Assumptions for this exercise

Assuming you are using the HCPms trial account, you can use the following screenshot to configure your application configuration, which points to the Northwind OData service:

Remember that your Android client app needs to onboard with HCPms before accessing any data. Here are some guidelines to MAF logon component:

How To... Setup MAF resources in Android Studio

Customizing MAF Logon Component in Android

Running Android apps on HCPms

Cheers

Claudia