Sunday, February 16, 2014

REST Calls, caching, and threading on Android

Recently I was granted access to Riot Games API allowing me to finally create a League of Legends app.  I've had a decent amount of experience of making basic applications Android applications such as my most recent release for Blizzards new game Hearthstone found here.  However this app would require much more advance skills then I have done in a java android environment.  For this project I needed to figure out how to accomplish what I stated in the title Rest calls,  caching, and threading! So after doing the leg work I present to you how to effectively  thread your app, make a rest call, and cache that call for later use.

The first step in this process is making and using a thread.  Threading in java and android is actually quite trivial but very important, if you don't use threads on asynchronous task such as making REST calls to a database then your app will lock up while it waits for an answer to your request. This way the user call still interact with the phone, use the UI or cancel the request, all without having to wait or thinking the app has gone unresponsive and force closing.   Threads are their own virtual class, so all you need to do is create a new thread and implement the run method as show below.

new Thread(){
    public void run()
    {
                       //I'll make a rest call from here so I lock up my UI!
                }
   
}.start();


The .start(); at the end of the new Thread creation is telling android to start doing what is in the run method once you reach this line of code.  Alternatively if you don't want to run the thread from within a method or would like to set it up, call it later or call it multiple times you could do the following.

Thread restThread = new Thread()
{
                public void run()
     {
                       //I'll make a rest call from here so I lock up my UI!
                }
}

void main()
{
      restThread.start();  // this will start the thread whenever whereever as many times as you want
}

Once our thread is started we can safely make our REST call without locking down the program. Making a rest call from java is also just a matter of a few steps.  We need to create an inputstream for our program to get return data from once the connection is made. We then try to open up a HttpURLConnection and set our request method in this case this is a GET method,  and any other header information we may need. We check the response code to make sure the connection worked. Then we make a character array large enough to hold all the data we get back from our server and start to read the data from the input string into our char array.  Just like that we made a set up a connection, requested data, and took data into our program.

IMPORTANT:  You must have the follow permission in your manifest file in order to have access to the internet and make these calls.  <uses-permission android:name="android.permission.INTERNET" />

InputStream  input = null;

try{
     URL url = new URL(www.databaseWeWannaCall.com);
     HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection();

     if(!(httpConnection instanceof HttpURLConnection))
      {
           throw new IOException ("this url is not a http url");
      }

       httpConnection.connect();
       int responseCode == httpConnection.getResponseCode();

       if(responseCode == HttpURLConnection.HTTP_OK)
      {
          input = httpConnection.getInputStream();
       }
}
catch(MalformedURLException e)
{
e.printStackTrace();
}
catch (IOException e) {
       e.printStackTrace();
}

try
{
    InputStreamReader inputReader = new InputStreamRead(input);

    int charRead;
    String ResponseText = "";
 
    char[] inputBuffer = new char[Size of data pulling down]  //if you dont know the size just make it a very                                                                    //large number it isn't efficient but it will get the job done for now.

    while((charRead = inputReader.read(inputBuffer))>0)
    {
           String readString = String.copyValueOf(inputBuffer,0,charRead);

            ResponseText += readString;
            inputBuffer = new char [Size of data pulling down];
     }
      input.close();
}

Just like that we now have a string called ResponseText filled with all the data we queried from the server.  Now that we have this data we still have a slight problem because the data is in our new thread we created, our next challenge is getting the data out of the thread and back to the main activity.  We do this by using a message system.   To do this we first set up our message handler, this is where when we send the message the data will be accessed inside our main activity.

 private Handler myHandler = new Handler() {
       
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
                 //do stuff with our data
          }
    };

Making a new Handler() requires us to implement the method void handelMessage(Message)  this method is called when a Message is broadcasted to the program.  But how do we send a message, as well as data with it?

Message msg = Message.obtain();

Bundle responseBundle = new Bundle();
responseBundle.putString("Response", ResponseText);
msg.setData(responseBundle);
myHandler.sendMessage(msg);

First we create our message object using the .obtain method. We then need to change our data from a string to a format that a message can send.  Java has a Bundle class which will do just that for us.  a bundle is basically just as it's called a bundle of information, it holds data along with a key to be accessed later much like a dictionary.  We take the bundle put our string into it and send the message to myHandler.

Taking the data back out of the bundle is trivial just add this one line of code into the myHandler. This takes the data from the message in the bundle with the key "Response which we set up earlier when packaging the message.

msg.getData().getString("Response"));

We that we have a full rest call system set up with threading we can worry about caching the responses we get.  Caching is a very important to do especially on the android environment we don't want to make our user make extra calls to the database especially when not on wifi.  There is a built in caching solution in the URL class which is very hands off, it supposedly takes care of everything for you and gives you very little access.  Because of this i chose to run with my own implementation of caching which is actually quite simple. All you need to do is write the data to a file and before you make a call to the database check to see if you  have data in that file and when's the last time you made that call and saved the data.  If the data is constantly changing  you want to make sure that they data will be refreshed periodically so that your first cache doesn't stay around forever.

I check the time by using javas built in Calendar class.

Calendar myCalnder = Calendar.getInstance();

gets a object that holds year month day hour minute seconds in a clean way.  I just update the calendar each time I'm about to make a call and compare it to the caches calendar. If more than the time i've wanted the cache to last has passed I make my REST call otherwise I use the cache file.

Another good thing to do is add a way for the player to clear our the cache and force a updated REST call.   One thing I did in my implementation and would also recommend in a mobile environment would be to make sure, if you have cache and it's supposed to be updated, if the user is not connected to wifi don't update the cache wait until they have wifi and then let it happen.  This way the user is angry that your app is using up all of their data plan.

You can check to see if the user is connected to wifi by doing the following call

 if ( NetworkConnected())
{
    //make the rest call
}
else
{
    InputStream input =  openFileInput(My_Cache_File);
}

you also must have the following permissions in your manifest file
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

That's pretty much all you need to know in order to get your own REST calls threading and caching working within and android environment, it's a very powerful tool and will open up endless possibilities for your app development.

I wish you all luck, and until next time, thanks for reading.

-Ian Percoco


No comments:

Post a Comment