David Caunt

Mobile Software Engineer

Subscribe to my RSS feed

Android Gotcha – Action Bar Home Icon Doesn’t Work

January 21st, 2012

Hopefully by now you’re using the Action Bar in your applications – it’s pretty much mandatory unless you’re making a game or something unusual. I recommend using the excellent ActionBarSherlock to deal with pre-Honeycomb platforms.

Jumping straight in with ActionBarSherlock can cause you to skip over the official ActionBar docs, leading to confusion over implementation details. On older devices the ActionBar home icon works fine and yet, on ICS, the button doesn’t work!

For packages targetting API level 14 onwards, you need to explicitly enable the home button by calling setHomeButtonEnabled()

In your onCreate, add the following:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
    getActionBar().setHomeButtonEnabled(true);
}

The moral of the story is to always read the official docs and be aware of the differences between a native and compatibility library ActionBar implementation.

 

Galaxy Nexus – Android 4 ICS Easter Egg

January 8th, 2012

On your Galaxy Nexus, go to Settings -> About phone and tap on the item which displays the version ‘Android version 4.0.1′ three times.

The settings screen and status bar will disappear and you’ll see this splash. Long press on the Android to enter a Nyandroid scene!

Android Gotcha – Unable to instantiate service

October 21st, 2011

If you’re using Eclipse and create an IntentService class using the IDE’s correction features you’ll create a class like this:

public class MyService extends IntentService {
 
    public MyService(String name) {
        super(name);
        // TODO Auto-generated constructor stub
    }
 
    @Override
    protected void onHandleIntent(Intent intent) {
        // TODO Auto-generated method stub        
        Log.d("MyService", "onHandleIntent (intent=" + intent + ")");
    }
}

I’ve added a Log call so I can see my service receive intents.

When you trigger the service in your application, you’ll immediately see this cryptic force close error in your logcat:

E/AndroidRuntime( 7758): FATAL EXCEPTION: main
E/AndroidRuntime( 7758): java.lang.RuntimeException: Unable to instantiate service com.example.brokenservice.service.MyService: java.lang.InstantiationException: com.example.brokenservice.service.MyService
E/AndroidRuntime( 7758): 	at android.app.ActivityThread.handleCreateService(ActivityThread.java:2177)
E/AndroidRuntime( 7758): 	at android.app.ActivityThread.access$2500(ActivityThread.java:132)
E/AndroidRuntime( 7758): 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1102)
E/AndroidRuntime( 7758): 	at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime( 7758): 	at android.os.Looper.loop(Looper.java:143)
E/AndroidRuntime( 7758): 	at android.app.ActivityThread.main(ActivityThread.java:4263)
E/AndroidRuntime( 7758): 	at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime( 7758): 	at java.lang.reflect.Method.invoke(Method.java:507)
E/AndroidRuntime( 7758): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
E/AndroidRuntime( 7758): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
E/AndroidRuntime( 7758): 	at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime( 7758): Caused by: java.lang.InstantiationException: com.example.brokenservice.service.MyService
E/AndroidRuntime( 7758): 	at java.lang.Class.newInstanceImpl(Native Method)
E/AndroidRuntime( 7758): 	at java.lang.Class.newInstance(Class.java:1409)
E/AndroidRuntime( 7758): 	at android.app.ActivityThread.handleCreateService(ActivityThread.java:2174)
E/AndroidRuntime( 7758): 	... 10 more

What gives?

The clue is in the java.lang.InstantiationException, which should be the first thing you search for. This suggests an issue with the constructor for MyService.

The problem is that the OS is looking for a constructor with no arguments, while the definition of IntentService has a constructor which takes a String name. This constructor is overridden by Eclipse. The correct definition of MyService looks like this:

public class MyService extends IntentService {
 
    public MyService() {
        super("MyService");
        // TODO Auto-generated constructor stub
    }
 
    @Override
    protected void onHandleIntent(Intent intent) {
        // TODO Auto-generated method stub      
        Log.d("MyService", "onHandleIntent (intent=" + intent + ")");
    }
}

Thanks to ddewaele on Stack Overflow for the correct answer.

Beyond the SDK – Improving the Android Development Workflow

April 7th, 2011

So you’ve got the Android SDK installed and Eclipse doesn’t seem as bad as you remember, but what else is worth setting up before you get stuck into a project? Below are extensions, tools and tips to improve your workflow.

Local documentation

If you have browsed your local Android sdk folder you may have noticed that there is a docs folder. This folder contains everything you can browse online at developer.android.com and can be accessed locally to avoid network latency and server/network downtime.

Open ‘file:///path/to/android-sdk/docs/reference/packages.html’ in your browser, replacing /path/to/android-sdk with your actual SDK path.

Note: I found that the API level filter doesn’t work in Google Chrome, probably due to local script execution. Firefox doesn’t have this problem, but if you will use Google Chrome, creating an Apache vhost for your docs is one workaround. If you know how to fix this, please leave a comment below.

Android SDK Reference search (Omnibox)

Android developer Roman Nurik has created a Google Chrome extension which allows fast Android SDK Reference search including both classes and XML elements. By simple typing ‘ad’ followed by your query, e.g. ‘ad ViewG’ you’ll see all classes beginning with ‘ViewG’.

This extension also adds links on class reference pages linking to the source on android.git.kernel.org.

Google Chrome Omnibox featuring Android SDK search

Source code for this extension is available at code.google.com and this extension could easily be customised to link to your local documentation (see above).

Android sources

Eclipse displays API documentation and autocompletes code but you can’t view the source of Android platform code within the IDE. Fortunately there is a plugin which will download and install the sources for you. You can then ctrl/cmd click on any line of code to see how it is actually implemented.  I often find this useful when documentation isn’t clear, and it’s a great way to improve your own code.

Coloured logcat output

Jeff Sharkey has written a great python script for colouring logcat output – colouredlogcat.py. This script simply colours lines from different programs in different colours, making logs more readable. I recommend putting this one on your PATH.

Sample output from colouredlogcat.py

Android Asset Studio

Don’t have an awesome in-house designer? Again Roman Nurik has your back with his Android Asset Studio, a set of web-based tools for generating image assets for your project. These are useful for prototyping but can generate production quality assets without launching Photoshop.

Themes

Roman Nurik’s Android themes won’t increase your productivity but they will make your browser more awesome! There’s a honeycomb theme and a traditional Android version.

WebView gradient backgrounds

April 5th, 2011

One of those easy questions shot up on Stack Overflow where a few people quickly jump in with an answer. How do you set a gradient background on a view?

Three answers later and the question poster refines his question: “What about a WebView?” While we all assumed the answer to be the same, WebViews ignore any background drawable used while a background colour is set. The default background colour for a WebView is white, so you need to make it transparent.

Simply specify 0 as your colour and add a drawable in code or via layout XML.

WebView webview = (WebView)findViewById(R.id.wv);
webview.setBackgroundColor(0);
webview.setBackgroundResource(R.drawable.gradient);

You can view the original discussion on Stack Overflow.

Easy command line scripts with Zend Application

February 25th, 2010

As PHP developers, it is convenient to be able to write command line scripts in PHP. In doing so, you will almost certainly want access to Zend Framework components and their configurations as if you are writing a normal MVC app, but without invoking the MVC stack and without loading unnecessary resources. I’ve seen solutions where actions are exposed as controller actions and called by wget – these are counter-intuitive, inefficient, and will suffer from max execution timeouts and other problems.

Zend_Applicaton to the rescue

Lets start with our website’s public/index.php – the script which sets up and launches an application. It looks roughly like this:

<?php
 
// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH',
              realpath(dirname(__FILE__) . '/../application'));
 
// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV',
              (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV')
                                         : 'production'));
 
require_once 'Zend/Application.php';
$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/configs/config.php'
);
 
$application->bootstrap()->run();

One feature of Zend Application is that you can choose to bootstrap only certain resources, rather than all of those referenced in your application config and bootstrap (_init methods.) The following assumes that our script needs to use the database, and send an email.

<?php
 
// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH',
              realpath(dirname(__FILE__) . '/../application'));
 
// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV',
              (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV')
                                         : 'production'));
 
require_once 'Zend/Application.php';
$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/configs/config.php'
);
 
//only load resources we need for script, in this case db and mail
$application->bootstrap(array('db', 'mail'));

Having bootstrapped the resources, we can retrieve them from the application as follows:

$db = $application->getBootstrap()->getResource('db');
 
//do something!
$row = $db->fetchRow('SELECT * FROM something');

Zend Framework Pitfalls Part 2 – Zend_Db Won’t Use the Query Cache with MySQL

November 28th, 2009

This one’s not limited to Zend Framework, but is actually a ‘problem’ in MySQL. I think it is worth covering, as the paragraph in the manual is easily missed.

From the MySQL manual:

Before MySQL 5.1.17, prepared statements do not use the query cache. Beginning with 5.1.17, prepared statements use the query cache under certain conditions, which differ depending on the preparation method

This means that if you’re running MySQL 5.0.x, not uncommon at the time of writing, your applications are not going to benefit from the query cache. There’s a simple workaround, however:

If you’re using Pdo, set the following driver option:

$pdoParams = array(
    PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true
);
 
$params = array(
    'host'           => '127.0.0.1',
    'username'       => 'webuser',
    'password'       => 'xxxxxxxx',
    'dbname'         => 'test',
    'driver_options' => $pdoParams
);

Zend_Config_Ini [parse_ini_file()] doesn’t support class constants, so ini users will have to supply the value of PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 1000, in their configs:

resources.db.adapter         = pdo_mysql
resources.db.params.host     = localhost
resources.db.params.username = webuser
resources.db.params.password = xxxxxxxx
resources.db.params.dbname   = myDb
resources.db.params.driver_options.1000 = true

Serving gzipped assets from Amazon S3 & Cloudfront

October 13th, 2009

One of the first steps in improving front-end performance is to migrate static assets to a content delivery network, such as Amazon’s CloudFront or Akamai. CloudFront is particularly attractive with its pay-as-you-go model, tiny upfront investment and ease of use.

Your existing web server may already be set up to compress JavaScript and CSS, potentially saving hundreds of kb on the wire. In uploading and testing your assets on CloudFront you’ll soon realise that it doesn’t perform any gzipping or compression. How to benefit from Amazon’s superfast edge locations and smaller file sizes?

When your browser requests a page, the headers sent might look like the following:

Host: www.davidcaunt.co.uk
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 3.5.30729) FirePHP/0.3
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.8,en-gb;q=0.5,en-us;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://www.davidcaunt.co.uk/about/

The header we’re interested in here is Accept-Encoding – this denotes whether the browser can cope with gzipped assets, and is used by Apache to decide whether to compress them. We can use this header in our PHP scripts to reference pre-compressed assets, and here’s how:

  1. Compress asset, e.g. home.css -> home.cssgz
  2. Upload both files, home.css and home.cssgz to S3 (CloudFront)
  3. Add PHP code to link to the compressed file if the browser accepts

You can easily compress assets on Linux using the following:

gzip home.css

In step 2, you’ll need to inform S3 that your assets are gzipped. S3 allows you to specify headers that will be sent with your file:

Content-Encoding: gzip

All good libraries and gui tools will help with this. It also makes sense to set Expires headers, if your assets are versioned.

Then the following PHP snippet should be all you need:

if (false !== strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')){
	$path = '/css/home.cssgz';
}else{
	$path = '/css/home.css';
}

You’ll want to integrate this code into your View Helpers (Zend Framework) or application code for generating asset URLs.

Note

You’ll notice I’ve named my file home.cssgz, not home.css.gz. I had problems with Safari PC (and probably Mac) refusing to use these files inline, and being disposed as attachments.


Zend Framework Pitfalls Part 1 – Zend_Auth

October 12th, 2009

Foreword

Zend Framework is excellent; this series of posts entitled ‘Zend Framework Pitfalls’ won’t try and dispute that. There are, however, one or two problems and poorly implemented components that can cause problems. Before using any library component it is important to be aware of any drawbacks and issues. It is then possible to make an objective decision before investing your time, and you can avoid banging your head against the desk understanding a known bug or problem that isn’t well documented.

Component

Zend_Auth

Priority

Minor (definition)

Problem

Zend_Auth is implemented as a singleton. This singleton references a single instance of Zend_Auth_Storage_Interface, used to persist an identity. This makes management of two or more authentication systems (e.g. frontend and admin) difficult. You must manually set the storage each time you want to query a different identity.

Solution 1 – Don’t use multiple authentication systems

In most simple web applications, you can use a single user database (table) to store both common users and administrators, and expose administrator privileges as appropriate via Zend_Acl or similar.

Solution 2 – Toggle storage

Zend_Auth has a method for changing storage, setStorage. Calling this method every time before retrieving the identity object is viable, but you have to remember to do so every time or you could read the wrong storage. This can be wrapped up for practicality:

class My_Auth extends Zend_Auth {
 
	public static function getInstance($storageNamespace = 'Zend_Auth'){
 
		// set namespace
		$this->setStorage(new Zend_Auth_Storage_Session($storageNamespace));
 
		return parent::getInstance();
	}
 
}

Remember to use this getInstance method every time you need to access your auth (and namespace) rather than storing a reference to the Zend_Auth instance.

Solution 3 – Your own implementation of Zend_Auth

Zend_Auth doesn’t actually do much heavy lifting. You could write something that can take advantage of the other Zend_Auth_* components, without implementing the singleton pattern. This is suggested in the reference manual.

Summary

It is unlikely that Zend_Auth will be re-architected for the 2.0 release of Zend Framework, the earliest opportunity for a break in backwards compatibility. Whether the singleton pattern is appropriate is debatable and a strongly advantageous alternative solution would be necessary to justify any changes.

As always, your comments and solution suggestions are welcomed.

Avoiding Firefox ‘screen jumping’ when scrollbars are displayed

September 15th, 2009

I recently discovered a simple way to improve the experience of Firefox users when navigating through a website. When a document is longer than the viewport, Firefox will display a vertical scrollbar, but when the document is shorter the scrollbar is not displayed. Constant toggling of the scrollbar is jarring to users and often gives the illusion that your pages are not consistently designed.

Fortunately there’s a fix which means the scrollbar is always displayed. Simply add this to your css:

html {
    overflow-y:scroll;
}

Top