Monday, May 28, 2012

Android: Running Background Tasks

In my app I'm using the asmack library as the back bone for packet sending and processing. Doing these in the context of the UI thread is not ideal as it may freeze the UI and leads to perception of app freezing. 


The better way to solve this problem is to run these tasks in the background. In general, this can be solved by having the UI thread queueing a Runnable onto an executor, and having the Runnable send a Broadcast when it finishes.


In practice, you'll need to instantiate an executor first: 

       /**
* Restart the executor pool.

*/
private void initExecutor() {


m_executor = Executors.newFixedThreadPool(1);
}



Then implement your Runnable:

/**
* Logs into the server.

*/
private class loginRunnable implements Runnable {


String user;
String pass;


public loginRunnable(String user, String pass) {


m_loginUser = user;
this.user = user;
this.pass = pass;
}


public void run() {


// TODO: 
                        // Implement your login routine. 


// Notify login success.
m_app.sendBroadcast(new Intent(LOGIN_SUCCESS));
}
}


To queue the login request, simply do: 
        m_executor.execute(new loginRunnable(user, pass));


After your Activity queues the Runnable onto the Executor, you should consider populating a loading Dialog indicate the request is being processed. The Dialog should be cancelled when the complete event is received in the Broadcast Receiver. 

Sunday, May 27, 2012

Android: Using Preferences

Sometimes I find myself needing to cache certain little system status, such as if the user is currently logged in, what the logged in username/password are, etc. Using SQLiteHelper in this scenario is probably an overkill. This is when SharedPreferences comes in handy. In my app I implemented a simple Preferences class with the following definition: 



public final class Preferences {


/** 
* Configurable attributes. 

*/
public static final String LOGIN_USERNAME = "username";
public static final String LOGIN_PASSWORD = "password";
public static final String LOGIN_STATE = "loginState";


private static SharedPreferences pref;


private Preferences() {


}


static public void init(Context context) {


pref = context
.getSharedPreferences("PREF", Context.MODE_PRIVATE);
}


static public void setBoolean(String key, boolean value) {


pref.edit().putBoolean(key, value).commit();
}


static public boolean getBoolean(String key) {


return pref.getBoolean(key, false);
}


static public void setString(String key, String value) {


pref.edit().putString(key, value).commit();
}


static public String getString(String key) {


return pref.getString(key, null);
}
}


Since the function is implemented as a static class, one can simply call 


Preferences.setBoolean(Preferences.LOGIN_USERNAME, user); 


to set the variable anywhere else in the app. 

Tuesday, May 22, 2012

Setting up Ejabberd

For the Android app I've been developing, I've been using OpenFire as the back end for development purposes. Openfire was chosen mostly for convenience, but I didn't plan on using it for production as it costs when number of user scales up.
I did a bit of research and settled on ejabberd for my production server. Installing the server was as painless as it can get:


sudo apt-get install ejabberd


Note that this will install the ejabberd from the repository, which may not be the latest. I did grab the latest copy, but had problem install it.


After installation completes, I had to do some custom configuration.
Stop ejabberd first:


sudo /etc/init.d/ejabberd stop


Open the cfg file:


sudo vi /etc/ejabberd/ejabberd.cfg


For debugging purposes, I enabled debug log:


{loglevel, 4}


Set the admin user:


{acl, admin, {user, "ricky", "password"}},


Set the host. Since I repurposed another PC at home, I just set the host to its IP address:


{hosts, ["192.168.1.101"]},


For my application, I also needed to enable user directory search:


{mod_vcard, [{host, "search.192.168.1.101"}]},


That's it. To restart the server:


sudo /etc/init.d/ejabberd start


To view the log, you can:


tail -f /var/log/ejabberd/ejabberd.log


Another useful feature is to dump the current database: 


sudo ejabberdctl dump /tmp/ejabberd_dump


You can Google ejabberdctl command to see the exhaustive command set. 


I'm also using asmack for the client. I'll put up some other posts in the future regarding asmack.