Sunday, 15 June 2014

Dealing with HTTP connections

Hi, Nick again. Thought I'd write about this (extremely overdue) topic of HTTP connections in Android apps using Java. However, as this is a blog post and not a textbook, I cannot deal with too many technical details. Click the hyperlinks in the text to bring up the relevant information pages if you wish to read more about these topics.

HTTP CONNECTIONS

To start off, we first look at HTTP. HTTP stands for Hyper-Text Transfer Protocol. It is the "language" of the web; your browser requests data from web hosts via this mode of communication. The web host then sends back the relevant data, which could be HTML files (webpages), images, videos, anything.

When a client (your browser) talks to a server (the web host), we say that a session has been established. The client sends a HTTP request, and the server replies with a two-part response: a status line and the message body. The status line tells the client whether the request has been understood and replied to correctly. A status code of "200" means everything is OK, perfect. And as well all know, the status code "404" means the item requested was not found. There are many other status codes on Wikipedia here, but the one that we NEED to know is simply "200". This is the one that will come with a sensible message body, whose contents are our main concern.

So what's inside the message body? It depends mainly on the type of HTTP request that was sent by the client. There are two main kinds: GET and POST. A GET request is simply asking the server to return a resource, while a POST request means the client is sending, or "posting", data to the server for some purpose, and the response should describe the outcome of the sending. A good example of a POST request is a login. The client sends the username and password to the server, and the server, after checking, will return a message describing the success or failure of the login. An example of a GET request is asking IVLE for a list of modules; in this case, the message body would contain the list of modules.

However, each server has it's own way of structuring its response content. The list of modules returned by the IVLE server above are usually in JSON format. JSON stands for JavaScript Object Notation, and it's a handy way of dealing with data. JSON has two main data structures: Object and Array. An object is a unordered set of key-value pair mappings, where the keys are strings and the values are either objects, arrays, or primitives (int, boolean, etc). An array is an ordered set of values, and these values can be objects, arrays, or primitives as well. The values are accessed by calling the relevant position in the array. A JSON structure can be written as a string, where the { } curly braces represent objects and [ ] square brackets represent arrays.

ANDROID IMPLEMENTATION

Now that we know how HTTP connections work, we can take a look at how to implement them in an Android app.

I am sure we have all experienced a webpage loading very slowly before, or our internet-based game "lagging". This is usually caused by the server not responding to our computer's HTTP request immediately, but the browser or game needs the data to carry on. In this case, the only thing to do is wait for the response. Waiting is not optimal, as the response may really take ages to reach the client. Also, on single-threaded programs, the waiting time would make the computer appear to have "hung" because the program cannot continue without the response data. Let's make a simple example: you dial your friend on your phone, and while waiting for your friend to pick up the call, you stop doing everything else. No walking, no blinking, no breathing even. It's pretty difficult to live like that.

Fortunately, we can multitask, and so can Android apps (multi-threading). They have the capability of running multiple threads in parallel, which means one program can do a few things at once. Every app has one main thread, which the User Interface (UI) runs on. If we perform a task on the main thread that takes up a lot of time, the UI will freeze for that amount of time. Even if we try to show a loading bar, the bar will freeze at a point while the task runs on the main thread. However, if we run our time-intensive task in the background on a separate thread, then the loading bar can show normally and the UI will not freeze. The background task will then notify the UI thread once it is complete, and then the UI can update itself accordingly.

Android provides us with a nice, easy-to-use Java class called AsyncTask, which allows us to run a background (asynchronized) task and then return the result of the task to the main thread upon completion. We therefore put our HTTP requests in this AsyncTask, so that the program can wait for the server to respond and yet not have to suspend all other activities. Click the hyperlink to view the AsyncTask API if you want more implementation details.

To carry out the HTTP connection in Android, we need to first create a URL object. URL stands for Uniform Resource Locators, which is the string of letters and symbols you see in the address bar. The object is created by defining the URL in the constructor. A HttpURLConnection object is then created from the URL object's openConnection() method. The status code (remember "200" and "404"?) and the response content can then be requested from the server by running getResponseCode() and getInputStream() respectively. The Input Stream received must be read by a stream reader to get the entire response content. Since we have been running on the background thread, we just need to send the response content back to the main thread for the UI to be updated accordingly.

IVLE AND NUSBUDDY SPECIFICS

Let's now focus specifically on the IVLE LAPI's URLs and responses.



The IVLE LAPI (Learning Application Programming Interface) is a collection of URLs to which HTTP requests can be sent, and relevant responses received. We use HTTP connections establish sessions with the IVLE servers such that we can send, request and receive data regarding the following:

  • Login
  • Modules
  • Announcements
  • Gradebooks
  • Final Exam Timetables
  • Student Profile

When a user calls the URL for his profile page, and the data of the profile would be sent back to him. The URL for the Student Profile looks like this:
https://ivle.nus.edu.sg/api/Lapi.svc/Profile_View?APIKey={String}&AuthToken={String}
The APIKey is a unique key to identify the caller, while the AuthToken is an authentication token for the current logged-in user's session. 

The response content is, by default, structured in the JSON format (as mentioned above). This means we can read the response content as a string. This string is then parsed as an actual JSON object using the Java class called JSONObject. We can now easily extract the data from the response using get() methods on the JSONObject object.

The actual JSON response string looks like this:
{"Results":[{"UserID":"a0108358","Name":"NICHOLAS LUM AIK YONG","Email":"a0108358@nus.edu.sg","Gender":"Male","Faculty":"School of Computing","FirstMajor":"Computer Science (Hons)","SecondMajor":"","MatriculationYear":"2013"}],"Comments":"Valid login!","LastUpdate":"\/Date(1400344894329+0800)\/","LastUpdate_js":"2014-05-18T00:41:34.3293461+08:00"}
It's kinda messy in string form because of the nested objects and arrays, but with an online JSON parser, the structure can be made pretty clear:
With this data, we can then build the profile page of the user that requested it.

In our app, we work with JSON quite a bit because it's the default response structure of the LAPI. It is also very convenient to use as a simple data storage object because of the key-value mappings. One drawback is that if the JSON structure in the server's response changes, our methods for extracting the data would break.

SUMMARY

We have covered HTTP requests (GET & POST), the JSON structure, multi-threading in Android with relevant classes, HTTP connection objects and how to deal with responses, and finally an example of how we apply these methods in our NUSBuddy app.

Update 15 June: A Different GUI

Hi, it's Nick. Haven't blogged in a while because we've been too engrossed in coding, haha.

We decided to implement the Tests and Quizzes page, which is similar to the Homework Planner page. This section of the app was originally not planned for in our Trello Board, because the implementation is very similar to the homework planner and we thought it would not be worth doing as we wouldn't learn anything new. However, we felt that the minimum viable product would be more complete if we added this in. Anyway it's good that we did it, because we had the opportunity to rethink our GUI design.

L-R: Test and Quizzes and the expanded Event view

So why did we even think of redesigning in the first place?

Our first idea was to make something similar to the original design in our mock-up, which allows all events to be manipulated on the page itself without further navigation. Then we decided to do away with the "box" design so that we can utilize more screen real estate. This also made the layout look neater (in our opinion). We then tried to put the date and time on the same line as the event title, but it didn't look very nice because of the arrow at the side. Thus we opted for the two-line format, similar to the View All page of the Homework Planner. The click-to-expand feature stayed, but we made changes. The location header is a simple "@ " while the description header is gone. Also, the buttons have been pushed to the corners.

There are still a few kinks to iron out from this design. The date and time display line could be improved by finding a better place to put the time field. I think that it's a little out of place right now. However, if the time is placed on a new line, each event box would take up extra height. We might simply just encode the date and time as one string, similar to the homework page.

Also the delete and edit buttons could use a redesign themselves. The default button style does not suit the context very well. The placement of the buttons could be improved too, as I find that there is a lot of empty space wasted in the middle, but if the buttons are close together it doesn't look good either. Maybe's it's really down to the button style.

Lastly, to prevent clogging up of the page, we might only show at most two (or just one?) events, with a "see more" expander to show the rest if needed. While this is excellent at saving screen space, it reduces the "bird's eye view" advantage, which is our main selling point. Also, this is very similar to the View All feature in the current Homework Planner page.

Comparison of the Tests vs Homework pages. Click to enlarge.
L-R: Tests and Quizzes page, Homework Page, Viewing All Homework of a module.

So what do you think? Is this design better, or would you rather the one from the Homework Planner? I personally like this one better, and if we both continue to like it then we will refactor our homework planner page (and likely the other pages also) to look like this.

Anyway I'll be off Serving The Nation until the 21st, and Jiawei is involved in FSC too, so we're gonna be inactive for the most part of next week. Hopefully we don't fall too far behind!

Friday, 6 June 2014

Update on 6th June

Hello it's Jia Wei this time round. This post will be more technical so please bear with it.

Nick and I are now implementing the "View" homework page, which allows one to view all their homework in a particular module.

This is how it looks:





Upon tapping a homework, the tab expands.


Upon pressing edit button:


Some of the problems we faced was the delete button problem. To remove a homework, we must remove it from the database, the view homework page and the homework page. To ensure a user experience, we tried to remove deleted homework as fast as possible. We did this by overriding onBackPressed() (this method is called whenever the android back button is pressed) but this method appears to have some loopholes.

The showing and hiding of information when the user tap their homework was manageable but tedious. Aside from changing the hidden information visibility, we also had to get the homework data from database and set them into separate containers. We also had to implement a random id generator to help randomise the id of these homework since each homework is unique.

As of now, we are trying to have the fields in Add Homework page filled up with information whenever the press the edit button. There is also the need to reformat how the date in the date field will appear. Oh, and set a limit to the year since once it hits 2038 for the calendar goes back to the 1900's after year 2036.

Some minor bugs discovered while blogging:
- Due date (both date and time) of homework are set to calendar mode. This means we can set a due date that has already passed. We'll need to set limits to this.

And... after some googling, turns out that Calendar provided by Android is buggy.
Okay, time to get Nick to help me out again...


Thursday, 5 June 2014

Update 5th June: Doing Homework!

Hi all, it's Nick.

We have just started the first sprint iteration, which runs until the end of June. Our main focus this sprint is to complete the Homework Planner and the CAP Calculator. We are still in the midst of creating the Homework Planner, so I'll just show some of its sub-features that we managed to implement so far.

But first, our new splash screen!
This screen will show when the app starts or when the user is logging in. It may not look very impressive but it seems like a sleeker interface as compared to progress dialogues popping up everywhere. This is simply the login screen, but with the text fields hidden and a small progress ball shown.

Alright, now on to the Homework Planner.
The boxes shown here are containers for homework items, segregated by module. The module codes are gotten from the IVLE API, and then used to dynamically generate the view. The page is empty now because we have no homework items yet.

So how does one add a homework?
Tapping on any of the module containers will bring up a popup menu with two options, Add and View All. The popup menu is bound to the module container which was tapped, so if the user decides to add a homework, the homework item will be put under the chosen module, as we shall see.

Tapping the Add option brings the user to the Add Homework page.
The user will then fill up the relevant fields. The only two required fields are the Event Title and the Date. Here are a couple of examples for filling up the details.
Ticking the Recurring Event checkbox will cause additional radio buttons to show, offering more details of the event recurrence. We still need to beautify the page a little more, but for now it's functional. After filling in all the information, we press Add Event to save the homework item to the database backend. The Add Homework page is then closed, and the Homework Planner page is brought to the front again.
The image above shows a populated Homework Planner page. The homework items are stored in a database backend, local to the phone. On creation or refresh of this page, the database is polled. As a module container is being created (dynamically), the logic also performs a database query for all the homework items that are bound to that module. These homework items are then displayed under the appropriate module code.

For our next step, we will implement the View All page. This page will showcase all the homework items under a selected module, and will offer deletion and editing of the homework items.

Some details of our backend database implementation:

  • We are using the Android API version of SQLite. 
  • The database currently only has one table, "homework". We are still looking to see if we can utilize it better.
  • We chose to use a local database because its response time is much faster than cloud storage.
  • Also, it should be possible to retrieve the actual .db file and upload it to a cloud storage if the user wants to backup his data.


Alright that's all for now, hope to have Jiawei writing the next post :)

Thanks for reading!
Nick