Android Ax App – Part 2–The Android app


This is part 2 of the series to create an Andorid App to consume AIF services from Ax 2012.

Android Ax App – Part 1 – Set up the intermediate WCF service

This post is the equivalent of Joris’s blog:  10-Minute App – Windows Phone 7 App

For this app I will be using the Eclipse development environment, jammed with the Android SDK (i aimed it at using the 2.3.3 SDK, but i think you could use 2.1 or lower)

WARNING: There is a lot of code…..lots and lots of code (unlike the windows 7 app, and its code generation tools, there is not much here) I will try to provide the full source code for this project

UPDATE: The source code for the android application can be downloaded here
https://skydrive.live.com/embed?cid=39C5BF85D7859D05&resid=39C5BF85D7859D05%21301&authkey=AOma0LTxcyPetdU

For the requirements of this app, i will list some here to make sure we have all the libraries. I will assume that Eclipse and Android are setup based on the instructions

  1. Eclipse
  2. Android SDK(2.3.3) (We arent useing any OS specific feature. This app should be able to be written in much lower versions)
  3. Gson (Google Json library, this is a pretty lightweight and easy to use JSON library as compared to the one already included within the Java SDK)

So the first part of the process is to create the Android application. This should be some basic general settings CreateAndroidProject

Make sure to have the “Create activity” set to true. That creates a default activity to start with the application.

Because we are going to access our web service (i.e. use the internet) we need to give that access to the app (otherwise this will lead to frustration and excessive drinking and may also lead to baldness). To do so, add the following line to the AndroidManifest.xml file within the <manifest> tag

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

We will now create the UI for this. This will be split into 2 UI elements. One which is the main page, and the second which defines each row of the Items to be displayed. I Will try to make the UI look as close to the one in Joris’s Blog.

The main UI: When the application is created, a UI xml file is already created under /res/layout/main.xml

Main Layout

MainUILayout

Item row layoutItem_RowLayout

This UI starts with a TextView (User name label), a TextViewEdit (Username), Button (Get items), followed by another label (this will fetch the application name from the web service)

Follows that is a ListView placeholder. Later on the list view will be set to use the secondary view which contains the definition of a Row

The XML of the main view is (main.xml):

<!--?xml version="1.0" encoding="utf-8"?-->
<!-- Top section -->

	<button>

 <!-- Application name -->

 <!-- Listview placeholder -->

 

The row layout will be added in another UI file called “item_row.xml”

<!--?xml version="1.0" encoding="utf-8"?-->

Here we are only showing the Item Id and Item name below the other and with a different height for the item

We now have to link the Item_row UI to the LIstView. This is done using Adapters. There are lots of examples online how to attach a Listview to a array of strings, but very few with array of some class.

What i will do is First Show the Main Activity (this is where the item_row gets attached to the ListView too)

In the Activity class “LooneyDroidActivity” we will declare our 3 UI elements we would want to access. (In Android, the Activity can be linked to any UI, and hence we need to fetch the elements ourselves, unlike Silverlight Sad smile )

private ListView itemListView;
private EditText editTextUsername;
private TextView appNameTextView;

In the class, you will also see the onCreate method. This method is the entry point of the Activity. this is where we will initialize the private members that point to the UI elements.

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Username button
editTextUsername = (EditText)this.findViewById(R.id.editTextUserName);

//Application name
appNameTextView = (TextView)this.findViewById(R.id.AppName);

this.itemListView = (ListView)this.findViewById(R.id.itemList);
}

The “setContentView” sets the UI to be used by the activity. This is how the app knows which UI layout to show. you also see “R.id.*”  R is a class auto generated and resides under /gen/package name/R. Every time UI element is created, the ID for it is generated and stored in the class.

in the Main.xml layout, you also see the button element has a onClick method. This needs to be manually defined inside the activity class.

public void LoginBtn_OnClick(View v){
    ItemAdapter adapter = (ItemAdapter)this.itemListView.getAdapter();
    //Clearing the ListView
    if(adapter != null) {
        this.itemListView.setAdapter(null);
    }
    //Fetch the AplicationName
    String username = this.editTextUsername.getText().toString();
    String appName = RESTClient.connect("http://192.168.1.100:8080/DevTest/WcfApi/Api1.svc/api1/appName", username);

    try {
        appName = (String)ProcessJson.ProcessResult(MessageType.GetAppName, appName);
        appNameTextView.setText("Logged in as: " + appName);
    } catch (MalformedJsonException e) {
        e.printStackTrace();
        appNameTextView.setText("Cannot Login");
    }
    catch (JsonSyntaxException e){
        e.printStackTrace();
        appNameTextView.setText("Cannot Login");
    }

    //Fetch the itemList
    String itemList = RESTClient.connect("http://192.168.1.100:8080/DevTest/WcfApi/Api1.svc/api1/items", username);
    try{
        Item[] items = (Item[])ProcessJson.ProcessResult(MessageType.GetItemsList, itemList);
        //Binding itemList to UI
        ItemAdapter itemAdapter = new ItemAdapter(this, R.layout.item_row, items);
        this.itemListView.setAdapter(itemAdapter);

    } catch (MalformedJsonException e) {
        e.printStackTrace();
        appNameTextView.setText("Cannot Login");
    }
    catch (JsonSyntaxException e){
        e.printStackTrace();
        appNameTextView.setText("Cannot Login");
    }
}

The button click is doing 2 calls to the WCF service, to get the application name and then the item list.

For each call it goes to the RESTClient class, which returns the JSON string. The ProcessJson class converts that JSON to an object using the GSON library. The first process returns a string, the second an array of item (the item class consists of just the ItemId, and name).

I think this is already well beyond the 10 minute mark (took me more than that too)

The REST Client: (To call the WCF services, and fetch the JSON result)

public class RESTClient {
    private static String convertStreamToString(InputStream is){
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();

        String line = null;
        try{
            while((line = reader.readLine()) != null){
                sb.append(line + "\n");
            }
        } catch(IOException e){
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sb.toString();
    }

    public static String connect(String url, String username) {
        String result = "";
        HttpClient httpClient = new DefaultHttpClient();
        HttpGet httpGet = new HttpGet(url);
        HttpResponse response;
        try{
httpGet.addHeader("Authorization", username+":"+username);
            response = httpClient.execute(httpGet);
            Log.i("WCFAPI", response.getStatusLine().toString());

            HttpEntity entity = response.getEntity();
            if(entity != null){
                InputStream inStream = entity.getContent();
                result = convertStreamToString(inStream);
                Log.i("WCFAPI", result);
                inStream.close();
            }
        }catch(ClientProtocolException e){
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }
}

The ProcessJson Class(Convert JSON to custom objects)

public class ProcessJson {
    public enum MessageType{
        GetAppName,
        GetItemsList
    }
    public static Object ProcessResult(MessageType messageType, String result) throws MalformedJsonException{
        Gson gson = new Gson();
        Object returnValue = null;

        switch(messageType){
        case GetAppName :
            returnValue = gson.fromJson(result, String.class);
            return returnValue;
        case GetItemsList :
            returnValue = gson.fromJson(result, Item[].class);
            return returnValue;
        }
        return null;
    }
}

Item class: (data received from the WCF GetItems method)

public class Item {
    public String ItemId;
    public String Name;
}

And finally the ItemAdapter class (this takes the list of items, specifies how to map it to the Item_row.xml layout

OK……So “Finally” (finally,finally,finally)….our application is ready to deploy.

The start screen: (we have pre populated the username in the main.xml file)

AndroidAx Login Screen
Android Ax Items list
Android Ax Items Scrolled to the end
Android Ax Items Scrolled to the end

And if you enter an incorrect username, you get the error. (this is just error handling, and no connectivity to the web service will also give the same error)

Android Ax Incorrect Login result
Android Ax Incorrect Login result

This Android app is just a basic Single Activity based app, with no menu items or additional activities. The trusted intermediate Works just as expected with this too. What I haven’t covered on this yet is securing the WCF services by SSL and then consuming it from Android. I haven’t ventured into that jungle yet, but will try to post one on that later.
This concludes the Android app for Ax. I don’t think this would be anywhere near 10 minutes (especially with the ListView and the Custom Adapter we had to create), but that all depends with your Android skills. There was a lot of joy once I got this working, hopefully there will be more integration into Ax coming soon 🙂

Advertisements

2 thoughts on “Android Ax App – Part 2–The Android app

Leave a Reply / Comment

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s