Pages

Monday, January 31, 2011

Custom XML Attributes for Custom Views

I found there's a lot of help in books and online for creating your own View.  However, one thing I found is not well explained, and that is how to configure my own views with my own XML attributes.  It's well known that you can put your own strings and dimensions and other values in your resource files.  But those are values across the application - what if you want to use a custom view in more than one place, giving it different parameters in each case?

Part of the reason for my difficulty is that the Android documentation assumes you know all the ins and outs of XML.  If, like me, you think of XML as just neater HTML, then you'll need to learn about XML Namespaces.

A Crash Course on XML Namespaces

Anyone can make up their own XML tags and attributes, which leads to the possibility of conflicting tag and attribute names. (In the case of Android, they've created dozens of built-in XML attributes, and now the use can create their own.  Who knows if you're going to accidentally reuse an attribute the Google folks have already used.)

The solution is the Namespace concept.  You simply add a prefix to each XML tag name.  We've all seen one example: you don't get far in Android development without learning that Google's prefix is "android" as in android.layout_width, android.text etc.

So how do we ensure that the prefix is unique?  That's where that mysterious "xmlns" attribute at the start of android resource files comes in.  To refresh your memory, it says this:

xmlns:android="http://schemas.android.com/apk/res/android"

The purpose is to link the prefix to a URL.  For instance, if I wanted to use the prefix, "tomato" I'd add the attribute:

xmlns:tomato="http://oksmartphone.blogspot.com"

This attribute doesn't have to go at the start of the file - the prefix will be usable in the tag with the xmlns attribute, and all those contained within.  So putting it in the outermost container, along with the android prefix, will ensure it applies to the entire file.  After that, If I want to have an attribute called, say, "depth", I could add it with the tomato prefix

<com.blogspot.oksmartphone.JasonView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        tomato:depth="10"/>


An important point to realise is that the value of this attribute just has to be a unique string - there doesn't have to be any file relating to your attributes at that web page.  In fact, it doesn't have to be a URL at all.  I could have used:

xmlns:tomato="http://www.totally-fake-site.com"
or
xmlns:tomato="blah blah blah I hope this is unique"

Using a URL just a custom that  ensures that the string is unique.



Accessing Custom Attributes

Accessing attributes from a View class isn't hard.  When a View is created as part of an XML layout file, the constructor passes an AttributeSet object to the constructor.

The AttributeSet has lots of methods for accessing attributes (such as getAttributeValue.)  Each one has parameters for "namespace" and "attribute."  Note that the "namespace" refers to the unique string from the xmlns attribute, not the prefix associated with it (from my first example, I'd use "http://oksmartphone.blogspot.com/" and not "tomato".  For the attribute, leave off the prefix.  Again using my above example, I'd call:

attrs.getAttributeIntValue("http://oksmartphone.blogspot.com/", "depth", 0);

Assuming I wanted the default value (if the attribute is missing) to be zero.


For a better explanation of XML namespaces, try W3 Schools' page: http://www.w3schools.com/xml/xml_namespaces.asp

Tuesday, January 11, 2011

When the emulator won't start

Last time I talked about the slow starting of the emulator, now here is the related issue of simply getting it to start at all.  It doesn't give any useful error messages (at least by default) so it can be difficult to know what has gone wrong, and when you should start thinking that it's not merely slow, it's stopped all together.

Here are a few things I've found will cause the emulator to fail to start:
No Internet connection
The emulator requires an Internet connection to start, and without one, it will never finish loading.  So if you have an Internet connection that needs to be manually connected, and you haven't bothered because your app doesn't require the Internet, you may be left wondering why it won't start.

No Sound
The emulator also needs sound (it is supposed to be a phone, after all.)  I've tried running the emulator on a Linux box with a wonky sound configuration that befuddles many programs, and I've found I can't get it to start without specifying the -no-audio option.

Aborted Launch
Another problem is caused by an aborted first launch of the emulator.  The first time it runs with a given virtual device (AVD) the emulator needs to construct the memory image for the device.  If the emulator gets shut down before this image is completed, the emulator will not be able to use the unfinished image, nor will it be able to pick up where it left off; it simply won't work.
That's unfortunate since (as mentioned in the last post) the emulator takes longer to load than one would expect.  So a likely scenario is that the user starts the emulator, waits, assumes something is wrong and shuts it down, thus guaranteeing it won't work.
If this has happened, delete the AVD and recreate it. (Use the AVD manager, or delete the directory from the .android/avd directory.)

And if none of this helps, try starting the emulator with one of the debug flags (such as -debug-init.)  Try, emulator -help-debug-tags for all the options.

Friday, January 7, 2011

Speeding up the emulator start-up

One concern I had on first trying the Android emulator was just how long it takes to start.  If, like me, you tend to use the fix-one-thing-try-it-out style of developing, the thought of taking several minutes every time may scare you away.


First, let me reassure you with a point that often isn't spelled-out in Android books and tutorials: You don't have to restart the emulator every time you want to try new code; you can just leave it on, and rely on the tools to place the new package in the already-running emulator.

Also, if you're just starting into Android development, and you're worried that your older, slower computer just can't keep up.  It may at least make you feel less inadequate to know that the Emulator takes a long time to start even on newer, faster equipment.

But if you really want to speed up start up, Android Tutorials a couple of ideas on how to speed it up, a little.