Tuesday, December 22, 2009

Drawing from a thread

Like the swing implementation, android must only write to the UI if it is on the UI thread.

The recommended way to do this is using the AsyncTask. More information about this can be found here.

Sunday, December 20, 2009

JUnit

One of the first things that I needed to do was run unit tests on the android phone.

The application of choice is obviously Junit, but, you need a few tweaks as you will want to run it on the device and you will also most probably need to obtain resources and contexts.

The first thing to do is make sure that you create a Test project when you create your main application base. This will put all of the test cases that you write into it.

To create a test case, just right click on the class you want to test and create a JUnit test case.

Once the test case is created, you will want access to the resources in the project. Change the test case so that it does not inherit from the regular JUnit test case, instead, use this:


android.test.AndroidTestCase


Now you will be able to write code such as this in the test case:


Resources resources = getContext().getResources();
InputStream inputStream = resources.openRawResource(com.myapp.R.raw.infile);


There is something important to realize here. The context that you obtain is from the application - not the test case. I can't find any way to put test files in the test case project and then access them. There probably is a way, but for now, I am not sure. Instead, if I want to use test data, I will just put test files in the application folder until I find a better way.

To run the test, just right click and do run as android junit test.

One final point. Sometimes the tests don't run the first time you invoke them like this. To fix this, just run the tests again and it seems to pick it up.

Saturday, December 19, 2009

Debugging an application on the device

By far the best way to program for android is with a device. It is faster and easier to do.

To get to this point, there are a couple of things I needed to do.

The first was to get my device ready to host and debug and application. This guide:



  • On the device, go to the home screen, press MENU, select Applications > Development, then enable USB debugging.


  • Setup linux to detect the device. For myself, I added the following to /etc/udev/rules.d/51-android.rules:

    SUBSYSTEM=="usb", SYSFS{idVendor}=="0bb4", MODE="0666"


    Note (you might need to use SUBSYSTEM="udb_device" depending on what version of ubuntu you are using).
    And then:

    chmod a+r /etc/udev/rules.d/51-android.rules



  • execute adb devices. If this doesn't work, you might need to do the following:

    sudo su -
    adb kill-server
    adb start-server
    adb devices




Once you have done this, you should be able to run the application from eclipse.

NOTE: You must remember to enable debugging in the Android Mainfest. This is under the 'Application' tab of the manifest under eclipse.

NOTE: The above was all done with ubuntu 9.10 running eclipse 4.5.1.

Eclipse

I spent considerable time with a frustrating, intermittent problem. Under eclipse, things would hang. In fact, the weren't hanging, the UI was just not updating properly.

A google search didn't turn anything up. I clicked on the 'known issues' link on eclipse and was pleasantly surprised that there was a known issue. GTK and SWT dont play together nicely. To fix, just need export GDK_NATIVE_WINDOWS=true.

Starting up tinkering with andoird again

It has been a while, but I have decided to tinker with android once again now that I have flashy new android toy to play with.

The install process didn't go as smoothly as I would have liked. Firstly, when installing the eclipse ADT plugins, I was unable to access the https site. Switch to http worked (eventually).

Next, I went to have a look at what AVD (android virtual devices) I had access to using the android tool. There were none, so I went to see if I could update. I was unable to do so. Even checking the option to use http instead of https in the settings did not help.

Eventually I found a google group thread that discussed how to update the packages using the android tool:


android update sdk


The readme did point this out, but the web page for getting started did not.

Fingers crossed that this gets me a development environment.

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.