Monthly Archives: May 2010

Android Development – Using Custom Fonts

An Android device comes with 3 basic fonts – Droid Sans, Droid Sans Mono, and Droid Serif. These are sufficient for every day use, but for your custom apps you will most probably want to use your own font. This post will show you how you can do so.

First Steps

First step is to pick a font that you want to use. For this example, we’ll be using BPReplay, an OpenType font that I stumbled across here.

bpReplay

Hot looking font! In order to access our font easily, we need to bundle it with our application in a way that our code can subsequently load it. To do this, we create a Fonts folder in our assets directory and copy our font there.

fontsFolder

That’s it for the setup, now on to the code.

The Code

To access our custom font, we use the Typeface class in the Android SDK to create a typeface that Android can use, then set any display elements that need to use our custom font appropriately. To demonstrate, we’ll create two text views on our main screen, one using the default Android Sans font, and the other using our BPReplay font. The layout is below.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <TextView
        android:id="@+id/DefaultFontText"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:text="Here is some text." />
    <TextView
        android:id="@+id/CustomFontText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:text="Here is some text.">
        </TextView>
</LinearLayout>

The code to load and set the custom font is straight forward as well, and is shown below.

public class Main extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Typeface tf = Typeface.createFromAsset(getAssets(),
                "fonts/BPreplay.otf");
        TextView tv = (TextView) findViewById(R.id.CustomFontText);
        tv.setTypeface(tf);
    }
}

You can see on line 8 where we instantiate a new Typeface object from our font definition file. On lines 9 and 10, we set the text view to use our custom font. The result us shown below.

customFont1

Sure enough, we have a different font on the screen. Using another freeware font called Molot, our font goodness becomes even more apparent.

customFont2

Android Development – Bounce Animation

In this brief post I’ll go over how to implement a bare bones bounce animation on some hard-coded text in an Android app. To achieve this effect, we will be using both a translate animation class and a bounce interpolator class, both provided by the Android SDK.

[Edit:] Some readers wanted to see what this effect looked like, and I was thinking the same thing when I first published this. So below is a sample of what the effect looks.

The Setup

To demonstrate a simple bounce animation, we will capture any touch events and “bounce” some hard-coded text to the touched location with a horizontal offset of 100.

To start out, we’ll create our own View to work with, called BounceView. First we create a new Android application, and then add a new class file. We inherit from View, and prepare to override the below methods.

public class BounceView extends View {

    public BounceView(Context context) {
        super(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        super.onDraw(canvas);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        return super.onTouchEvent(event);
    }
}

The touch event is where we will capture the location where we will insert our bounce animation. The draw event is where we will actually draw our hard-coded text.

Capturing Touch Events

In the touch event, we will save off the touched coordinates for use in the draw event. Here, we will also reset our animation, and associate said animation with our custom view. Our touch event now looks like below.

float _currentX;
float _currentY;

@Override
public boolean onTouchEvent(MotionEvent event) {
    _currentX = event.getX();
    _currentY = event.getY();

    TranslateAnimation _tAnim = new TranslateAnimation(-100, 0, 0, 0);
    _tAnim.setInterpolator(new BounceInterpolator());
    _tAnim.setDuration(1000);

    startAnimation(_tAnim);
    invalidate();
    return true;
}

We have introduced two new class level variables to hold the coordinates. In the touch event, we create a new TranslateAnimation object, telling it to start our animation 100 pixels to the left of the starting location, with no vertical offset. We then set the animation interpolator to a new BounceInterpolator object, which will give us a bounce effect during the animation. Then, we set the duration of the entire animation to 1000 ms. Finally, we start the animation.

Drawing It

The draw event is very bare bones, and is shown below.

@Override
protected void onDraw(Canvas canvas) {
    if (_currentX > 0 && _currentY > 0) {
        Paint p = new Paint();
        p.setColor(Color.WHITE);
        p.setTextSize(20);

        canvas.drawText("hey there", _currentX, _currentY, p);
    }
}

Here we are simply instantiation a new Paint object, setting the color to white and the text size to 40, and then using that new brush to draw our hard-coded test on the canvas.

The Final Result

Unfortunately still shots don’t do the app justice, as the whole point is an animation; just don’t forget to change your call to setContentView in the main activity to use a new instance of our custom view that we defined above. The effect is that anywhere you click on your screen, our canned text of “hey there” appears 100 pixels to the left and slides over to where we clicked, bouncing into position.

Next Steps

The Android SDK provides a number of different animations that you can swap in for our TranslateAnimation, such as:

In addition to these, we have a handful of different interpolators that we can incorporate as well:

Finally, you can compose different animations and interpolators using the AnimationSet class. As you can see, there are lots of different ways you can animate your text (or pictures) in your Android apps.

Android Development – Database Management

In this post, I’ll go over bare bones database management in an Android application, demonstrating how to create a database and perform simple CRUD actions against this database. I’ll also wire up a very simple UI to test our CRUD functionality. Finally, I’ll show how to utilize the built-in database upgrade functionality.

The Database

Android ships with SQLite, an open-source and very lightweight database engine that is popular in a great many products. From their web site:

SQLite is a software library that implements a self-contained,serverless, zero-configuration, transactional SQL database engine. SQLite is the most widely deployed SQL database engine in the world. The source code for SQLite is in the public domain.

We will be creating a simple one table database for a fictional game that will track player history. Each row will represent a game, and will store whether the player won or lost, the time it took to finish the game, and what difficulty level the computer opponent was set to.

First Steps

We will extend SQLiteOpenHelper to help us talk to our database. Create a new Android project and add a new class file called DbHelper. Extend SQLiteOpenHelper, and let Eclipse add the methods that need to be overridden.

package com.personal.androidfun.databasetests;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase.CursorFactory;

public class DbHelper extends SQLiteOpenHelper {

    public DbHelper(Context context, String name, CursorFactory factory,
            int version) {
        super(context, name, factory, version);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // TODO Auto-generated method stub

    }

}

You can see that we have to implement two methods, onCreate and onUpgrade. To ensure that clients of this class don’t have to know all of the nitty gritty database details, we’ll change the constructor as below.

public DbHelper(Context context) {
    super(context, "games.db", null, 1);
}

The onCreate method is called whenever the database is first created. For our simple example, we will create the below schema.

schema

So our onCreate method will now look like the below.

@Override
public void onCreate(SQLiteDatabase db) {
    String sql = "create table Games " +
                 "(PlayerId integer primary key, " +
                 "Result integer, " +
                 "PlayTime integer, " +
                 "Difficulty integer); ";
    db.execSQL(sql);
}

We will ignore the onUpdate method for now and focus on getting our database created with simple CRUD. Now that our DbHelper class is created, we can move on to the CRUD operations.

The Data Layer

Add another class to our project called DataLayer. This class will be responsible for using our DbHelper to perform our desired CRUD functions. We will start with the “C” portion, record creation. Let’s add a new method called AddGame to our DataLayer, giving us a class that looks like below.

public class DataLayer {

    private DbHelper _dbHelper;

    public DataLayer(Context c) {
        _dbHelper = new DbHelper(c);
    }

    public void AddGame(int playerId, int result, int playTime, int difficulty) {
        SQLiteDatabase db = _dbHelper.getWritableDatabase();
        try {
            ContentValues values = new ContentValues();
            values.put("PlayerId", playerId);
            values.put("Result", result);
            values.put("PlayTime", playTime);
            values.put("Difficulty", difficulty);

            db.insert("Games", "", values);
        } finally {
            if (db != null)
                db.close();
        }
    }
}

The code is pretty straightforward. First you’ll notice our constructor, where we are instantiating our DbHelper class that we created above. The Context object will be passed in from our app. For the AddGame method, we are keeping this bare bones, so we just pass in the four values to be written out. We use our DbHelper class to bring back a writable version of our database. We then hydrate a ContentValues object which contains name-value pairs that will be written out to our database. Next, we call the insert method on the database object returned by our DbHelper. Finally, we clean up by closing the database after our insert.

Testing Harness

To test our fun, we’ll whip up a mangled UI that we’ll use to call the methods as we go. Add a button to the main layout, and add an event handler that will instantiate our DataLayer and add a new game. The simple layout is below.

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

<Button
    android:text="Add Record"
    android:id="@+id/AddRecord"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"></Button>
</LinearLayout>

And below is the code for the main screen.

package com.personal.androidfun.databasetests;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class main extends Activity implements OnClickListener {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Button b = (Button) findViewById(R.id.AddRecord);
        b.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        DataLayer d = new DataLayer(getBaseContext());
        d.AddGame(1, 2, 3, 4);
    }
}

Now you can run the app, press the button, and trust me that a record was written out! Yeah, I know, not very satisfactory.

Using sqlite3 With adb

There’s a better way to check out the status of our database than just trusting me. The Android SDK ships with sqlite3, a command line tool that you can use to issue queries against any database on your emulator. Additionally, the Android SDK has a tool called adb, or Android Debug Bridge, that allows you to essentially start a shell prompt on your emulator, as if it were a PC. We will be using both of these tools to first open our database and then verify that we our code is doing the right thing.

The first step is verifying that the Tools folder in the Android SDK is on your path so that we can launch the executable. The actual location may vary; mine is pictured below.

toolsFolder

Add this directory to your path and make sure your Android emulator is running. Then start a command prompt, type adb shell, and press enter.

adbShell

You now have a command shell on your emulator. You can issue standard *nix commands, such as ls and cd. To work with our newly created database, we have to find it. All databases on an Android device are created in /data/data/<your package name>/databases. In our case, we called our package com.personal.androidfun.databasetests, so we issue some cd commands to get to the right spot.

dbDir

So now we’ve used adb to open up a shell onto our emulator and navigate to where our newly created database is stored. Next we have to connect to it using sqlite3. To do this, type sqlite3 <database name>, where our database is called games.db.

dbConnected

And now we’re connected to our database. You can issue any valid SQL against your database, from CRUD to DDL. You can find full instructions on how to use the sqlite3 tool here.

The final step in this section is to verify that our application actually inserted a row into our database. The fact that the database exists verifies that our onCreate method actually created it. To verify our insertion, we issue a standard select statement, terminated by a semicolon.

insertVerification

There’s our simple row, with column values separated by pipes. So far, so good.

RUD…

We’ve taken care of the creation part of our CRUD requirement, now we need to take care of the rest. First, reading information. We need to add a method to our DataLayer class. For now, we will just select all records every time. We’ll create a small class to represent a row in the database, called GameResult.

package com.personal.androidfun.databasetests;

public class GameResult {
    public GameResult(int playerId, int result, int playTime, int difficulty) {
        PlayerId = playerId;
        Result = result;
        PlayTime = playTime;
        Difficulty = difficulty;
    }

    public int PlayerId;
    public int Result;
    public int PlayTime;
    public int Difficulty;
}

Next, we’ll update our DataLayer class to select all records from the table and hydrate a list of our new GameResult objects.

public ArrayList<GameResult> SelectGames() {
    SQLiteDatabase db = _dbHelper.getReadableDatabase();
    try {
        ArrayList<GameResult> results = new ArrayList<GameResult>();
        Cursor c = db.rawQuery("select * from Games", null);
        if (c.getCount() > 0) {
            c.moveToFirst();
            do {
                results.add(new GameResult(
                        c.getInt(c.getColumnIndex("PlayerId")),
                        c.getInt(c.getColumnIndex("Result")),
                        c.getInt(c.getColumnIndex("PlayTime")),
                        c.getInt(c.getColumnIndex("Difficulty"))));
            } while (c.moveToNext());
        }
        return results;
    } finally {
        if (db != null)
            db.close();
    }
}

We use the rawQuery method to do a simple select * from our table. We make sure we have records before we try to access our cursor. If we have records, we run through our cursor, hydrating a GameResult object for every row we find.

We’ll add another button to our layout, call it SelectRecords, and add some code to handle the selection. The updated layout looks like below.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <Button
        android:text="Add Record"
        android:id="@+id/AddRecord"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"></Button>
    <Button
        android:text="Select Records"
        android:id="@+id/SelectRecords"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"></Button>
</LinearLayout>

Finally, we augment our button handler in our main class to handle both adding and querying, and wire it up to listen to click events on our new button.

public class main extends Activity implements OnClickListener {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Button b = (Button) findViewById(R.id.AddRecord);
        b.setOnClickListener(this);
        b = (Button) findViewById(R.id.SelectRecords);
        b.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        Button b = (Button) v;
        DataLayer d = new DataLayer(getBaseContext());

        switch (b.getId()) {
        case R.id.AddRecord:
            d.AddGame(1, 2, 3, 4);
            break;
        case R.id.SelectRecords:
            ArrayList<GameResult> results = d.SelectGames();
            Toast t = Toast.makeText(getBaseContext(), "# records: "
                    + results.size(), 1000);
            t.show();
            break;
        }
    }
}

And now we have the R part of CRUD. Run the app, click the Select Records button, and we should have something like below.

selectionPiece

For the U and the D part of our CRUD goal, I’ll skip the layout snippets and just show the code.

For our update piece, we will update all PlayTime columns in our database to be a random number. We again go back to our DataLayer class and add a new method.

public int UpdateGames() {
    SQLiteDatabase db = _dbHelper.getWritableDatabase();
    try {
        Random r = new Random();
        ContentValues values = new ContentValues();
        values.put("PlayTime", r.nextInt());

        int affected = db.update("Games", values, null, null);

        return affected;
    } finally {
        if (db != null)
            db.close();
    }
}

Notice that to perform an update we use the now-familiar ContentValues object, populating it only with the key-value pairs that we want to update.

And below is our new onClick handler in our main class (don’t forget to wire up the new Update button to the handler).

@Override
public void onClick(View v) {
    Toast t = null;

    Button b = (Button) v;
    DataLayer d = new DataLayer(getBaseContext());

    switch (b.getId()) {
    case R.id.AddRecord:
        d.AddGame(1, 2, 3, 4);
        break;
    case R.id.SelectRecords:
        ArrayList<GameResult> results = d.SelectGames();
        t = Toast.makeText(getBaseContext(),
                "# records: " + results.size(), 1000);
        t.show();
        break;
    case R.id.UpdateRecords:
        int affected = d.UpdateGames();
        t = Toast.makeText(getBaseContext(), "records affected: "
                + affected, 1000);
        t.show();
    }
}

And now we have the U part of our CRUD goal. To verify that our update ran successfully, switch back to our adb session and re-run our select statement.

updateVerification

We’re almost there. Now for the delete part, and fixing our schema so we can add more than one row for a player. Again, we go back to our DataLayer class and add a new method to handle deletes.

public int DeleteGames() {
    SQLiteDatabase db = _dbHelper.getWritableDatabase();
    try {
        int recordsDeleted = db.delete("Games", "1", null);
        return recordsDeleted;
    } finally {
        if (db != null)
            db.close();
    }
}

Note here that we are passing a “1” as the where clause to our delete. This tells the method to both delete everything and to return the number of rows that were deleted.

Then we add a new button to fire our Delete method, augment the onClick handler to call our new method on the DataLayer class, and wire up the new button to our handler. I’ll only show the augmented onClick handler below.

@Override
public void onClick(View v) {
    Toast t = null;

    Button b = (Button) v;
    DataLayer d = new DataLayer(getBaseContext());

    switch (b.getId()) {
    case R.id.AddRecord:
        d.AddGame(1, 2, 3, 4);
        break;
    case R.id.SelectRecords:
        ArrayList<GameResult> results = d.SelectGames();
        t = Toast.makeText(getBaseContext(),
                "# records: " + results.size(), 1000);
        t.show();
        break;
    case R.id.UpdateRecords:
        int affected = d.UpdateGames();
        t = Toast.makeText(getBaseContext(), "records affected: "
                + affected, 1000);
        t.show();
        break;
    case R.id.DeleteRecords:
        int deleted = d.DeleteGames();
        t = Toast.makeText(getBaseContext(), "records deleted: "
                + deleted, 1000);
        t.show();
        break;
    }
}

And that’s it – we’ve created a database and implemented very bare bones CRUD against it. But what about that hokey primary key?

Updating the Database Version

You’ll notice that our initial database version had PlayerId as the primary key. What this tells us is that we can only ever have one row per player in our database, which obviously goes against our goal of storing a row for every game every player ever finishes. We are going to use the onUpgrade method that we left unimplemented at the beginning to auto-upgrade our database.

For this we need to go back to the DbHelper class that we started with, which we review again below.

public class DbHelper extends SQLiteOpenHelper {

    public DbHelper(Context context) {
        super(context, "games.db", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String sql = "create table Games " + "(PlayerId integer primary key, "
                + "Result integer, " + "PlayTime integer, "
                + "Difficulty integer); ";
        db.execSQL(sql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // do nothing for now
    }
}
 

Upon reviewing the onUpgrade method, we see that we have two parameters specifying the old version of the database and the new version of the database. Our flawed database version started as version 1, as we can see in our constructor. We’ll decree our new database version to be version 2. To update our games database from version 1 to version 2, we will drop the existing table and create a new one that adheres to the below diagram.

newSchema

Our onUpgrade method will look like below.

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    if (oldVersion == 1 && newVersion == 2) {
        String sql = "drop table Games;";
        db.execSQL(sql);
        sql = "create table Games " + "(Id integer primary key, "
                + "PlayerId integer, " + "Result integer, "
                + "PlayTime integer, " + "Difficulty integer); ";
        db.execSQL(sql);
    }
}

And we have to pass the new version to our base class constructor.

public DbHelper(Context context) {
    super(context, "games.db", null, 2);
}

Now whenever the new version of our app that uses our version 2 database runs on a device with a version 1 database, the onUpgrade method is called to update the database schema. Our onUpgrade code is destructive in that it drops the table and recreates it; you can implement this in a safer fashion to preserve your users’ data.

Next Steps

Our bare bones CRUD app has about 0 robustness built in, but it does demonstrate the absolute basics of Android database access. Improving on said robustness is beyond the scope of this article, and is something we might be seeing in the next few weeks.

IBatis.NET Tips & Tricks Part 4 – Nulls & Lists

In this part of our IBatis.NET series, we’ll go over how to handle null values declaratively. Also, we’ll review how to hydrate list types with your query results instead of having to define new classes. We build on the code from the prior parts of this series, so start there if you want to be fully up to speed. As in prior parts, we use the AdventureWorks database.

Null Values

IBatis.NET gives you the flexibility to replace null values in query results with another pre-defined value. It’s pretty straightforward. Take the SpecialOffers table from the AdventureWorks database.

specialOfferTable

Let’s say we want to hydrate a list from the SpecialOffer table, and that we want to have all nulls in the MaxQty column be set to a really big number, say 99999. Our select statement and map would look like below.

<resultMap id="GetSpecialOffersRM"
           class="SpecialOffer">
    <result property="Description" column="Description"/>
    <result property="MaxQuantity" column="MaxQty" nullValue="0"/>
</resultMap>

<select id="GetSpecialOffers"
        resultMap="GetSpecialOffersRM">
    select
    Description,
    MaxQty
    from
    Sales.SpecialOffer
</select>

The magic happens by virtue of the nullValue attribute on the MaxQuantity result element. As you can guess, we can tell IBatis.NET to replace null values in the given column with anything we want. The code to take advantage of this looks the same as any other map consumption.

[Test]
public void GetSpecialOffersTest()
{
    IList<SpecialOffer> offers = Mappers.AWMapper.QueryForList<SpecialOffer>
        ("GetSpecialOffers", null);
    Assert.That(offers, Has.None.With.Property("MaxQuantity").Null);
}

More complicated null handling can be effected using custom type handlers, which you can review in Part 2 of this series.

Lists

If all you want is a quick and dirty way to get some data (i.e. without having to write a lot of objects), then you can hydrate a Hashtable (or list of Hashtable objects) with the result of your query. Let’s assume that you want to pull a list of first and last names from the Contact table, along with the corresponding contact id. Our select statement and map would look like below.

<select id="GetContactHashtable"
        resultMap="GetContactHashtableRM">
    select
    *
    from
    Person.Contact
    order by
    Person.Contact.ContactID ASC
</select>

<resultMap id="GetContactHashtableRM"
           class="Hashtable">
    <result property="ContactID" column="ContactID" />
    <result property="FirstName" column="FirstName" />
    <result property="LastName" column="LastName" />
</resultMap>

Note how instead of specifying an object that we’ve created as the target in the class attribute, we’ve specified Hashtable as the target. This allows us to write code like the below.

[Test]
public void GetContactHashtableTest()
{
    IList results = Mappers.AWMapper.QueryForList("GetContactHashtable", null);

    Assert.That(results, Is.Not.Null);
    Assert.That(results.Count, Is.EqualTo(19972));
    Assert.That(((Hashtable)results[0])["ContactID"], Is.EqualTo(1));
    Assert.That(((Hashtable)results[0])["FirstName"], Is.EqualTo("Gustavo"));
}

Definitely a nice little bare bones approach to data access. It gets slightly better though. We can cut the result map entirely out of the equation and rely solely on the select statement.

<select id ="GetContactHashtable2"
        resultClass="Hashtable">
    select
    *
    from
    Person.Contact
    order by
    Person.Contact.ContactID ASC
</select>

And the code that calls this select statement is the same, save for the select statement id of course.

[Test]
public void GetContactHashtable2Test()
{
    IList results = Mappers.AWMapper.QueryForList("GetContactHashtable2", null);

    Assert.That(results, Is.Not.Null);
    Assert.That(results.Count, Is.EqualTo(19972));
    Assert.That(((Hashtable)results[0])["ContactID"], Is.EqualTo(1));
    Assert.That(((Hashtable)results[0])["FirstName"], Is.EqualTo("Gustavo"));
}

Next Steps

In the next part of this series, we’ll go over multiple results in one select statement. We will also go over sub maps and discriminators, and how you can use these to help make hydrating complex objects easier.

Android Development – Fun With Files And UI

Bare bones file manipulation on an Android device is stupid easy, as long as you know how to interact with files in Java and as long as you stay within your application’s designated space. The former, well, this post isn’t going to fill in the blanks. The latter is cake; just start with the guidelines below. Note that to get something slightly above trivial, I had to sprinkle some additional UI goodness throughout the sample app that takes us a bit far afield, so bear with it as we go.

The Goal

Let’s say that in our Android app we want to represent users by separate files. The files could contains user preferences for that specific user in some predefined format; for this post, we’ll just be writing out the time of user “creation” so we can focus on the file manipulation aspect of things.  Our convention will be “<username>.prefs” where <username> is the name of the selected user.

When our application spins up, it will look for a list of preference files and present the corresponding list of defined users in a spinner control so that the current user can be chosen. It will also allow the user to enter a new name, which will create a corresponding preferences file in the application’s file space. This will allow us to support multiple users in our app in a very bare bones way.

The App

Let’s start by creating a new Android app. Our first task will be to look in the application’s directory for any preference files, and if they are found, to present them in a spinner control for the user to select from. We’ll be calling our application FileTests, and our source file will be called the same. Let’s modify the main layout file, main.xml by adding a Spinner control inside of the LinearLayout that Eclipse gave us in our default layout. Find your main.xml layout file in the res –> layout node in the Package Explorer and double click it to bring up the file in the editor.

defaultLayout

Now double-click the LinearLayout node in the bottom right of the IDE, and then click the green plus sign that appears in the toolbar above the element list.

addingElement

This brings up a simple dialog where you can specify what UI element you want to add to your screen. Select Spinner and click OK.

pickSpinner

Your layout will now look as below.

spinnerAdded

Let’s go ahead and rename the spinner to something more indicative of what it does, such as UserList. Let’s also change the width to something a little less offensive for cases when our user list is empty. Our layout now looks as below.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />
    <Spinner
        android:id="@+id/UserList"
        android:layout_width="300sp"
        android:layout_height="wrap_content"></Spinner>
</LinearLayout>

Now we need to write the code that looks for files of type <username>.prefs in our application space to load into our spinner control. We will be using the fileList method, which returns a list of all the files in our application directory. The code is as below.

private void loadUsers() {
    String [] files = fileList();
    _users = new ArrayList<String>();
    for (String f : files) {
        _users.add(f);
    }
}

Pretty straightforward. Again, the only file access we have to worry about here is figuring out what files we have in our application directory. That method call is on line 2 of the listing above, the rest is just storing it in an ArrayList called _users that we are defining in our class. After we lace this into our onCreate method, our FileTests.java file looks like below.

public class FileTests extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        loadUsers();
    }

    private ArrayList<String> _users;

    private void loadUsers() {
        String [] files = fileList();
        _users = new ArrayList<String>();
        for (String f : files) {
            _users.add(f);
        }
    }
}

Since we haven’t defined any users yet, running our app does nothing.

Adding New Users

Bear with me here – it’s going to take a bit to get to the part where we actually need to write out a file to the file system. To add a new user in our bare bones app, we need to create a file of the right name in our application directory space. But first we need to let the user enter her name so that the right file can be created. To do this, we’ll add another LinearLayout above our current one which will contain and EditText element and a Button element. The user will then be able to enter her name in the EditText element and press the button to add herself to the list of users the app knows about.

To effect our desired layout (get it), we need to add two new LinearLayouts to our root LinearLayout. We’ll present the add new user functionality at the top of our screen, so we’ll shift our current spinner element into the second of our new LinearLayouts, and add an EditText and Button to the first of our new LinearLayouts.

Again, open up the main.xml layout file, double-click the root LinearLayout node in our Outline tab, and add two LinearLayouts.

newLinears

With the second LinearLayout selected, press the blue up arrow once to make it a sibling of the first LinearLayout that you added. Go ahead and select the TextView and delete it, as we don’t need it right now. Then select the Spinner control and click the down arrow three times to make it a child of the second LinearLayout in our screen. Finally, select the first child LinearLayout and add an EditText and a Button control to it.

newUserElementsAdded

Finally, we’ll set a width on our EditText element and our Button element so they don’t shift all willy-nilly based on the contained text, and we’ll rename our screen elements to better reflect their function. Our new layout finally looks like below.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <LinearLayout
        android:id="@+id/UserNameEntryLayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <EditText
            android:text=""
            android:id="@+id/UserNameEntry"
            android:layout_width="200sp"
            android:layout_height="wrap_content"></EditText>
        <Button
            android:text="Add"
            android:id="@+id/AddNewUser"
            android:layout_width="100sp"
            android:layout_height="wrap_content"></Button>
    </LinearLayout>
    <LinearLayout
        android:id="@+id/CurrentUserDisplay"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <Spinner
            android:id="@+id/UserList"
            android:layout_width="300sp"
            android:layout_height="wrap_content"></Spinner>
    </LinearLayout>
</LinearLayout>

Now for some code. Let’s start by adding a handler to our AddNewUser button. This handler will take the text from our EditText control and add it to our internal list of user names.

At this point you’ll notice that we actually didn’t bother binding our list of user names to our spinner control up above. Since we’re actually going to start dealing with users now, we’ll go ahead and write that code as well. First, the button handler to get our new user name.

private void setupButtonHandlers() {
    Button b = (Button) findViewById(R.id.addNewUser);
    b.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            TextView t = (TextView) findViewById(R.id.userNameEntry);
            String newUserName = t.getText().toString();
            if (newUserName.length() <= 0)
                return;
            // non-zero user name
            _users.add(newUserName);

            bindUsers();
        }
    });
}

Next, the method that binds our user name list to our spinner control.

private void bindUsers() {
    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
            android.R.layout.simple_spinner_item, _users);
    adapter
            .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    Spinner s = (Spinner) findViewById(R.id.userList);
    s.setAdapter(adapter);
}

So now when we run our app, we can add users to our list by entering their name and clicking the Add button. However, when we restart our app, it’s as if we didn’t add any new users during the last run. This is where we need to persist our new user preference files out to disk. Before that, let’s make our user experience a smidgen better by clearing out the EditText element when we click the Add button, preventing the user from adding a duplicate name, and selecting the newly added user from the list after the Add button is clicked.

The first tweak is easy; we just add the below line to the addNewUser click handler.

t.setText("");

The second tweak is also straightforward,  we just look for the entered user name in our list of user names, returning if we find it, adding it if we don’t. Our Add button handler looks like below now.

private void setupButtonHandlers() {
    Button b = (Button) findViewById(R.id.addNewUser);
    b.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            TextView t = (TextView) findViewById(R.id.userNameEntry);
            String newUserName = t.getText().toString();
            if (newUserName.length() <= 0)
                return;
            int pos = _users.indexOf(newUserName);
            if (pos == -1) {
                _users.add(newUserName);
                pos = _users.indexOf(newUserName);
            }
            t.setText("");
            bindUsers();
        }
    });
}

The third tweak builds on the second tweak. We’ll use the integer position of the found or newly added user name to simply select it in our Spinner control. This requires adding the below two lines to our Add button handler below the call to bindUsers.

Spinner s = (Spinner) findViewById(R.id.userList);
s.setSelection(pos);

Persisting Information

Finally we get to the next aspect of file handling in an Android app, creating files. So we’re still stuck with the issue where we can add users find while within the app, but restarting the app causes us to forget all the users we’ve added. We can fix this by adding a method that will create a file based on our convention above, namely <username>.prefs.

private void persistUser(String userName) {
    String filename = userName.concat(".prefs");
    FileOutputStream fos = null;
    try {
        fos = openFileOutput(filename, MODE_PRIVATE);
        PrintStream p = new PrintStream(fos);
        p.println(userName);
        p.println(System.currentTimeMillis());
        p.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } finally {
        if (fos != null)
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
    }
}

The call to openFileOutput is what creates our file, if it doesn’t already exist. If it does, it simply opens it up for output. You can see also that we are writing two pieces of information to our file, namely the user name and the current system time in milliseconds. We have standard exception handling and cleanup in the rest of the method. Now when we add users in our application, a corresponding file is persisted, allowing our application to remember what users we have added the next time we start up.

One more thing we have to do is modify our routine that loads our users from the file list. We need to splice out the file extension, which we do by splitting on the “.” in the file name.

private void loadUsers() {
    String[] files = fileList();
    _users = new ArrayList<String>();
    for (String f : files) {
        String[] parts = f.split("\\.");
        _users.add(parts[0]);
    }
}

Reading File Contents

The next thing we want to do is read the contents of the user file when a user is selected or added. To show the contents, we’ll add another LinearLayout element after our current two LinearLayouts, and add a TextView to display the actual contents.

contentsDisplay

Since we want the contents to be read when we select a user, we wire up an event handler to our Spinner’s item selected event.

private void setupSpinnerHandler() {
    Spinner s = (Spinner) findViewById(R.id.userList);
    s.setOnItemSelectedListener(new OnItemSelectedListener() {
        public void onItemSelected(AdapterView<?> arg0, View arg1,
                int arg2, long arg3) {
            TextView item = (TextView) arg1;
            loadUserFileContents(item.getText().toString());
        }
        public void onNothingSelected(AdapterView<?> arg0) {
        }
    });
}

And the meat of the file read is in loadUserFileContents, shown below.

private void loadUserFileContents(String userName) {
    String filename = userName.concat(".prefs");
    FileInputStream f = null;
    try {
        f = openFileInput(filename);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
        return;
    }

    StringBuilder contents = new StringBuilder();
    int buf = -1;
    do {
        try {
            buf = f.read();
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
        contents.append((char) buf);
    } while (buf != -1);

    TextView fileContents = (TextView) findViewById(R.id.userFileContents);
    fileContents.setText(contents.toString());
}

The magic happens on line 5 with the call to openFileInput. The rest is just standard file reading cruft.

Deleting Files

We’ll wrap up our fantastic app by demonstrating file deletion. We’ll add another LinearLayout and a button to delete the currently selected user along with his file.

deleteUserLayout

And the code is just as straightforward, we simply have to add the below to our setupButtonHandlers method.

b = (Button) findViewById(R.id.deleteUser);
b.setOnClickListener(new OnClickListener() {
    public void onClick(View v) {
        Spinner s = (Spinner) findViewById(R.id.userList);
        String userName = s.getSelectedItem().toString();
        if (userName == null) return;

        String fileToDelete = userName.concat(".prefs");
        deleteFile(fileToDelete);

        loadUsers();
        bindUsers();
        s.setSelection(0);
    }
});

Here the magic takes place on the call to deleteFile.

There is a lot more that could be done to make our app more intelligent, but we strayed off the beaten path enough as it was. We covered creating files, writing to files, reading from files, and deleting files. All of it was straightforward, and adds another weapon to your arsenal when it comes to handling persisting of user information.

Android Development – Debugging Your App

Coming from a Windows environment, specifically the .NET space, I’ve been used to a pretty easy and seamless debugging approach. If I’m working on some source code in the IDE and I want to debug it, I hook up some sort of executable aspect and press F5 and click things until I get to my breakpoint (let’s pretend I’m ignorant of unit tests, and concentrate on just getting a debugger to fire). So when I started dabbling with some Android development, you can imagine my surprise when pressing F9 did nothing (that sets a breakpoint in Visual Studio). You can further imagine my shock when pressing the Debug button in Eclipse ran my app but didn’t really let me, well, debug.

So here I am, all in a tizzy, unable to debug my android app, facing the proposition of having to do poor man’s debugging – namely, throwing up a message box at key points in the app to see what was going on. And then, I got a new perspective.

perspective Literally. And now I can debug my app.

The Trick

So one of the differences between Eclipse and Visual Studio is the concept of perspectives, defined as:

A perspective is a visual container for a set of views and editors (parts).  These parts exist wholly within the perspective and are not shared.  A perspective is also like a page within a book.  It exists within a window along with any number of other perspectives and, like a page within a book, only one perspective is visible at any time.

And this was all that I was missing when it came to debugging Android apps. Let’s say we want to do some code spelunking in the ApiDemos Android demo app. We fire up Eclipse and do all the proper importing and what not. We then click the Debug option to debug the app in the emulator.

debugOption

Our app fires up in the emulator in all of its glory. How, then, do we actually perform debug actions such as inspecting variable values and setting breakpoints? This is where the concept of Eclipse perspectives comes into play. Tucked away in the Window menu is a handy option called Open Perspective.

openPerspective

That’s right, there is a Debug option in that submenu. Clicking that reveals, well, a whole new perspective.

debugPerspective

As you can see, there’s a lot of window action going on here. Let’s stay focused on our initial goal, which is simple debugging and breakpoints. You’ll notice in the middle of the IDE I have the Link.java file open. Let’s say I want to study this example so I can see how it works. I scroll down to the onCreate method in this class and set a breakpoint by double-clicking in the left margin on the line I want to break on.

settingBreakpoint

And then I navigate to the Text –> Linkify menu option in the ApiDemos sample app.

breakpointReached

The green line in the Link.java file shows where our execution is currently stopped. The selected tab in the top right portion of the IDE named Variables shows us the current local variables. Finally, you can see lots of yummy messages in the LogCat window at the bottom right, as well as the Console window in the bottom left.

That’s it – bare bones debugging of an Android application. And all it took, at least for me, was a slight change in perspective.

Android Development – The Dreaded Dalvik Error

One of the best ways to learn when it comes to coding is to read source code. This especially applies when you’re dealing with a new language or a new platform. If you’re dealing with both a new language AND a new platform, well, you better be reading someone else’s source code (that works, of course).

When it comes to Android development, one of the best ways to start learning is to look at the APIDemos project that Google has graciously provided. This project, along with some other samples, can easily be installed following these instructions.

While trying to spin the APIDemos project up however, you might encounter an error that reads like the below.

theError

I’ve gotten this error twice now, after I first imported the APIDemos project into a clean workspace that had been made aware of the Android libraries. While I was pretty sure I hadn’t specified anything related to “Dalvik format” or some such, I was extremely saddened to see that the project had failed to convert to said format with error 1. Funny – every time I see this error I’m reminded fondly of Dr. Who and his battles with the Daleks.

200px-Dalek_2010_Redesign

Turns out after some googling, the error is related to two copies of the Android libraries ending up on the build path. To find the build path, you have to open up the project’s properties.

projectProperties

Click on the Java Build Path node and select the Libraries tab.

javaBuildPath

Sure enough, looks like there are two references to the Android library on my path. How this happened, well, let’s leave that to Dr. Who to figure out. To fix my issue, I select the android.jar entry and click Remove followed by OK. Follow this up by cleaning the project (since I’m still firmly in the ranks of Eclipse n00bs, I’m including a screenshot).

cleanProject

After all of this, your project will have been cleansed and you can resume source code spelunking. Let’s just hope the Daleks don’t return in the next episode.

Using LINQ to SQL with a Stored Procedure

In this post I’ll go over a very bare bones way to call a stored procedure using LINQ to SQL.

Scenario

So I was writing up a bare bones tool to send me the results of a handful of queries I wanted to run against our OnTime database. This tool would have at most three clients, would run every hour, and was certainly not mission critical. I didn’t really want to spin up SubSonic or IBatis.NET, and I certainly didn’t want to spend time learning EF just for this mini-project. Amazingly enough I’d gotten away without having to learn LINQ to SQL up to this point, but alas, it seemed like the time was right. It seemed like the right choice, since all I wanted to do was to call a stored procedure in a database and massage the results into some text I’d be emailing out every hour.

For our sample below, we’ll be using Visual Studio 2010 RC and the AdventureWorks database.

Generating the Model

While there a lot of pictures in the below steps, they are pretty straightforward and self-explanatory. What’s really powerful here is the options you’d have if you were after something more than a bare bones way of calling a stored procedure.

Right click on the project node in the Solution Explorer and add a new ADO.NET Entity Data Model.

addNewItem

Name the model AdventureWorks, for obvious reasons.

nameTheModel

Click Add.

dataModelWizard1

Ensure that “Generate from database” is selected and click Next.

dataModelWizard2

Set up a new connection to the AdventureWorks database (this will be dependent on your database so I’ll skip the steps). After you have your connection your dialog will look something similar to the below.

dataModelWizard3

And yes, my laptop is a cheapo, so I’m accepting donations. Email me for details! The next step brings up a list of all the objects in the target database that we can model. Since our goal is a bare bones, easy way of calling a stored procedure without a lot boilerplate code, we just need to select the ones we are interested in. For this example, we are going to call uspGetManagerEmployees.

dataModelWizard4

Leave the defaults selected for not and click Finish. Visual Studio will work its magic and add the needed references to your project to support the newly introduced entity data model. Your IDE will appear similar to the below.

freshEntityDataModel

We need to tell Visual Studio to generate code so that we can call our stored procedure in a bare bones way. To do this, select the Model Browser tab in the Solution Explorer.

modelBrowserSelection

Expand the Stored Procedures node and find the one we’re interested in, uspGetManagerEmployees.

sprocPreGen

Right click on the stored procedure and select Add Function Import.

addFunctionImport

As you can see, we have lots of options available to us when adding a function import. For now, we’ll keep most everything set to the default selections. Press the “Get Column Information” button to have Visual Studio go out to the database to determine what our stored procedure returns.

columnInformationRetrieved

Pretty nifty if you ask me. Even niftier is the button that’s now enabled, “Create New Complex Type.” Click that.

complexTypeCreated

So what we’ve basically done is tell Visual Studio create a new type based on the return columns of the stored procedure we want to call. Click OK. You’ll get taken back out to Visual Studio, but you’ll see now that the stored procedure we were working with has its mapping details filled in.

mappingDetails

Again, pretty nifty.

The Code

I saved the best for last in this one. To call our newly modeled stored procedure, we use the code below.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects;

namespace SimpleLINQtoSQLWithSproc
{
    class Program
    {
        static void Main(string[] args)
        {
            using (AdventureWorksEntities db = new AdventureWorksEntities())
            {
                ObjectResult<uspGetManagerEmployees_Result> result =
                    db.uspGetManagerEmployees(3);
            }
        }
    }
}

The result object will contain the rows returned from our stored procedure call – that simple. It’s even better than that though. Because of our prior modeling, we have full IntelliSense support on our results object.

resultIntelliSense

So if we wanted to produce a simple list of employees and who they report to, we modify our console app as below.

static void Main(string[] args)
{
    using (AdventureWorksEntities db = new AdventureWorksEntities())
    {
        ObjectResult<uspGetManagerEmployees_Result> result =
            db.uspGetManagerEmployees(3);

        foreach (var x in result)
        {
            Console.WriteLine(
                "{0} {1} reports to {2} {3}",
                x.FirstName,
                x.LastName,
                x.ManagerFirstName,
                x.ManagerLastName);
        }
    }

    Console.WriteLine("press any key...");
    Console.ReadLine();
}

And that’s it. We’ve modeled our stored procedure, which enables us to execute it and return a strongly-typed result set. This approach is even better when you realize you can throw the full power of LINQ at your result set. So for small apps that don’t need a full blown “architecture,” LINQ to SQL has become my data access tool of choice. Always remember your context when choosing the tool for the job.