Posts Tagged ‘java’

A Whole Mess of Android Helpers

Overview


In my work on my MMA fighter Android app Knuckle Head I used a lot of Android functionality that I’m sure I’ll use again. Things like JSON processing, asynchronous tasks with ProgressDialogs, and single instance Toasts are all things that will inevitably show up in future work. Because I’m just so generous, I decided to refactor them out of the Knuckle Head specific code and turn them into a Java package anyone could use.

* Clone or download

 

The Classes


Its a small collection so far, but sure to grow very quickly. Here’s a list of the classes included so far:

  • – A collection of JSON handling functions. Includes Retrieving JSON from a remote URL.
  • – A generic key/value pait class. Useful for populating Android Spinners.
  • – A collection of static classes for operations I don’t have a better home for.
  • – I hate how Toasts in Android are shown sequentially. To prevent this I operate on a single instance of a Toast throughout my apps.
  • – A class that utilizes ToastSingleton.java and delivers Toasts with convenient static functions.
  • – This is a custom AsyncTask for a very common Android problem. I very often need to retrieve JSON from a remote URL, display a ProgressDialog while this occurs, operate on the data when it is returned, and then close the ProgressDialog. With this class that work is reduced down to just a few lines of code.
 

UrlJsonAsyncTask Example


If you had only have time for a quick look, be sure to check . Using this class in side my Activity code reduced the line count drastically. Since I was lazy about documentation for any of this, here’s an example to reward my blog reader’s. This is straight from Knuckle Head code. You’ll notice a few other classes mentioned above are also included.

UrlJsonAsyncTask is not abstract like AsyncTask, most of the functionality has been implemented. You only need to implement onPostExecute(JSONObject) if you want to do something with the returned JSON. In order for this to work, your JSON needs to return an object formatted like this:

{
    "success":true|false,
    "info":"error or warning message from server",
    "data": {}
}
  • success is a boolean indication from your JSON source whether or not the request was successful
  • info on error or warning, will contain an app user friendly message that can be delivered via Toast
  • data This is the actual JSON object or array that you will operate on given a successful request
 

And this is how you would define your own UrlJsonAsyncTask. In this case I am querying my server to get a list of fighter, or the profile of one particular fighter. In either scenario, as stated in the JSON description above, the “data” attribute of my JSON is what I will pass to the target intent.

private class FighterSearchTask extends UrlJsonAsyncTask {
    public FighterSearchTask(Context context) {
        super(context);
    }
 
    @Override
    protected void onPostExecute(JSONObject json) {
        try {
            this.validateJson(json); // throws IOException, JSONException
 
            // These 4 lines represent the actual post execute logic
            Class> intentClass = json.getString("info").equals("list") ? FighterListActivity.class : FighterTabActivity.class;
            Intent intent = new Intent(context, intentClass);
            intent.putExtra("json", json.getString("data").toString());
            startActivity(intent);
        } catch (IOException e) {
            // IOExceptions are custom and return JSON "info" in getMessage()
            Toaster.toast(this.context, e.getMessage());
        } catch (JSONException e) {
            // Lazy.Ex.getStackTrace(Exception) is just a simple one liner for turning 
            // a stack trace into a String.
            Log.e("YourTagName", Lazy.Ex.getStackTrace(e));
 
            // JSONExceptions here are generally because your JSON is not formatted as 
            // per the description in the comments above. We don't want to show these 
            // errors to the user, so we give them a pre-defined error message to let 
            // them know something went wrong.
            Toaster.toast(context, this.getMessageError());
        } finally { 
            super.onPostExecute(json); // Must be called to close the ProgressDialog
        }
    }
}

After you have created your subclass of UrlJsonAsyncTask, you can execute these following few lines of code anywhere to fire your task and have a ProgressDialog pop up until it either finishes successfully or or returns an error/warning message. There’s tons of setters to customize your task. Check them out in the .

FighterSearchTask task = new FighterSearchTask(SearchActivity.this);
task.setMessageLoading("Searching for fighters...");
task.setConnectionParams(2000, 5000, 3); // connection timeout(ms), read timeout(ms), number of retries
task.execute(url);

And voila, you got JSON from a remote URL with a ProgressDialog assuring your users that the data is in fact loading. All of this is non-blocking so you are able to continue other operations or update the UI if necessary.

Summary


So yeah, it’s just another collection of a developer’s reusable tools for getting stuff done, this time for Android. If you do happen to peruse, or use, the code, let me know what you think. Suggestions,criticisms, and of course contributions are more than welcome.

Knuckle Head: My MMA Fighter App for Android

Get the App


* Click here to download “Knuckle Head” on the Android Market!

Overview


Knuckle Head is an app for the true Mixed Martial Arts fan. It allows you to search a database to find details on any fighter in the world, not just the UFC. In just a few touches you can search by name, nickname, or weight class to find every detail about your favorite fighters. This is not just another MMA news app. Inside you’ll find fighter images, detailed fight records, vital statistics, and other MMA analysis.

Oh, and I love feedback, so tell me what you want next!

Screenshots


In Case You Were Interested…


I’ll have some technical blog posts regarding this app up very soon. There’ll be lots of native Android development goodies to be gleaned. In addition I’m likely gonna post up some Android/Java convenience classes I’ve been using for various tasks like JSON handling, AdMob, ProgressDialogs, and more to my . Stay tuned.

Handling Global Configuration in Android

The Problem

You have configuration variables and data that you want to share globally in your Android app. You want all Activities to be able to access and edit the same instance of application specific data.

Generic Solution

You could create a Configuration class loaded with static members or as a Singleton. Now you’ve got a shared, single instance of your configuration that can be accessed anywhere in your application. But there are 2 minor drawbacks to this method in the context of Android development.

  1. You now have to initialize your configuration in a separate class, in this case, your startup Activity.
  2. You’ll need to carry this new Configuration class around in all your projects.

Neither of these problems are critical, but let’s see if we can do better.

Android Solution

In Android it is possible to extend the Application class in order to store additional application specific information… like say configuration data. These additional members are then accessible in any Activity via the getApplicationContext() method.

The first step in this process is extending your app’s Application object. Android gives your app a generic Application object by default, so you may have never even had to look at this class directly. But as you’ll see below, its pretty simple to extend.

SampleApplication.java

public class SampleApplication extends Application {
    private String mStringValue;
 
    @Override
    public void onCreate() {
        // Here you could pull values from a config file in res/raw or somewhere else
        // but for simplicity's sake, we'll just hardcode values
        mStringValue = "SavageLook.com";
        super.onCreate();
    }
 
    public String getStringValue() {
        return mStringValue;
    }
 
    public void setStringValue(String value) {
        mStringValue = value;
    }
}

As you can see above, extending the Application class as SampleApplication is quite simple. You add class members for each bit of configuration data you would like to share throughout your application. In this example, we are simply saving a String value (mStringValue) that can then be accessed and modified in any Activity in SampleApplication.

After you’ve added your members and any necessary getters/setters, you need to override the onCreate() method. In the onCreate() method you can then initialize your class members with your configuration data. You can do this any way you want. To keep the example simple, I hardcoded the configuration value (mStringValue), but I commonly store configuration data in JSON files in res/raw and load them into my extended Application object. I won’t get into those details, though, as that will likely be a whole other blog post. Make sure you call super.onCreate() when you are finished.

NOTE: It’s not necessary to initialize your members in the onCreate(). For application-wide configuration data you would likely always do it in onCreate(), but you are technically free to manipulate the extended Application object anywhere in your app code.

AndroidManifest.xml

 version="1.0" encoding="utf-8"?>
 xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.yourdomain"
      android:versionCode="1"
      android:versionName="1.0">
 
    
 
     
        android:icon="@drawable/icon" 
        android:label="@string/app_name"
        android:name=".SampleApplication">
         android:name=".SampleActivity">
            >
                 android:name="android.intent.action.MAIN" />
                 android:name="android.intent.category.LAUNCHER" />
            >
        >
    >
>

The final modification to make our Android app use the new SampleApplication class is setting it in the element of the AndroidManifest.xml file. The only change we make to AndroidManifest.xml is adding the android:name attribute to the element. Just add this attribute and set it equal to the name of your extended Application object, in this case SampleApplication.

OK, so now your app is using your new SampleApplication class. How do we access the stored data in its members? See the basic usage below.

Sample usage in any Activity

public class SampleActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
        SampleApplication sampleApp = (SampleApplication)getApplicationContext();
        String localStr = sampleApp.getStringValue();    
        // perform operations on localStr
        sampleApp.setStringValue(localStr);
 
        // The rest of your Activity code...
    }
}

All you have to do is call getApplicationContext() and cast it to the type of your new Application object (SampleApplication). The resulting SampleApplication object can now be used the get/set any of the members you defined for it in SampleApplication.java.

Summary

Now you have a solid, Android native way to share data globally in your app code. While I’m a big fan of portable solutions, I feel this Android specific one is worth to have a clear distinction between the onCreate() of my Application versus my Activities. Hopefully this walkthrough was clear because this is something you will likely do very frequently when developing Android apps.

One final note. I can already envision some lazy developers’ minds churning, “I can use this instead of Intent extras!”… Don’t! Intent extras have a specific interaction context which is important not only to functionality, but also to readability of your code. Don’t undo this by just feeding them into the global Application object. Extending your Application object is a complement to Intent extras, not a replacement.

Android Quick Tip: EditText with DONE Button That Closes the Keyboard

Android Quick Tip

Close the keyboard when you click ‘DONE’… seems like a simple task, right? Unfortunately, clicking ‘DONE’ or the ‘RETURN’ button in even a single line Android EditText will not drop focus and close the soft keyboard. In most cases it will just generate a new line of text. So what do you have to do if you want to close the soft keyboard by clicking ‘DONE’?

First you need to set the android:imeOptions attribute equal to “actionDone” for your target EditText as seen below. That will change your ‘RETURN’ button in your EditText’s soft keyboard to a ‘DONE’ button.

* example_edittext.xml

 
    android:id="@+id/edittext_done"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:hint="Enter some text"
    android:imeOptions="actionDone"
    />

Now we need to create a custom OnEditorActionListener for the target EditText that will recognize when the ‘DONE’ button has been clicked. In it we override the onEditorAction() method, get an instance of the InputMethodManager, and use it to close the soft keyboard. Here’s the code for the custom OnEditorActionListener class:

* DoneOnEditorActionListener.java

class DoneOnEditorActionListener implements OnEditorActionListener {
    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        if (actionId == EditorInfo.IME_ACTION_DONE) {
            InputMethodManager imm = (InputMethodManager)v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
            return true;   
        }
        return false;
    }
}

Now go to the onCreate() method of the Activity that contains the target EditText. We’ll call it SampleActivity here. In here you will assign the new DoneOnEditorActionListener to the target EditText via the setOnEditorActionListener() method.

* SampleActivity.java

public class SampleActivity extends Activity {      
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.sample_activity_layout); // sample_activity_layout contains our target EditText, target_edittext
 
        EditText targetEditText = (EditText)findViewById(R.id.target_edittext); 
        targetEditText.setOnEditorActionListener(new DoneOnEditorActionListener());
 
        // The rest of the onCreate() code
   }
}

And there you go, your target EditText field will now close the soft keyboard whenever you click the ‘DONE’ button. Very handy and not too difficult. Enjoy.

Android Quick Tip: Remove ListView Dividers

Quick Tip

If you want to remove the dividers from an Android ListView, execute the following code on your ListView object.

ListView listView = (ListView)findViewById(R.id.your_listview_id);
listView.setDivider(null);
listView.setDividerHeight(0);

or if you are trying to remove dividers from a ListActivity, do this in your onCreate() method:

this.getListView.setDivider(null);
this.getListView.setDividerHeight(0);

And there you go, no more dividers. Enjoy.

Display Images from the Internet in Android

The Overview

Android ImageVIew
I’ll make my usual yammering quick so you can get straight to the good stuff. This is just a snippet to show you how you can display an image from the Internet in your native Android app via ImageView. This is ideal in a few situations, namely when you need to keep app size and initial load time down, or if it isn’t feasible to locally store all the images your app will use.

The Code

package com.savagelook;
 
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
 
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.widget.ImageView;
 
public class ShowImageActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
        // YOUR_LAYOUT is the name of your layout resource
        // IMAGEVIEW_ID is your ImageView in YOUR_LAYOUT
        setContentView(R.layout.YOUR_LAYOUT);
        ImageView imageView = (ImageView)findViewById(R.id.IMAGEVIEW_ID); 
 
        imageView.setImageDrawable(createDrawableFromURL("https://savagelook.com/misc/sl_drop2.png"));
    }
 
    private Drawable createDrawableFromURL(String urlString) {
        Drawable image = null;
        try {
            URL url = new URL(urlString);
            InputStream is = (InputStream)url.getContent();
            image = Drawable.createFromStream(is, "src");
        } catch (MalformedURLException e) {
            // handle URL exception
            image = null;
        } catch (IOException e) {
            // handle InputStream exception
            image = null;
        }
 
        return image;
    }
}