MOBILE

# BlackBerry Java Application Development : Networking - HTTP Basics

1/17/2012 11:46:39 AM

Threading

Another thing that makes working with networking difficult is that you must also use threading. Networking just can't be done without threading, but this also makes the applications more complicated and difficult. Network traffic is the epitome of a "long running task" by even desktop computer standards. Mobile devices and mobile networks are much slower than desktops! Therefore, you should always utilize a thread when doing anything that relates to sending or receiving of data over a network. Unfortunately, this means more complicated code, but there is just no avoiding it.

Threading is a way to branch the flow of execution and, in essence, performing two actions at the same time. Every piece of code that is executed is done so in a thread. We've never had to mention it before though because the samples that we've created haven't needed more than one execution path.

By branching the flow of execution we can have one thread sending or receiving data through a network connection while the other is allowing the user to continue to use the application, display menus, or enter data. If a thread were not used, the user would not be able to do anything else in the application while the network communication is happening. It would be unresponsive to menu clicks or even redraw the screen properly so the user would probably believe the application was broken or had crashed. This obviously isn't good, which is why the recommendation is to never do network communication unless it is done in a thread.

If you are unfamiliar with threads, the sample application we make here won't make much sense. It would be best to get this understanding and then return to networking later.

Connector class

Another critical part of the networking toolkit is the Connector class. This class has only a few static members and acts as a factory for all of the Connection types. The networking that we will be doing is of course one of these, but there are, in fact, many kinds of connections that can be made through the Connector class. This class is very flexible because the open method takes only one parameter-a connection string.

It may seem funny but the Connector class doesn't actually initiate a connection. It simply creates an object that represents the connection. The Connection object does the actual work of opening the connection sometime later when it needs to do so. Therefore, the Connector won't fail unless the connection string is invalid in some way.

A connection string is also called a URL but it is more than just an address like you might think of when web browsing. It can also contain all of the instructions and options that the Connection class might need in order to establish the connection. Certainly an address is part of that, but the options may be just as important and are likely to vary greatly depending on what kind of connection is being made.

When a connection string has options they are given as a name/value pair and are separated by a semicolon. An example of a connection string with an option that we will see and use later is http://www.someserver.com;deviceside=true. The Connector class puts no limits on the number of options a connection string might have. In the right circumstances, a connection string can get very long and complex.

HTTP basics

The BlackBerry SDK does provide good support for networking, but the support is primitive. Not only are there a myriad of ways to connect to a server in order to make a request, and that we as developers are left to account for them all, but we must also have a fairly detailed understanding of the underlying protocol.

In this case, we will be creating an HttpConnection object so we also need to have a basic understanding of the HTTP protocol. The only thing that most people really know about HTTP is that it is something you put in front of the website addresses in a browser.

The extremely simplistic answer is that HTTP is a protocol designed for requesting files from one computer by another computer. The name, Hyper Text Transfer Protocol, comes from the idea that a document would have HyperText links embedded into it, which a user can use to gather more information about a topic. When this happens, one computer would request the linked document from the other so that the user can see it. In order to make this happen, both computers have to understand what each other are saying and so the protocol, HTTP, was created to make this possible. The protocol has grown over time to do more than just get documents, but the basic idea is still the way it is primarily used, even today.

In order to support more than just document retrieval the protocol has a series of commands, or methods that are supported. The basic operations of GET and POST are by far the most common uses. HTTP v 1.1 added a few more commands such as PUT, DELETE, and a few others that are still not widely used.

The protocol requires a request/response pattern in which the sender issues a request, to get a file for instance, and the receiver then issues a response with the requested data if there were no errors. There is also a header in both the request and response where additional parameters can be placed. These parameters might give an indication about what type of document it is, how large it is, or the event authentication information if the document is secured.

This all makes sense when you look at it from this a low level like this. The point, however, is that we do need to know about it in order to make an application that uses it. Only the basic operations of GET and POST will be used here, but the important thing is that we have to build the request. Therefore, we need to know what pieces we will need to go into it and when to use them.

HTTP GET requests

So now that we have some of the basic information out of the way, let's start with a simple page fetch from a website. This is just a baby step of course, but we need to start somewhere.

The biggest part of this will involve simply setting up the thread to service the connection and then setting up the connection. The code isn't too difficult, but there are a lot of things that can go wrong as well.

Time for action - ‑ HTTP Basics

  1. Let's get started with a new project named HTTPBasics. Create a BlackBerry project in Eclipse and create a standard UiApplication derived class and a MainScreen derived class.

  2. At this point you need only one field added to the screen-a RichTextField called _Output. Add a constructor for the screen and then add that field to the screen in the constructor.

  3. You need one more class in this application, a thread to handle the processing of the request. One more time, create a new class derived from Thread called ServiceRequestThread.

  4. Now that the skeleton is in place, start adding some code. The first step will be to set up the thread with the data that you will need in order to make the request. Add these data members and the following constructor to the ServiceRequestThread class.

    protected String _URL;
    protected HTTPBasicsMainScreen _Dest = null;
    public ServiceRequestThread(String URL, HTTPBasicsMainScreen screen)
    {
    super();
    _Dest = screen;
    _URL = URL;
    }
  5. We will need more code in the thread, but we will come back to that in a bit. Instead, add a menu item to the HTTPBasicsMainScreen class so that you can start the request.

    protected MenuItem _GetDataAction = new MenuItem("GetData" , 100000, 10)
    {
    public void run()
    {
    String URL = "http://www.google.com;deviceside=true";
    ServiceRequestThread svc = new ServiceRequestThread(URL, (HTTPBasicsMainScreen)
    UiApplication.getUiApplication().getActiveScreen());
    svc.start();
    }
    };


  6. Don't forget to add the new menu item to the menu by adding this code in the constructor of the screen.

    addMenuItem(_GetDataAction);
  7. Another thing you need in the screen is a method to make sure the screen is updated safely.

    public void updateDestination(final String text)
    {
    UiApplication.getUiApplication().invokeLater(new Runnable()
    {
    public void run()
    {
    _Output.setText(text);
    HTTP GET requestsHTTP GET requestsHTTP basics}
    });
    }
  8. The last step is to implement the actual request and network call by implementing the run method of the ServiceRequestThread.

    public void run()
    {
    try
    {
    HttpConnection conn = (HttpConnection)
    Connector.open(_URL, Connector.READ_WRITE);
    conn.setRequestMethod(HttpConnection.GET);
    int responseCode = conn.getResponseCode();
    if (responseCode == HttpConnection.HTTP_OK)
    {
    InputStream data = conn.openInputStream();
    StringBuffer raw = new StringBuffer();
    byte[] buf = new byte[4096];
    int nRead = data.read(buf);
    while (nRead > 0)
    {
    raw.append(new String(buf,0,nRead));
    nRead = data.read(buf);
    }
    _Dest.updateDestination(raw.toString());
    }
    else
    {
    _Dest.updateDestination("responseCode="+ Integer.toString(responseCode));
    }
    }
    catch (IOException e)
    {
    // TODO Auto-generated catch block
    e.printStackTrace();
    _Dest.updateDestination("Exception:"+e.toString());
    }
    }


  9. If you run the application and click on the Get Data menu item, the screen will soon fill up with raw HTML from the Google.com home page!

What just happened?

Wow, that was exciting, wasn't it? It's not much to look at, but this simple application is a great example for demonstrating the basics of networking. The first few steps were all about setting up and getting started, but I didn't give you much help there. How did it feel? That basic setup has been done with every project we've made so far and will likely be the first steps of nearly every project in the future. I don't know why the "new BlackBerry project" template doesn't do all that boilerplating for you, but it doesn't.

We got into some code in Step 4 with setting up the Thread object. This is just basic stuff so we could add the code to create and start the thread in the menu in Step 5. Although this just shows that even though the thread runs separately from the rest of the application doesn't mean it can exist in a vacuum. We had to have some information to start the request, that is, the URL, and we had to have some way to get the results back out to the main application. This part was simply about making sure that information was collected.

In Steps 5 and 6 we created the menu item that will start the thread and added it to the application. For this sample, the connection string was simply hardcoded in the menu, but the thread is set up to be dynamic and allow the URL to be passed in as a parameter.

As we've said before, the URL is more than just a web address and this URL includes that parameter we mentioned earlier. First, let me explain that www.google.com was chosen simply because the web page loads fast and it isn't very large. Can you imagine trying to load a page with a lot more content?

Secondly, that parameter is used to force the device to initiate a TCP/IP direct connection. While there may be concern about using TCP/IP direct in a production application, this is just the simulator and we shouldn't face any problems using it. We could have left the parameter off completely and the result would still be the same. Each device has a default set that makes sense for the device, and for the simulator, the default is a TCP/IP direct connection.

Step 7 is where we added an odd looking little method to update the _Output field with the text that is being passed into the method. Why is this needed? Remember that this application is a multithreaded application. Updating user interface fields from another thread is dangerous! This is often said in another way; it is not thread-safe. There are other things going on in the other thread and when we try to set the text from the ServiceRequestThread, those things might conflict and cause problems. This is particularly important when something could happen that would cause the screen to be redrawn, such as in this case.

The invokeLater method is used as a way for one thread to ask another thread to run some code when there is a chance. The calling thread (the ServiceRequestThread) doesn't have any control over WHEN the code runs. The receiving thread, which in this case is the main application thread, will decide when to execute the code.

The last step in this code is where the real fun stuff happens. Everything up until this point is supporting code so we can make the request and do something useful with the response.

This first line is where we set up the connection and use the Connector class that was mentioned previously. The Connector class will always return a Connection HttpConnection object and so, it is cast to the proper type. We can safely cast it because we know for certain the URL class, but we really need an will begin with http://, which is what tells the Connector to make an HttpConnection object. Also, remember that the Connector doesn't actually open the connection, so as long as the URL is valid we should be fine. The second parameter specifies the permissions requested of the new connection. Even though we won't be writing at this stage we're still going to ask for Read and Write permissions for later on.

HttpConnection conn = (HttpConnection)Connector.open(_URL, Connector.READ_WRITE);



The call to the setRequestMethod is how we specify which HTTP command is to be sent to the destination address. Like we've seen a number of times earlier in the SDK, the valid values have been defined in the HttpConnection class to make things clear and easy to understand.

conn.setRequestMethod(HttpConnection.GET);


If we were making a more complicated request then there may be other parameters and values to be set before calling getResponseCode. However, for the simple fetch that we are doing here, there is nothing else required and we can issue the request. It should be plain to see that we make that request with a call to the getRespsonseCode method.

What? No, that's not clear at all!

Well, it does sort of make sense. How can you get a response code if the request hasn't been sent? The bottom line here though is that there isn't a single method that will make the request. Any method which requires the request to be sent will actually cause it to happen. It's an on-demand methodology that has its benefits, but clarity isn't one of them.

The whole purpose of getting the response code though was to get and check the return value to know if the request was successful or not. The HTTP protocol uses a defined set of numbers to indicate various success or failure conditions. A large number of them are defined as constants in the HttpConnection class. For the most part though, you will only be concerned about whether it worked or not and we check for this with the HTTP_OK constant. There are other constant values that can mean success as well, and so again, this is where the framework leaves the details to us to handle at a low level. Generally, any response code in the range of 200 to 300 means success of some kind, but this is where a detailed understanding of HTTP comes in useful.

if (responseCode == HttpConnection.HTTP_OK)

Once we know the request has succeeded, we can start to get the data that has been returned. In this case, it is done by reading 4k of data at a time and building up a StringBuffer object with the data. You can use a ByteArrayInputStream or other technique if you prefer.

InputStream data = conn.openInputStream();
StringBuffer raw = new StringBuffer();
byte[] buf = new byte[4096];
int nRead = data.read(buf);
while (nRead > 0)
{
raw.append(new String(buf,0,nRead));
nRead = data.read(buf);
}

The last step is to simply update the screen by using the helper method we created, called updateDestination. Generally, you won't be displaying the raw HTML in the screen like this though and you would process the data somehow.

Dest.updateDestination(raw.toString());

Pop quiz

  1. What method is used to determine if the request succeeded?

    a. isSuccess

    b. HttpConnection.HTTP_OK

    c. getResponseCode

  2. Which command is used to issue an HTTP request?

    a. HTTPConnection.GET

    b. HTTPConnection.REQUEST

    c. HTTPConnection.SEND

  3. All networking communication should be done within a thread.

    a. TRUE

    b. FALSE

Have a go hero - but what if it didn't work?

In spite of laying out good plans and even using already tested code, sometimes things just don't work. Debugging this kind of situation can be very hard! For me, I always assume that there is some kind of bug in the code first, but when dealing with networking code we have to look at the environment as well. If this sample didn't work you are in luck because you know that it can't be the code that is wrong.

Remember that even though we are running this in the simulator, that simulator is running on your computer, which is a part of your network. The simulator doesn't try to simulate the network traffic. No, it actually issues the request on your computer so that the request can be completed for real. This means that the simulator is connecting to the network and sending data to the host just like the device will do. This also means that if there is some networking issue on the computer you are running the simulator on, it will interfere with the application being run on the simulator in the same way. Do you have a firewall running? Is your networking configured correctly? There are a 101 possibilities as to why the simulator might be failing-all of them dealing with the computer it's running on.

Now, you may try to run the browser in the simulator as a test to make sure that the simulator is working right. Sadly, this isn't going to work without running an additional program on your desktop. We'll use this program later, but for now, just understand that the simulator browser application isn't a good way to test things out.

The best way to test things out is through your standard desktop browser. Can you address the host or service you are trying to connect to? If you can't do it through your desktop browser then the simulator isn't going to work either.

HTTP POST requests

The other method that is available in HTTP is the POST method. Using an HTTP POST is the most common way to send data to a server and it is supported with the HttpConnection (which we just used). The server will send some data back as well, so a POST command isn't just a one way message. Consider it to be a POST immediately followed by another GET, all rolled into one command.

Historically, an HTTP POST is used to submit a form on a web page once the user is done filling it out and has clicked a Submit button. You can certainly use a BlackBerry application to do an HTTP POST to interact with forms like a user would do, but this isn't the best approach.

Because the forms are meant to look good, be displayed on the screen and interact with a user there is a lot of other stuff that comes along with the HTML than just the form. There will be HTML tags related to the layout of fields on the form, there may be color or image tags, or even JavaScript, all of which a BlackBerry application just doesn't need to be concerned with. For these reasons, you shouldn't interact with HTML pages unless there is no other choice.

The clear alternative is to utilize a web service of some kind to trade information with a server. With a web service there isn't any other data related to formatting or presentation, and so the amount of data being transmitted is significantly less than utilizing web pages like a user might use. These can also use the HTTP POST method.

For simple web services, the process for making a request is exactly the same as the process of submitting a form like a user might do. The biggest difference is in the response data-a web service response should be much more concise.

In order to pass the data with an HTTP POST command we must get familiar with a new class-the URLEncodedPostData class. This class has two important purposes. First, it stores the data that will be sent with the request to the server as a list of name-value pairs. There is no data type information to go along with these parameters either; they are all just string values.

The second purpose is to encode the data into a URL encoded format. Why is that needed? The URL encoded format isn't complicated or special; it just makes sure that the data provided with the parameters can be sent to the server. The HTTP specification uses a lot of characters for special purposes within the protocol, and so those characters aren't allowed to be in the data being sent through HTTP. Some things, such as spaces, are ignored while others such as a greater-than-sign are given special meaning. We can't just do without these characters so we must encode them in some way so that they can be passed with the request.

Other  
  •  Mobile Phone Game Programming : Analyzing 2D Sprite Animation
  •  Mobile Phone Game Programming : Understanding Animation
  •  Synchronizing Mobile Data - Using Merge Replication (part 2) - Programming for Merge Replication
  •  Synchronizing Mobile Data - Using Merge Replication (part 1) - Using Good Design to Avoid Synchronization Failures
  •  Windows Phone 7 Advanced Programming Model : Advanced Data Binding (part 4) - Data Bind to Anything
  •  Windows Phone 7 Advanced Programming Model : Advanced Data Binding (part 3) - Showing Progress & Lazy Load Images
  •  Windows Phone 7 Advanced Programming Model : Advanced Data Binding (part 2) - Syndicated Services
  •  Windows Phone 7 Advanced Programming Model : Advanced Data Binding (part 1)
  •  Beginning Android 3 : The Input Method Framework - Fitting In
  •  Mobile Application Security : Mobile Geolocation - Geolocation Methods & Geolocation Implementation
  •  Mobile Application Security : SMS Security - Application Attacks & Walkthroughs
  •  iPad SDK : Popovers - The Stroke Width Popover
  •  iPad SDK : Popovers - The Font Size Popover
  •  Beginning Android 3 : The Input Method Framework - Tailored to Your Needs
  •  Beginning Android 3 : Working with Containers - Scrollwork
  •  Mobile Application Security : SMS Security - Protocol Attacks (part 2)
  •  Mobile Application Security : SMS Security - Protocol Attacks (part 1)
  •  Mobile Application Security : SMS Security - Overview of Short Message Service
  •  iPad SDK : Popovers - The Font Name Popover (part 2)
  •  iPad SDK : Popovers - The Font Name Popover (part 1)
  •  
    Top 10
    Nikon 1 J2 With Stylish Design And Dependable Image And Video Quality
    Canon Powershot D20 - Super-Durable Waterproof Camera
    Fujifilm Finepix F800EXR – Another Excellent EXR
    Sony NEX-6 – The Best Compact Camera
    Teufel Cubycon 2 – An Excellent All-In-One For Films
    Dell S2740L - A Beautifully Crafted 27-inch IPS Monitor
    Philips 55PFL6007T With Fantastic Picture Quality
    Philips Gioco 278G4 – An Excellent 27-inch Screen
    Sony VPL-HW50ES – Sony’s Best Home Cinema Projector
    Windows Vista : Installing and Running Applications - Launching Applications
    Most View
    Bamboo Splash - Powerful Specs And Friendly Interface
    Powered By Windows (Part 2) - Toshiba Satellite U840 Series, Philips E248C3 MODA Lightframe Monitor & HP Envy Spectre 14
    MSI X79A-GD65 8D - Power without the Cost
    Canon EOS M With Wonderful Touchscreen Interface (Part 1)
    Windows Server 2003 : Building an Active Directory Structure (part 1) - The First Domain
    Personalize Your iPhone Case
    Speed ​​up browsing with a faster DNS
    Using and Configuring Public Folder Sharing
    Extending the Real-Time Communications Functionality of Exchange Server 2007 : Installing OCS 2007 (part 1)
    Google, privacy & you (Part 1)
    iPhone Application Development : Making Multivalue Choices with Pickers - Understanding Pickers
    Microsoft Surface With Windows RT - Truly A Unique Tablet
    Network Configuration & Troubleshooting (Part 1)
    Panasonic Lumix GH3 – The Fastest Touchscreen-Camera (Part 2)
    Programming Microsoft SQL Server 2005 : FOR XML Commands (part 3) - OPENXML Enhancements in SQL Server 2005
    Exchange Server 2010 : Track Exchange Performance (part 2) - Test the Performance Limitations in a Lab
    Extra Network Hardware Round-Up (Part 2) - NAS Drives, Media Center Extenders & Games Consoles
    Windows Server 2003 : Planning a Host Name Resolution Strategy - Understanding Name Resolution Requirements
    Google’s Data Liberation Front (Part 2)
    Datacolor SpyderLensCal (Part 1)