Saturday, August 30, 2008

accessing @android:id in the java code

In the notepad v1 tutorial, you set up a list with two views in it - one with the id "@android:id/list" and one with "@android:id/empty".

These are special id's used under a ListActivity. The first defines the view to use for the list and the second the view to use when there is no data in the list.

I was wanting to obtain a handle to the list view to set the background image. I was unable to find how to access it given that the id is not defined in the autogenerated R.java. After a bit of hunting, I found that it is defined under android.R.id.list.

The code I used to set the image was:


View myView = findViewById(android.R.id.list);
myView.setBackgroundResource(R.drawable.icon);


A better way to do this however is to use the xml file to define the background image:


<ListView android:id="@android:id/list" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:background="@drawable/icon"></ListView>

setViewBinder - taking data and populating UI elements (eg a checkbox)

One of the first things that I wanted to try out was adding a checkbox to the simple notepad v1 application in the tutorial. The tutorial uses a SimpleCursorAdapter and then uses this in a call to setListAdapter to populate the screen with information from the database.

I added an extra checkbox to the notes_row as I wanted a checkbox to be displayed as well. Also, instead of using a LinearLayout, I used a RelativeLayout for each of the items in the list. The XML I used was as follow:


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView android:id="@+id/text1" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_alignParentTop="true"

android:layout_alignParentLeft="true">
</TextView>
<CheckBox android:id="@+id/CheckBox1" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="CheckBox"
android:layout_alignParentTop="true" android:layout_alignParentRight="true">
</CheckBox>
</RelativeLayout>


Note that I used this handy little droid draw tool to generate the XML layout.

Now, I was ready to go with taking the data from the database and populating the text and checkbox - the problem is, how do I convert the data in the database to a checkbox format?

The answer is by using setViewBinder. Here is the code that I used:


private void fillData() {
Cursor c = mdbHelper.fetchAllNotes();
startManagingCursor(c);

String[] from = new String[] { NotesDbAdapter.KEY_TITLE, NotesDbAdapter.KEY_CHECK };
int[] to = new int[] { R.id.text1, R.id.CheckBox1 };

// Now create an array adapter and set it to display using our row
SimpleCursorAdapter notes = new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to);

notes.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
int nCheckedIndex = cursor.getColumnIndexOrThrow(NotesDbAdapter.KEY_CHECK);
if (columnIndex == nCheckedIndex) {
CheckBox cb = (CheckBox) view;
boolean bChecked = (cursor.getInt(nCheckedIndex) != 0);
cb.setChecked(bChecked);
return true;
}
return false;
}
});
setListAdapter(notes);

}


As data is retrieved from the database, the adapter sets the value on the view. If it is setting the value for the checkbox (as indicated by the columnIndex), we simply obtain the checkbox, set its state and return true. If we return false, the adapter will use its normal method to populate the UI element.

@android:id vs @+id - some information found

After doing some reading through the documentation, I found a little more information regarding the use of @android:id. The relevant documentation indicates that @android:id/list and @android:id/empty are two special cases required for a ListActivity. So, perhaps @android:id refers to a predefined android identity - hence the reason why these ids are not inserted into the R.java file. @+id is used to indicate that the id should be placed into the R.java file. Not sure if this is the case, but it seems to work in my current mental model of the platform fits together, so until I find out otherwise, I will make this assumption.

As a side note, it appears that the documentation for ListActivity is slightly wrong - it specifies ListView id="android:list" and I think it should be ListView id="@android:list".

Friday, August 29, 2008

Why can't there be better checking at compile time!

I am glad that I found out about this little gotcha early on in the piece....

The issue has to do with the difference between @+id and @android:id. The documentation (and Notepad tutorial) don't really give much insight into the difference between the two. I still don't know the difference..

Anyway, when I was following the Notepad V1 tutorial, it gets to step 4 and suggest creating the following file:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">

<ListView android:id="@android:id/list"
android:layout_width="wrap_content"

android:layout_height="wrap_content"/>
<TextView android:id="@android:id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"

android:text="@string/no_notes"/>

</LinearLayout>



Notice the android:id="@android:id/list" part. Well, if you use the eclipse layout plugin and add a ListView and TextView using this tool, you don't get "@android:id/list", instead you get "@+id". Surely the two must be equivalent you would think. I happened to notice the difference at the time, but continued on, using the "@+id" format.

After completing the tutorial and getting to the part about running the program, my excitement about seeing my first android application deployed was soon crushed as I got an exception every time I went to deploy it. On I hunch, I change the convention to use the one suggested in the tutorial. To my amazement, it worked the next time I deployed it.

I posted this question on the developer forum and was pleased to get a quick response which I have added below courtesy of Romain Guy:

Hi,

@+id/foo means you are creating an id named foo in the namespace of
your application. You can refer to it using @id/foo. @android:id/foo
means you are referring to an id defined in the android namespace.
This namespace is the namespace of the framework. In this case, you
need to use @android:id/list and @android:id/empty because these are
the id the framework expects to find (the framework knows only about
the ids in the android namespace.)

The XML layout editor doesn't know how you will use your layout and
generates by default ids that are in your application namespace. So
the XML format is correct, it's not a compile time error, but really a
runtime error.

Getting Started....

Getting started with the android platform is very straightforward and went without a hitch really.

I like the fact that the team at Google are working with the eclipse platform. The documentation for the project is OK - it could be better in my opinion and concepts could be clarified with more examples or links to tutorials that explain the concepts. If all uses of an API had an associated example or tutorial, learning the API would be just that little bit easier. There is nothing worse than having low level details buried behind an esoteric black box that only the core development team knows about. Microsoft are the mastesrs of this - I hope Google don't go down this path! The tutorials are a good introduction and the concepts are fairly clear. I have been happy so far, but there have been some issues that I feel the team at Google could address - more of those in future posts.

Below are the low level details for setting up the android platform:

  • Download the Java SDK (Version 6 at time of writing)
  • Install this onto your system
  • Update your PATH variable to point to the bin directory:

    eg: PATH:=C:\Program Files\Java\jdk1.6.0_07\bin

  • Unzip the android SDK to Program Files. Add the tools directory to your PATH (see above).
  • Install eclipse and follow these instructions:

    1. Start Eclipse, then select Help > Software Updates...
    2. In the dialog that appears, click the Available Software tab.
    3. Click Add Site...
    4. Enter this as the Location:
      https://dl-ssl.google.com/android/eclipse/
      Click OK.
    5. Back in the Available Software view, you should see the plugin. Select the checkbox next to Developer Tools and click Install...
    6. On the subsequent Install window, "Android Developer Tools", and "Android Editors" should both be checked. The Android Editors feature is optional, but recommended. If you choose to install it, you need the WST plugin mentioned earlier in this page.
    7. Click Finish.
    8. Restart Eclipse.
Follow this and you should be good to go.