Monday, August 22, 2011

Use a common Tag for all your activities' logging

It is pretty common for any non-trivial Android app to be composed of several Activities which together interact with the user for the furtherance of whatever is the objective of the app itself.


It is also pretty common, especially during the development phase, to have a need to emit logs so that one can check certain events happen when they are supposed to, and invariants, for example, are satisfied.


The Android ADT (Eclipse plugin) has a very nice feature in the form of the LogCat View that shows all the system logs, including those coming from your applications: as there may well be tens of apps running (and logging) at the same time (especially on a live device -- as to why you should use a device for your testing and debugging, you may want to read this) the LogCat enables one to 'filter in' a subset, based on a 'tag'.


The tag used by the LogCat is the value of the string used for the tag parameter in the Log.x() calls:
Log.d("myApp.tag", "All is going well");

It is pretty obvious that, in any given Activity, we would want a constant to use as the tag:
private static final String TAG = "myApp.tag";
but this has the drawback that we would have to either duplicate that same statment across all Activities (and, even worse, keep them all in sync if we decide, for whatever reason to change them) or resign ourselves to use different tags for different activities.


Alternatively, we could use a common 'Constants' class to keep, amongst others, a constant Tag:
public interface Constants {
  public static final String TAG = "myApp.tag";
  // other constants...
}

This is not very friendly, however, as every log statement (and there may well be hundreds in your code) would look something like:
Log(Constants.TAG, "All is going well");
it's only 10 extra characters, but multiply that for several hundrends, and you've a veritable case of carpal tunnel syndrome on your hands (well, ok...).

A much better option is to use Android's mechanism to store common application strings, which also gives the additional benefit that it's dead easy to change the tag in one full swoop, should that ever be necessary: in one of the XML files in the res/values/ directory, have a line of the form
myApp.tag
and in your code, you can do something like:

public class MyActivity extends Activity {
  public static String TAG; // note no 'final' here

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    TAG = getResources().getString(R.string.TAG);
    Log.d(TAG, "Starting User Preferences activity...");
    // other initialization follows...
  }
}

This can be done in each and every of your App's activities, and then you can easily create a new filtered view in LogCat so that you can see only your App's logs, from all the activities, also with the reassurance that, should ever want to change that, it's just a one minute edit of the XML file


Saturday, August 13, 2011

HTTP POST for Android (with a twist: Protocol Buffers)

One of this blog's most visited entries (ranking always around the Top 5 Google results for "HTTP POST" too) elaborated on how to send data across to a server from a J2ME Midlet.


I thought it was high time for bringing this into the new Century, and provide an update as to how to do this from an Android smartphone.
It turns out that (a) the code is relatively straightforward and (b) that there is not so much difference after all from writing the same code for a desktop client: credit for this ought to go to the Android Google team who have done such a superb job of adapting the J2SE API to the Android platform...

THIS BLOG HAS MOVED TO codetrips.com


Please read the rest of this post on codetrips.com

Tuesday, August 9, 2011

Automating Eclipse launch

I've recently taken up the Eclipse team at Google (we integrate Google's internal build tools and distributed development environment with the Eclipse Platform) and we are constantly faced with the challenge of maintaining several distributions in a multi-user environment.


I thought I'd use some of the goodness we've come up with in my home environment too, so have put together a much-scaled-down version of our launch script, for my personal use - and thought I'd share this more broadly, as I'm sure other folks will find this useful too.


I generally have multiple installation and user configuration profiles, and even from the desktop launcher, I much prefer to use launch scripts than just pointing the shortcut to the binary executable.


Here is my generic configuration script:
#!/bin/bash
#
# Runs the stable version of Eclipse.
# By default, it will launch Indigo, installed in /opt/eclipse; different
# versions can be launched by invoking this script and setting the
# ECLIPSE_INSTALL and CONFIG variables to point to the correct places.
#
# The default configuration directory is set to '/home/$USER/.eclipse/eclipse37'
# but this can be changed exporting a different value for CONFIG.
# See /home/marco/bin/eclipse-helios for an example of how to do this.

##############################
# Globals (default value):
#
#   LD_LIBRARY_PATH           (/usr/local/lib:/usr/lib)
#     library search path for C++ dynamic libraries
#
#   ECLIPSE_INSTALL           ()
#     installation directory
#
#   CONFIG                    ()
#     user's configuration directory
#
#   MEM_ALLOC_POOL, PERM_SIZE (2,048MB, 256MB)
#     Memory allocation and PermGen size
#
#   JVM                       (/usr/local/java/bin/java)
#     Java VM executable (java)
#
# By setting any of the variables above after source`ing this script
# and before invoking launch_eclipse() the default value(s) can be changed
##############################
declare ECLIPSE_INSTALL
declare CONFIG
declare MEM_ALLOC_POOL
declare PERM_SIZE
declare JVM="/usr/local/java/bin/java"

##############################
# Concatenates input paramters to LD_LIBRARY_PATH, if not already present
##############################
munge_library_path() {
  for dir in $@; do
    if [ -n "${dir}" ]; then
      local is_present=`echo $LD_LIBRARY_PATH | grep ${dir} | wc -l`
      if [ ${is_present} -eq 0 ]; then
        export LD_LIBRARY_PATH=${dir}:$LD_LIBRARY_PATH
      fi
    fi
  done
}

##############################
# Sets up global variables with default values if not already set
##############################
check_dirs() {
  # Installation directory
  if [ -z "${ECLIPSE_INSTALL}" ]; then
    echo "You must set ECLIPSE_INSTALL to the Eclipse installation directory"
    exit -1
  fi
  if [ ! -d ${ECLIPSE_INSTALL} ]; then
    echo "Cannot find Eclipse installation directory (${ECLIPSE_INSTALL})"
    exit -1
  fi

  # Configuration directory, user-specific
  if [ ! -d "${CONFIG}" ]; then
    mkdir -p ${CONFIG}
  fi
}


##############################
# The location of the JVM, currently the default (OpenJDK 6)
##############################
locate_jvm() {
  if [ ! -e "${JVM}" ]; then
    echo "Could not locate a valid JVM at ${JVM}"
    echo "Trying to locate a valid java installation"
    JVM=`which java`
    if [ -z "${JVM}" ]; then
      echo "Could not find a valid JRE, giving up"
      return -1
    fi
    echo "Found a JRE at ${JVM}"
  fi
}

##############################
# Runs a few checks, sets up the LD library path and then launches Eclipse
#
# Param:
#   clean   will set the '-clean' Eclipse option that will clear the plugins cache
##############################
launch_eclipse() {
  check_dirs
  locate_jvm
  munge_library_path /usr/local/lib /usr/lib

  if [ "$1" == "clean" ]; then
    CLEAN="-clean"
  fi

  $ECLIPSE_INSTALL/eclipse $CLEAN -vm $JVM -configuration $CONFIG \
      -bundlepool $CONFIG/plugins \
      -vmargs -Xmx${MEM_ALLOC_POOL:-"2048M"} -XX:MaxPermSize=${PERM_SIZE:-"256M"}
}
This is used in the actual shell script (called, unimaginatively, eclipse):
#!/bin/bash
#
# Runs the stable version of Eclipse.
# By default, it will launch Indigo, installed in /opt/eclipse; different
# versions can be launched by invoking this script and setting the
# ECLIPSE_INSTALL and CONFIG variables to point to the correct places.
#
# See eclipse_config.sh for more details

source /home/marco/bin/eclipse_config.sh

ECLIPSE_INSTALL="/opt/eclipse"
CONFIG="/home/${USER}/.eclipse/eclipse37"

launch_eclipse


What is left is to just point a desktop (or menu) launcher to this script and replace the generic icon with the one in the eclipse/ folder (icon.xpm)




CREDITS -- I would very much like to gratefully acknowledge Machtelt Garrels and his much-consulted "Bash Guide for Beginners;" I never seem able to remember the bash conditional operators!