Mobile Computing Articles

Data I/O in iOS

I noticed a strange lack of high performance I/O routines in Objective-C. All I see is:

  • Bulk I/O. E.g, contentsAtPath of NSFileManager or writeToFile of NSString. These are memory intensive and impractical for complex data structure.
  • Very low level buffer based I/O from NSFileHandle. This is not good for reading NSString, int and float.

It appears that most people fall back on C routines like fwrite and fscanf for the job. I decided roll out a class that handled the task of reading and writing NSString, int, float etc. I wanted to borrow Java’s readUTF and writeUTF methods for NSString. In fact, my implementation should be compatible to Java’s.

The implementation below reads and writes data using binary files. The class can improve upon more error checking. The readUTF method can be optimized by recycling the malloced buffer.

FileUtil.h

#import <Foundation/Foundation.h>


@interface FileUtil : NSObject {
    FILE *mFile;
}

- (BOOL) openRead: (NSString*) file;
- (BOOL) openWrite: (NSString*) file;
- (BOOL) openAppend: (NSString*) file;
- (void) close;
- (NSString*) readUTF;
- (void) writeUTF: (NSString*) string;
- (int) readInt;
- (void) writeInt: (int) value;
- (float) readFloat;
- (void) writeFloat: (float) value;

@end

FileUtil.m

#import "FileUtil.h"


@implementation FileUtil

- (FileUtil*) init {
    [super init];
    
    mFile = NULL;
    
    return self;
}

- (BOOL) openRead: (NSString*) file {
    [self close];
    mFile = fopen([file fileSystemRepresentation], "rb");
    
    return mFile != NULL;
}

- (BOOL) openWrite: (NSString*) file {
    [self close];
    mFile = fopen([file fileSystemRepresentation], "wb");    
    
    return mFile != NULL;
}

- (BOOL) openAppend: (NSString*) file {
    [self close];
    mFile = fopen([file fileSystemRepresentation], "ab");
    
    return mFile != NULL;
}

- (void) close {
    if (mFile != NULL) {
        fclose(mFile);
        mFile = NULL;
    }
}

- (void)dealloc {
    [self close];
    [super dealloc];
}

- (NSString*) readUTF {
    int length = 0;
    fread(&length, 2, 1, mFile); //Java's writeUTF writes length in 2 bytes only
    
    char *buff = malloc(length + 1); //Extra byte for '\0'
    fread(buff, 1, length, mFile);
    buff[length] = '\0';
    
    NSString *string = [NSString stringWithUTF8String: buff];
    
    free(buff);
    
    return string;
}

- (void) writeUTF: (NSString*) string {
    const char *utf = [string UTF8String];
    int length = strlen(utf);

    fwrite(&length, 2, 1, mFile); //Java's writeUTF writes length in 2 bytes only
    fwrite(utf, 1, length, mFile); //Write UTF-8 bytes
}

- (int) readInt {
    int i;
    
    fread(&i, sizeof(int), 1, mFile);
    
    return i;
}

- (void) writeInt: (int) value {
    fwrite(&value, sizeof(int), 1, mFile);
}

- (float) readFloat {
    float f;
    
    fread(&f, sizeof(float), 1, mFile);
    
    return f;
}

- (void) writeFloat: (float) value {
    fwrite(&value, sizeof(float), 1, mFile);
}

@end

No Comments

Uninstalling XCode

I am getting ready to install XCode 4. First, I wanted to uninstall XCode 3.2. Here are the steps.

Open a terminal window.

Change to the root directory:

cd  /

Uninstall all of XCode:

sudo Developer/Library/uninstall-devtools –mode=all

sudo  Developer/Library/uninstall-devtools  –mode=all

It takes a while to uninstall everything. The uninstaller seems to leave behind the documentation files under /Developer/Platforms/iPhoneOS.platform folder.

No Comments

Understanding Memory Management in Objective-C

Mac OS X now has support for garbage collection. But that facility is not available in iOS yet. Only reference count based memory management is available. So, it pays to have a good feel for how memory is allocated and deallocated.

We will use a very simple program to learn the basics. The interface will remain unchanged throughout this article.

@interface Address : NSObject {
  NSString* street;
  NSString* city;
  NSString* zip;
}

- (Address*) initStreet: (NSString*) s city: (NSString*) c zip: (NSString*) z;
- (void) print;
@end

Our first implementation will be very basic.

@implementation Address

- (Address*) initStreet: (NSString*) s city: (NSString*) c zip: (NSString*) z {
  street = s;
  city = c;
  zip = z;
  
  return self;
}

- (void) print {
  NSLog(street);
  NSLog(city);
  NSLog(zip);
}
@end

Here, the the Address class does not take ownership of the various NSString objects sent to the initStreet method.

Let’s see a use of the class:

int main (int argc, const char * argv[]) {
  NSString *s = [[NSString alloc] initWithCString: "101 Flora"];
  NSString *c = [[NSString alloc] initWithCString: "Miami"];
  NSString *z = [[NSString alloc] initWithCString: "33139"];
  Address *a = [[Address alloc] initStreet:s city:c zip:z];

  [a print];

  return 0;
}

The code will work just fine. Except that there is mass scale memory leak. All four objects created in the main method will leak.

We can easily fix that by releasing the objects. A golden rule of memory management is that the owner of an object should free it. An entity that creates an object is the default owner of it.

int main (int argc, const char * argv[]) {
  NSString *s = [[NSString alloc] initWithCString: "101 Flora"];
  NSString *c = [[NSString alloc] initWithCString: "Miami"];
  NSString *z = [[NSString alloc] initWithCString: "33139"];
  Address *a = [[Address alloc] initStreet:s city:c zip:z];

  [a print];

  /* Free all objects */
  [a release];
  [s release];
  [ c release];
  [z release];

  return 0;
}

This is much better. Now we have stopped the memory leak.

The Address class still does not take ownership of the NSString objects. This can cause problem if an Address object needs to use the NSString objects after they are released. For example, the following is an error and will cause the program to crash.

int main (int argc, const char * argv[]) {
  NSString *s = [[NSString alloc] initWithCString: "101 Flora"];
  NSString *c = [[NSString alloc] initWithCString: "Miami"];
  NSString *z = [[NSString alloc] initWithCString: "33139"];
  Address *a = [[Address alloc] initStreet:s city:c zip:z];

  [a print];

  [s release];
  [ c release];
  [z release];

  /* Error. Will cause crash. */
  [a print];

  [a release];

  return 0;
}

Here we have a situation where an object must take ownership of other objects even though it did not create them in the first place. We will change the initStreet method to retain the NSString objects and there by taking ownership.

- (Address*) initStreet: (NSString*) s city: (NSString*) c zip: (NSString*) z {
  street = s;
  city = c;
  zip = z;
  
  /* Take ownership */
  [street retain];
  [city retain];
  [zip retain];
  
  return self;
}

Now, the program will not crash. You can safely call the print method after the main method has released the NSString objects.

There is one problem. The Address class does not release the NSString objects. Remember the golden rule. The owner of an object should release it. In this example, the NSString objects have two owners – the main method and the Address class. They should both release them. A good place to release these objects is from the destructor method – dealloc. Add this method to the implementation.

- (void) dealloc {
   
  [street release];
  [city release];
  [zip release];
  
  [super dealloc];
}

Now, we are all good. The code, in full form will look like this.

#import <Foundation/Foundation.h>

@interface Address : NSObject {
  NSString* street;
  NSString* city;
  NSString* zip;
}

- (Address*) initStreet: (NSString*) s city: (NSString*) c zip: (NSString*) z;
- (void) print;
@end

@implementation Address

- (Address*) initStreet: (NSString*) s city: (NSString*) c zip: (NSString*) z {
  street = s;
  city = c;
  zip = z;
  
  [street retain];
  [city retain];
  [zip retain];
  
  return self;
}

- (void) dealloc {
  puts("Dealloc called");
  
  [street release];
  [city release];
  [zip release];
  
  [super dealloc];
}

- (void) print {
  NSLog(street);
  NSLog(city);
  NSLog(zip);
}
@end

int main (int argc, const char * argv[]) {
  NSString *s = [[NSString alloc] initWithCString: "101 Flora"];
  NSString *c = [[NSString alloc] initWithCString: "Miami"];
  NSString *z = [[NSString alloc] initWithCString: "33139"];
  Address *a = [[Address alloc] initStreet:s city:c zip:z];
  [s release];
  [ c release];
  [z release];

  [a print];
  [a release];

  return 0;
}

No Comments

Decompile Android’s DEX File

Android uses a DEX archive in place of JAR. Also, the Java classes are compiled differently. To decompile the classes, you need to go through a few extra steps.

What Will You Need?

  1. Dex2Jar from http://code.google.com/p/dex2jar/
  2. A regular Java decompiler, such as JD from http://java.decompiler.free.fr.

Install these programs.

The Steps

First, extract the .apk file of the Android application.

jar  xvf  HelloWorld.apk

You will notice classes.dex file in the extracted folder.

Next, run dex2jar to convert the classes.dex file to a JAR file.

dex2jar.bat  classes.dex

This will produce an improbably named classes.dex.dex2jar.jar file.

Launch JD decompiler. Open the classes.dex.dex2jar.jar file and then view the .class files.

17 Comments

Get Started With HTML5 Webinar

The webinar today was a huge success. We had about 300 attendees. There were many excellent questions.

You can download the presentation and sample code from this link.

Links to useful resources:

  1. Modernizr library.
  2. How good is your browser’s HTML5 support?
  3. So many specs, where do they all come from?
  4. HTML5 Training.

No Comments

Long Running Work in Same Thread

By default, in Android, a single thread is used to run every application component, such as Activity and Service. If you perform a long running task from an event handler, messages to all other components will be delayed. Generally speaking, spawning a separate thread for long running work is recommended. At the same time, you do not always need the complication of a separate thread. In this article below, we will show you how to use the Handler framework to carry out a long work in small chunks using the solitary main thread of the application. You can even show a progress dialog to keep the user notified.

image

Basics of the Handler Framework

In Android, you can use an android.os.Handler object to post a message in the event queue of the thread where the handler is created. Keep in mind, all UI events are processed in the main thread of the application. If you create a handler in that thread then all messages for that handler will be mixed with the UI events in the queue.

The Handler class has many sendXXX() methods to queue a message. We will use the very basic sendEmptyMessage(int what) method.

When a message arrives for a Handler, the handleMessage(Message msg) method is called.

Getting Started

In your activity that will do the long running work, add these member variables.

ProgressDialog mProgressDialog;
int mProgressAmount = 0;

Create another member variable for the Handler.

final Handler mHandler = new Handler() {
	public void handleMessage(Message msg) {
		try {
			Log.v("Handler", "Progress: " + mProgressAmount);
			Thread.sleep(500);
		} catch (Exception e) {
		}
		mProgressAmount += 10;
		if (mProgressAmount < 100) {
			sendEmptyMessage(0);
		} else {
			mProgressDialog.dismiss();
		}
	}
};

The handleMessage method performs the long running operation in small chunks. Work is simulated here by the Thread.sleep() method. If further work is needed, we send another message for the handler. If work is done, we dismiss the progress dialog.

Finally, from the on click event handler of a button or some other event handler, we kick off the work.

public void onClick(View arg0) {
	mProgressAmount = 0;
	mProgressDialog = ProgressDialog.show(this, "", "Loading. Please wait...", true);

	mHandler.sendEmptyMessage(0);
}

Showing Progress Amount

image

We can easily use a horizontal progress bar. Change the way the progress bar dialog is created.

public void onClick(View arg0) {
	mProgressAmount = 0;
	
	mProgressDialog = new ProgressDialog(this);
	mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
	mProgressDialog.setMessage("Loading. Please wait...");
	mProgressDialog.show();
	
	mHandler.sendEmptyMessage(0);
}

In the handler, increment the progress amount.

mProgressAmount += 10;
mProgressDialog.incrementProgressBy(10);

Analysis

Here we see a simple technique to break up a long running work in small pieces and doing all the work in the main thread of the application. The progress bar dialog prevents any interaction with the activity while the work is in progress.

If, in the middle of the work, user clicks the back button, the progress dialog will be dismissed. But the work will continue. User is able to interact with the Activity at this point. This can lead to undesirable behavior. To prevent this from happening, make the progress dialog non-cancelable.

mProgressDialog.setCancelable(false);

No Comments

Custom Toast with Border

In Android, a Toast is a great way to show popup notification to users. It can be used by a background service, which otherwise has no visible user interface. By default, a toast simply shows a text message. In this tutorial, we will show you how to use a layout resource to display custom content. We will also show you how to provide a custom border to the view.

The tutorial assumes that you have a functional Eclipse based Android development system.

When done, the toast will look like this.

image

Create the Resources

We need three resource files.

  1. An image resource file. This image is shown in the left hand side of the toast.
  2. A shape resource file that will draw the rounded rectangle border around the toast.
  3. A layout resource file that defines the views for the toast.

First, create a small image file. Save it in the project as res/drawable/annie.png.

Next, in the res/drawable folder, create a new XML file called my_border.xml. Set the contents of the file as follows.

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"> 
    <stroke android:width="4dp" android:color="#FFFFFFFF" /> 
    <padding android:left="7dp" android:top="7dp" 
            android:right="7dp" android:bottom="7dp" /> 
    <corners android:radius="4dp" /> 
</shape>

Next, in the res/layout folder, create a new layout file called my_toast.xml. Set its content as follows.

<?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"
	android:background="@drawable/my_border">
<ImageView android:layout_width="wrap_content"
	android:layout_height="wrap_content" 
	android:src="@drawable/annie" />
<TextView android:layout_width="wrap_content"
	android:layout_height="wrap_content" 
	android:text="The image has been uploaded"
	android:layout_gravity="center_vertical" />
</LinearLayout>

Note, how the border shape is set for the root ViewGroup, the LinearLayout, using the background attribute.

Here is a screenshot of all three files.

image

Create and Show the Toast

The trick is to load the layout from the XML file and set the root view of the toast.

From an event handler of your activity, do the following.

Context context = getApplicationContext();
LayoutInflater inflater = getLayoutInflater();

View toastRoot = inflater.inflate(R.layout.my_toast, null);

Toast toast = new Toast(context);

toast.setView(toastRoot);
toast.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL,
		0, 0);
toast.show();

We are using a LayoutInflater to load the root view from the resource file. Then we are calling setView of the toast to set the root view.

8 Comments

Making Equal Width Buttons in Android

It is a common requirement to layout a bunch of buttons side by side. Making them of equal width is just plain good GUI design.

image

To achieve the effect above, first create a LinearLayout just for the buttons. The layout will contain three buttons.

<LinearLayout android:id="@+id/LinearLayout02" android:layout_height="wrap_content" 
  android:layout_width="fill_parent">
  <Button android:layout_height="wrap_content" android:text="Update" 
    android:layout_width="fill_parent" android:layout_weight="1"/>
  <Button android:layout_height="wrap_content" android:text="New" 
    android:layout_width="fill_parent" android:layout_weight="1"/>
  <Button android:layout_height="wrap_content" android:text="Delete" 
    android:layout_width="fill_parent" android:layout_weight="1"/>
</LinearLayout>

We took these steps to get the effect:

1. For the LinearLayout we set android:layout_width="fill_parent". This causes the layout view to take up the full width available from the device.

2. For each Button, we set android:layout_width="fill_parent" and android:layout_weight="1".

9 Comments

Android 2.x Programming Course Announced

As promised in an earlier blog post, we have just announced our first Android programming class.

WA1921 Enterprise Android Application Development

From the web page of the course:

Android is an open source platform for mobile computing. Applications are developed using familiar Java and Eclipse tools. Many vendors and carriers offer Android based devices (phones). Android is enjoying a healthy growth, in terms of hand set sells, applications available and new project starts. This course teaches students the architecture, API and techniques to create robust, high performance and appealing applications for the Android devices. While most courses from other vendors focus only on the mobile device, this course also deals with the server side architecture. This makes the class ideal for enterprise class businesses.

No Comments

Getting Started With Android 2.2

I have often found that Google’s quick start guide for Android development lacks crucial details. Finally, I decided to do something about it. This tutorial should help an absolute new comer to Android programming.

Before you start, make sure that you have these installed:

  • JDK 6. Just JRE is not enough. You will need to install full JDK.
  • Eclipse Galileo

Install Android 2.2 Platform

Download android SDK 2.2 from this link. Unzip the ZIP file under C:\. This should create the C:\android-sdk-windows folder.

Add C:\android-sdk-windows to the PATH environment variable.

Log off and log back in for the change to PATH to take effect.

Now, we will download the Android 2.2 platform.

From the C:\android-sdk-windows\tools folder, run android.bat.

image

Select Settings on the left hand list.

Check the Force https checkbox as shown above.

image

Select Available Packages.

On the right hand side, select SDK Platform Android 2.2, API 8, revision 1 as shown above.

Click Install Selected to start installation.

image

Click Install.

image

When installation finishes, click on Close.

Install Eclipse Plugin

Make sure that you have added the SDK directory to PATH environment variable.

Launch Eclipse.

Select Help > Install New Software.

Click the Add button to add a new site.

image

Add the https://dl-ssl.google.com/android/eclipse/ URL as the new site. Click OK.

image

Expand Developer Tools and check Android Development Tools.

Click Next.

image

Click Finish.

image

Click OK.

image

Click Yes to restart Eclipse.

Create a Virtual Device

An Android Virtual Device (AVD) is a device (phone) emulator. You will use it to test and debug applications.

From Eclipse menubar, select Window > Preferences.

image

Select Android.

Click Browse button and select the directory where the SDK was installed (C:\android-sdk_r06-windows in our case).

Click OK.

From menubar, select Window > Android SDK and AVD Manager.

Select Virtual Devices on the left.

Click New.

image

Enter my_avd as the name. Select Android 2.2 as the target.

Click Create AVD.

Close the AVD manager.

Write a Simple Application

We will now develop a basic application to test our development environment.

in Eclipse, select File > New > Project from the menubar.

image

Expand Android and select Android Project.

Enter the values as shown below.

image

Click Finish.

Expand the HelloWorld project and then src > com.webage.hello.

image

Open HelloActivity.java.

Change the onCreate method as follows.

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    TextView tv = new TextView(this);
    tv.setText("Hello World!");
    setContentView(tv);
}

Organize imports (Control+Shift+O).

Save changes.

Test the Application

While the editor for HelloActivity.java is active, from the menubar, select Run > Run.

image

Select Android Application. Then click OK.

System will start the Android Virtual Device. This can take up to 5 minutes. While the device is booting, the screen will look like this.

image

Then, you will see the home screen.

image

Finally, the application will be started.

image

To exit the application, click the home button.

image

Congratulations, you have successfully installed the Android development environment and tested your first Android application.

3 Comments