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: 

In this tutorial, my intention is to introduce the SAP Mobile Platform SDK for Android, Harmonized OData API online store concept to you with a code snippet altogether 31 lines long. You can call it the „Hello World” for OData on Android. Around the code, I try to provide as much explanation as possible, so that anyone new to the topic can understand. The only prerequisites are basic knowledge of Java programming, the Android SDK, RESTful web services and the OData protocol, as well as Android Studio and SAP Mobile SDK being installed on your developer PC, the latter being downloadable from the location specified in this article at the time of writing this post: http://scn.sap.com/community/developer-center/mobility-platform/blog/2014/05/22/download-and-install... .

There is already plenty of other material available covering learning OData SDK for Android. They are all great, for example Claudia Pacheco’s „How To...Consume OData Services in Online Mode (Android)” tutorial (available here: http://scn.sap.com/docs/DOC-60634) is really excellent. It contains nicely designed and comprehensive code, from which you can learn a lot. In comparison, this post contains a code snippet that just wants to be short and simple, so please don’t criticize the shortcuts, they are intended. For example, all our code is synchronous and runs within the UI thread, that is something you don’t want to do in a „serious” app, as network can be really slow and it should be avoided that the app looks to be frozen. However, adding multithreading and asynchronity to the app would bring in more complexity, so I left them out for now.

So let’s start the adventure! I’ve broken down what we need to do into 7 simple steps (from which the 5th one „Write new code” is much longer than the others, as it contains the key part of this tutorial). TL;DR: If you are only interested in the code snippet as a whole, you can find it at the end.

Step 1: Create a new Android Studio project from Blank Activity template

Nothing to explain here, give your project a catchy name, Next, Next, Finish.

Step 2: Set up library dependencies

This is simple but not completely trivial. You can find a great description of what you should do in the „Android Applications” Developer Guide of SMP Native SDK, in the „Setting Up Android Studio for Native SDK Development” section: http://help.sap.com/saphelp_smp3010sdk/helpdata/en/f9/1c1c77615f441db0a99ea8c8f5b0b0/content.htm .

Step 3: Configure manifest file

In order to declare that your app needs to be able to access the network, add these 2 lines (if they are not yet there) just before the closing </manifest> tag of the manifests/AndroidManifest.xml file within your project:

<uses-permission android:name="android.permission.INTERNET"></uses-permission>

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" ></uses-permission>

Step 4: Delete unnecessary generated code

We are going to write all our code within the onCreate method of the main Activity. It is enough to keep super.onCreate(savedInstanceState); as the first line of the method from all that has been generated by the New Project wizard, the rest can be deleted. All our new code created here in this tutorial comes after this one remaining line within the onCreate method.

Step 5: Write new code

Now we are getting serious: write our brand new code!

I’ll start with a step-by-step explanation and then list the complete code snippet to make sure you enter it into Android Studio in the right order. When unresolved libraries are highlighted with red, add imports via Alt+Enter when saving the file. In case multiple alternatives are offered for some classes or interfaces having names starting with OData, choose the ones in the package com.sap.smp.client.odata.

Our output (data retrieved from the backend service) is going to be shown to the user via a TextView, so let’s initialize that, as well as the String object that will accumulate the text containing the output:

TextView textView = new TextView(this);
textView.setTextSize(
20);
String text =
"";

Then we set a default output message, to make sure that even if something goes wrong (like network connection issue, odata.org service being down etc.), we show something meaningful to the user:

textView.setText("There was an error getting data from backend service.");

After making sure we’ll have something going out, let’s start taking care of getting something in: data from an OData service via the network. In order to manage data traffic via the internet, we are going to use our SDK’s HttpConversationManager class. As its name suggests, it manages the conversation between the client and the server via the HTTP (or HTTPS) protocol. As you may already know, OData transfers data via internet or intranet networks via HTTP as network protocol, the data being represented as XML or JSON structured text. However, HttpConversationManager is such a great thing that for now, you absolutely don’t have to worry about details of HTTP. We don’t even have to worry about authentication as the service being used is a public one without any logon credentials being requested. In subsequent parts of this series I’m planning to introduce how to handle authentication via using HttpConversationManager in combination with SAP Mobile App Framework (MAF) Logon Manager, but not yet now, for the sake of simplicity of first time introduction.

Let’s construct our HttpConversationManager object, providing this as Android context, as the only constructor parameter, then start a try block, as the things that follow are able to throw various kinds of exceptions (for example network access issues):

HttpConversationManager manager = new HttpConversationManager(this);
try {

Now we’ll specify where our backend service lives, as an URL object. The backend service we are going to use is the public test / demo service on odata.org website. The newest version of the OData protocol specification is V4, but as SAP OData SDK currently supports an extended version of OData V2, we should also use this V2 version of the protocol from the service as well, that’s why „/V2” is part of the URL. Then we open our OnlineODataStore, for which the first parameter is Android context, the second one is the service URL, the third one is the HttpConversationManager used for handling network connectivity, and the last one is an online store options object that is optional and not needed now, so we provide null here.

Opening the store doesn’t retrieve any business data yet, just connects to the OData service document and initializes the online store.

URL url = new URL("http://services.odata.org/V2/OData/OData.svc");
OnlineODataStore store = OnlineODataStore.open(
this, url, manager, null);

Once the store is opened successfully (which we can make sure as the result of a null check), the OData feed of a specific collection can be read through the network, by default in XML format (using JSON instead of XML can be specified via configuration within the online store options object). In this case we are retrieving the „Suppliers” collection, and as second parameter we provide null as options object, having no extra configuration for now.

if (store != null) {
ODataResponseSingle resp = store.executeReadEntitySet(
"Suppliers", null);

Once we have the XML content retrieved in the memory (in the form of the ODataResponseSingle resp object, internally storing the data just as a big string), let’s parse it so that we can easily handle the content instead of needing to deal with the internal structure of the XML. The getPayload() method of the response object takes care of the XML parsing, and provides the data as a structured object representation of the OData feed in memory. Out of this feed, we can retrieve just the business data records as  a List of ODataEntity objects via the getEntities() method call.

ODataEntitySet feed = (ODataEntitySet) resp.getPayload();
List<ODataEntity> entities = feed.getEntities();

Now that we have the list of business object entities at hand, let’s prepare for processing them one by one, via declaring the variables that will temporarily store the data before processing: the OdataPropMap object will store all the properties of the current entity in the list, and the OdataProperty object will contain one specific property value of a given entity.

ODataPropMap properties;
ODataProperty property;

When iterating through the list of entities the ODataEntity object stores the current entity within the iteration. The first thing we do with this entity is to get the map of its properties.

for (ODataEntity entity : entities) {
properties = entity.getProperties();

Then we just go one by one and retrieve all the property objects, providing property names as parameters, and then getting the values of the properties. The given value is immediately concatenated to the string that is to be shown to the end user as output. Of course, in case of a real application (instead of this overly simplified tutorial code), you could for example construct a statically typed business object from these property names and values, in this case a class named Supplier would be a likely candidate.

property = properties.get("ID");
text +=
"ID: " + property.getValue();
property = properties.get(
"Name");
text +=
", Name: " + property.getValue();
property = properties.get(
"Address");
text +=
", Address: " + property.getValue();
property = properties.get(
"Concurrency");
text +=
", Concurrency: " + property.getValue() + "\n\n";

After iterating through the entities, we are done with data processing. The output text is ready, so we should just set it as the content of our textView object (right before the end of the block of our if statement that made sure we process data only in case connecting to the backend OData store was successful).

}
textView.setText(text);
}

Again, in a real application, you would have proper exception handling with error messages shown to the end user and logging etc. but here we just print the stack trace to make it easier to troubleshoot issues during the learning process.

} catch (Exception e) {
e.printStackTrace();
}

Last but not least, we set the textView object as the only UI element on the screen.

setContentView(textView);

This is it! As I said before, here comes the complete code snippet:

TextView textView = new TextView(this);
textView.setTextSize(
20);
String text =
"";
textView.setText(
"There was an error getting data from backend service.");
HttpConversationManager manager =
new HttpConversationManager(this);
try {
    URL url =
new URL("http://services.odata.org/V2/OData/OData.svc");
    OnlineODataStore store = OnlineODataStore.open(
this, url, manager, null);
    if (store != null) {
        ODataResponseSingle resp = store.executeReadEntitySet(
"Suppliers", null);
        ODataEntitySet feed = (ODataEntitySet) resp.getPayload();
        List<ODataEntity> entities = feed.getEntities();
        ODataPropMap properties;
        ODataProperty property;
       
for (ODataEntity entity : entities) {
            properties = entity.getProperties();
            property = properties.get(
"ID");
            text +=
"ID: " + property.getValue();
            property = properties.get(
"Name");
            text +=
", Name: " + property.getValue();
            property = properties.get(
"Address");
            text +=
", Address: " + property.getValue();
            property = properties.get("Concurrency");
            text +=
", Concurrency: " + property.getValue() + "\n\n";
        }
        textView.setText(text);
    }
}
catch (Exception e) {
    e.printStackTrace();
}
setContentView(textView);

Step 6: Check network connectivity

Before you run the app, please make sure that your test device or emulator can properly connect to the internet. The safest thing in order to avoid any proxy issues is usually to use a real device, turn off WIFI and go via 3G.

Step 7: Run

… and now, run the app and you are supposed to see something like this if everything went well.

My next blog of this to-be-series is planned to be about how to handle authentication when connecting to an OData service. Stay tuned!

8 Comments