<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>h6 - HatSix &#187; Android</title>
	<atom:link href="http://hat6.com/category/android/feed/" rel="self" type="application/rss+xml" />
	<link>http://hat6.com</link>
	<description>Hat6 Web Application Engineering</description>
	<lastBuildDate>Fri, 12 Mar 2010 17:13:32 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Android Resources + SQLite. &#124;&#124; Pick a number, any number.</title>
		<link>http://hat6.com/2010/01/01/android-resources-plus-sqlite/</link>
		<comments>http://hat6.com/2010/01/01/android-resources-plus-sqlite/#comments</comments>
		<pubDate>Sat, 02 Jan 2010 00:53:22 +0000</pubDate>
		<dc:creator>Dusty</dc:creator>
				<category><![CDATA[Android]]></category>

		<guid isPermaLink="false">http://hat6.com/?p=96</guid>
		<description><![CDATA[So, you have a nifty neat application that is storing data based on user input.  You allow the user to choose a resource (an icon, maybe a sound file) to be stored with that data record.  Everything is going great until you add new resources to your project.  Suddenly the icons are [...]]]></description>
			<content:encoded><![CDATA[<p>So, you have a nifty neat application that is storing data based on user input.  You allow the user to choose a resource (an icon, maybe a sound file) to be stored with that data record.  Everything is going great until you add new resources to your project.  Suddenly the icons are mixed up, no longer the icon originally chosen.  Welcome to the world of machine-generated code.</p>
<p>The solution is rather simple, just not presented anywhere in the Android docs.  We&#8217;ll create an Enum that associates the Resource IDs with our own local IDs.  This way, we can store the local IDs, so that the SDK can change the resource IDs as much as it wants. Full code for the enum is at the bottom.<br />
<span id="more-96"></span><br />
From now on, we retrieve resources with the Enum:</p>
<pre class="brush: java">
	    	 mIcon.setImageDrawable(getResources().getDrawable(ReminderResources.AUDIO_ICON.resourceId()));
</pre>
<p>Storing the ID in SQLite is also very simple, storing our ID instead of the generated one.</p>
<pre class="brush: java">
        initialValues.put(KEY_ICON, r.getIconID().localId());
</pre>
<p>Then, when we retrieve the ID from SQLite, we use the &#8216;get()&#8217; method to retrieve the Enum:</p>
<pre class="brush: java">
                    reminder.setIconID(ReminderResources.get(cursor.getInt(iconColumn)));
</pre>
<p>Full code for the Enum:</p>
<pre class="brush: java">

public enum ReminderResources {
	AUDIO_ICON 	(0, R.drawable.audioicon),
	FORM_ICON		(1, R.drawable.form),
	FINGER_ICON 	(2, R.drawable.finger),
	LAUNDRY_ICON	(3, R.drawable.laundry),
	TASK_ICON		(4, R.drawable.task),
	BELL   		(5, R.drawable.bell);

    private final int localId;   // in kilograms
    private final int resourceId; // in meters
    ReminderResources(int localId, int resourceId) {
        this.localId = localId;
        this.resourceId = resourceId;
    }
    public int localId()   { return localId; }
    public int resourceId(){ return resourceId;}

    private static final Map&lt;Integer,ReminderResources&gt; lookup
    	= new HashMap&lt;Integer,ReminderResources&gt;();

	static {
	    for(ReminderResources s : EnumSet.allOf(ReminderResources.class))
	         lookup.put(s.localId, s);
	}

    public static ReminderResources get(int code) {
        return lookup.get(code);
   }

}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://hat6.com/2010/01/01/android-resources-plus-sqlite/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Android DataServices &#8211; DB4O</title>
		<link>http://hat6.com/2009/12/05/android-dataservices-db4o/</link>
		<comments>http://hat6.com/2009/12/05/android-dataservices-db4o/#comments</comments>
		<pubDate>Sun, 06 Dec 2009 03:06:27 +0000</pubDate>
		<dc:creator>Dusty</dc:creator>
				<category><![CDATA[Android]]></category>

		<guid isPermaLink="false">http://hat6.com/?p=72</guid>
		<description><![CDATA[You&#8217;ve been through the Notepad example, and you&#8217;ve seen my enhancements in the previous post.  But what if you don&#8217;t want to have to worry about schema updates and figuring out how to store dates/images/whatever in SQLite?  What if you just want to store your objects without all of the SQL-hassle?
Enter Object Oriented Databases.
OODBs are [...]]]></description>
			<content:encoded><![CDATA[<p>You&#8217;ve been through the <a title="Android Notepad Tutorial" href="http://developer.android.com/guide/tutorials/notepad/index.html" target="_blank">Notepad</a> example, and you&#8217;ve seen my <a title="Android DataServices SQLite" href="http://hat6.com/2009/12/05/android-dataservices-sqlite/">enhancements</a> in the previous post.  But what if you don&#8217;t want to have to worry about schema updates and figuring out how to store dates/images/whatever in SQLite?  What if you just want to store your objects without all of the SQL-hassle?</p>
<p>Enter Object Oriented Databases.</p>
<p>OODBs are great for small and simple databases, letting you write the fun(ctional) code without the drag of SQL.  We&#8217;re not talking ORM or Hibernate, with cleverly-hidden SQL.  Just simple store(MyObject) and we&#8217;re done.</p>
<p>The source code is found in the same place as the DataServices and SQLite project:<a title="DataServices Example Source Code" href="http://svn.hat6.com/hat6public/DataServiceExample/trunk" target="_blank"></a><a title="Use CTRL + click or middle-click to open in a new tab" href="javascript:void(0);">http://svn.hat6.com/hat6public/DataServiceExample/trunk</a>.<br />
For all of this wonderful functionality, we&#8217;ll be using <a title="DB4O" href="http://www.db4o.com/" target="_blank">DB4O</a>.  They even have a <a title="DB4O Android" href="http://developer.db4o.com/Resources/view.aspx/Reference/Platform_Specific_Issues/Android" target="_blank">page dedicated to Android</a>, though the source they provide won&#8217;t build.<br />
<span id="more-72"></span><br />
The code matches the <a title="Android DataServices" href="http://hat6.com/2009/12/05/android-dataservices/" target="_blank">DataService</a> interface I provided earlier, so if you&#8217;ve read through the <a title="Android DataServices SQLite" href="http://hat6.com/2009/12/05/android-dataservices-sqlite/" target="_blank">SQLite post</a>, you should be able to scan this easily.  This file weighs in at just a hair over 200 lines, and a big chunk of that is Exception handling and Comments.  So, without further ado, I present to you a working DB4O Android Implementation:</p>
<pre class="brush: java">
package com.hat6.dataServiceExample.model;

import java.util.List;

import com.db4o.Db4o;
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.instrumentation.core.Db4oClassSource;

import android.content.Context;
import android.util.Log;

public class ReminderDB4OImpl implements IReminderDataService {

	//TAG for logging.
    private static final String TAG = &quot;ReminderDB4OImpl&quot;;
    /**
     * Static variables holding information about our database itself.
     * NAME and TABLE are now used to determine where the DB file lives in the filesystem
     * VERSION allows our app to know if it has to perform any upgrades
     * 		(Though right now, we aren&#039;t using it)
     */
    private static final String DATABASE_NAME = &quot;hatsixExamples&quot;;
    private static final String DATABASE_TABLE = &quot;remindersDS&quot;;
    private static final int    DATABASE_VERSION = 1;

	/**
	 * Context is needed when interacting with the DB
	 */
	private final Context mCtx;
    /**
     * The actual Database.
     */
	private static ObjectContainer _container = null;

    /**
     * Constructor - takes the context to allow the database to be
     * opened/created
     *
     * @param ctx the Context within which to work
     */
    public ReminderDB4OImpl(Context ctx) {
		mCtx = ctx;
		open();
		Db4oClassSource dbocs; //DB40 crashes if we don&#039;t force this to be compiled in.
	}

    /**
     * Open the database. If it cannot be opened, try to create a new
     * instance of the database. If it cannot be created, throw an exception to
     * signal the failure
     *
     * @return this (self reference, allowing this to be chained in an
     *         initialization call)
     */
    public IReminderDataService open() {
		long startTime = 0;
    	try {
    		if(_container == null){
    			startTime = System.currentTimeMillis();
    			_container = Db4o.openFile(configure(), db4oDBFullPath());
    		}
    	} catch (Exception e) {
        	Log.e(TAG, e.toString());
        	return null;
        }
    	Log.d(TAG, &quot;Database opened: &quot; + startTime);

        return this;
    }

    public void close() {
    	if(_container != null){
    		long startTime = System.currentTimeMillis();
    		_container.close();
    		Log.d(TAG, &quot;Database committed and closed: &quot; + startTime);
    		_container = null;
    	}
    }

    /**
     * Create a new reminder record.  We pass in a Reminder, rather than just
     * some text values like in the Notepad Example. If the reminder is
     * successfully created return the new rowId for that reminder, otherwise return
     * a -1 to indicate failure.
     *
     * @param r the Reminder we want saved.
     * @return rowId or -1 if failed
     */
    public long createReminder(Reminder r) {
        if (_container != null){
	        try {
	        	_container.store(r);
	        	_container.commit();
	        	Log.d(TAG, &quot;Created selected object: &quot; + r.getTitle());

			} catch (Exception e){
				Log.d(TAG, &quot;Reminder could not be created: &quot; + r.getTitle());
				long l = -1;
				return l;
			}
        }
    	return r.getId();
    }

    /**
     * Fetch all Reminders.  This will utilize SQLite&#039;s cursors and create an ArrayList
     * that is passed back to the caller.
     *
     * @return List of Reminders
     */
    public List&lt;Reminder&gt; fetchAllReminders(){
        List&lt;Reminder&gt; list = _container.query(new com.db4o.query.Predicate&lt;Reminder&gt;() {
			private static final long serialVersionUID = 1L;
			public boolean match(Reminder r) {
        		return true;
        	}
        });
    	return list;
    }
    /**
     * Fetch Individual Reminder.  We take the &#039;query by example&#039; approach, where we pass in
     * a Reminder.  DB40 truly allows us to do query by example, allowing us to search by
     * and piece of data.  We return the first result, if any.
     *
     * @param r Reminder with data set to the Reminder we want fetched.
     * @return Reminder that we were searching for, or null if not found.
     */
    public Reminder fetchReminder(Reminder r){
    	if (_container != null){
	        try {
	        	ObjectSet&lt;Reminder&gt; os = _container.queryByExample(r);
	        	return os.get(0);
			} catch (Exception e){
				Log.d(TAG, &quot;Reminder not found: &quot; + r.getTitle());
				return null;
			}
        }
    	return null;
    }
    /**
     * Update the reminder using the details provided. We pass in a
     * Reminder, create ContentValues from that Reminder, then update
     * the record based on rowID
     *
     * @param r the Reminder to update
     * @return true if the reminder was successfully updated, false otherwise
     */
    public boolean updateReminder(Reminder r) {
        if (_container != null){
	        try {
	        	_container.store(r);
	        	_container.commit();
	        	Log.d(TAG, &quot;Updated selected object: &quot; + r.getTitle());

			} catch (Exception e){
				Log.d(TAG, &quot;Reminder not found: &quot; + r.getTitle());
				return false;
			}
        }
    	return true;
    }

    /**
     * Delete the reminder.  Rather than passing in the rowID, we pass the entire
     * reminder.  Again, by passing objects, our app is significantly simplified.
     *
     * @param r the Reminder to be deleted.
     * @return true if deleted, false otherwise
     */
    public boolean deleteReminder(Reminder r) {
        if (_container != null){
	        try {
	        	_container.delete(r);
	        	_container.commit();
	        	Log.d(TAG, &quot;Deleted selected object: &quot; + r.getTitle());

			} catch (Exception e){
				Log.d(TAG, &quot;Reminder not found: &quot; + r.getTitle());
				return false;
			}
        }
    	return true;
    }

    /**
     * configure creates a new Configuration and sets some parameters, namely that
     * the &#039;title&#039; should be indexed, and that the DB file should not be locked
     * @return Configuration for the OODB
     */
	private static com.db4o.config.Configuration configure(){
		com.db4o.config.Configuration configuration = Db4o.newConfiguration();
    	configuration.objectClass(Reminder.class).objectField(&quot;title&quot;).indexed(true);
    	configuration.lockDatabaseFile(false);
    	return configuration;
    }

	/**
	 * db4oDBFullPath returns the path to the DB File in the Context&#039;s path.
	 * @return String for the Database.
	 * @throws Exception
	 */
	private String db4oDBFullPath() throws Exception {
		if (mCtx == null){
			throw new Exception(&quot;Db4o Module not initialized&quot;);
		}
		return mCtx.getDir(DATABASE_NAME, Context.MODE_PRIVATE) + &quot;/&quot;  + DATABASE_TABLE + &quot;.db4o&quot;;
	}

}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://hat6.com/2009/12/05/android-dataservices-db4o/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Android DataServices &#8211; SQLite</title>
		<link>http://hat6.com/2009/12/05/android-dataservices-sqlite/</link>
		<comments>http://hat6.com/2009/12/05/android-dataservices-sqlite/#comments</comments>
		<pubDate>Sun, 06 Dec 2009 02:20:20 +0000</pubDate>
		<dc:creator>Dusty</dc:creator>
				<category><![CDATA[Android]]></category>

		<guid isPermaLink="false">http://hat6.com/?p=69</guid>
		<description><![CDATA[You&#8217;ve made your way through the Android &#8216;Notepad&#8216; tutorial, but find yourself wanting more?  Maybe you want to deal with Typed Objects instead of all of these strings everywhere? While this code isn&#8217;t generic enough to paste into your app and use as-is, it is simple enough to adapt to your own typed objects.  Using [...]]]></description>
			<content:encoded><![CDATA[<p>You&#8217;ve made your way through the Android &#8216;<a title="Android Notepad Tutorial" href="http://developer.android.com/guide/tutorials/notepad/index.html" target="_blank">Notepad</a>&#8216; tutorial, but find yourself wanting more?  Maybe you want to deal with Typed Objects instead of all of these strings everywhere? While this code isn&#8217;t generic enough to paste into your app and use as-is, it is simple enough to adapt to your own typed objects.  Using the Interface described <a title="Android DataServices" href="http://hat6.com/2009/12/05/android-dataservices/" target="_blank">here</a> makes it super easy to change the way you are storing your data, without having to refactor your app itself (imagine a hybrid online/offline storage, or as we&#8217;ll see in the <a href="http://hat6.com/2009/12/05/android-dataservices-db4o/">next post</a>, an Object Oriented DataBase[OODB]).</p>
<p>If you&#8217;d like to follow along in eclipse, source code is found here: <a title="DataServices Example Source Code" href="http://svn.hat6.com/hat6public/DataServiceExample/trunk" target="_blank"><a title="Use CTRL + click or middle-click to open in a new tab" href="javascript:void(0);">http://svn.hat6.com/hat6public/DataServiceExample/trunk</a></a>.<br />
<span id="more-69"></span><br />
We&#8217;re only looking at one file here, ReminderSQLiteImpl.java. I&#8217;ve tried to make certain that the comments explain everything, so I&#8217;m just dumping the code below.  This class comes in at about twice the size of the Notebook&#8217;s DBAdapter class, but most of that comes from my class storing more columns of data.</p>
<pre class="brush: java">
/**... imports removed ...**/
public class ReminderSQLiteImpl implements IReminderDataService {
	/**
	 * Static variables describing our schema.  We use these variables so that we can refer to the
	 * constants instead of having to worry about refactoring when our schema changes.
	 */
	public static final String KEY_ROWID = &quot;_id&quot;;
    public static final String KEY_TITLE = &quot;title&quot;;
    public static final String KEY_ICON = &quot;icon&quot;;
    public static final String KEY_STARTDATE = &quot;startDate&quot;;
    public static final String KEY_ENDDATE = &quot;endDate&quot;;
    public static final String KEY_MODIFIED = &quot;modified&quot;;
    //TAG for logging.
    private static final String TAG = &quot;ReminderSQLiteImpl&quot;;
    /**
     * Static variables holding information about our database itself.
     * NAME and TABLE are self explanatory.
     * VERSION allows our app to know if it has to perform any upgrades (right now it&#039;s
     * 		simply dropping the entire table and all associated data).
     * CREATE allows us to specify the SQL needed to create our DB.
     */
    private static final String DATABASE_NAME = &quot;hatsixExamples&quot;;
    private static final String DATABASE_TABLE = &quot;remindersDS&quot;;
    private static final int    DATABASE_VERSION = 1;
    private static final String DATABASE_CREATE =
        &quot;create table &quot; + DATABASE_TABLE + &quot; (&quot; + KEY_ROWID + &quot; INTEGER primary key autoincrement, &quot;
                + KEY_TITLE + &quot; TEXT not null, &quot;
                + KEY_STARTDATE + &quot; TEXT, &quot;
                + KEY_ENDDATE + &quot; TEXT, &quot;
                + KEY_MODIFIED + &quot; DATE not null&quot;
                + &quot;);&quot;;

	/**
	 * Context is needed when interacting with the DB
	 */
	private final Context mCtx;
	/**
	 * DatabaseHelper is a private class, defined at the end of this file.
	 */
    private DatabaseHelper mDbHelper;
    /**
     * The actual Database.
     */
    private SQLiteDatabase mDb;

    /**
     * Constructor - takes the context to allow the database to be
     * opened/created
     *
     * @param ctx the Context within which to work
     */
    public ReminderSQLiteImpl(Context ctx) {
		mCtx = ctx;
		open();
	}

    /**
     * Open the database. If it cannot be opened, try to create a new
     * instance of the database. If it cannot be created, throw an exception to
     * signal the failure
     *
     * @return this (self reference, allowing this to be chained in an
     *         initialization call)
     * @throws SQLException if the database could be neither opened or created
     */
    public ReminderSQLiteImpl open() throws SQLException {
        mDbHelper = new DatabaseHelper(mCtx);
        mDb = mDbHelper.getWritableDatabase();
        return this;
    }

    public void close() {
        mDbHelper.close();
    }

    /**
     * Create a new reminder record.  We pass in a Reminder, rather than just
     * some text values like in the Notepad Example. If the reminder is
     * successfully created return the new rowId for that reminder, otherwise return
     * a -1 to indicate failure.
     *
     * @param r the Reminder we want saved.
     * @return rowId or -1 if failed
     */
    public long createReminder(Reminder r) {
        ContentValues initialValues = new ContentValues();
        initialValues.put(KEY_TITLE, r.getTitle());
        initialValues.put(KEY_STARTDATE, r.getStart());
        initialValues.put(KEY_ENDDATE, r.getEnd());
        initialValues.put(KEY_MODIFIED,convertDateToString(new Date()));

        return mDb.insert(DATABASE_TABLE, null, initialValues);
    }

    /**
     * Fetch all Reminders.  This will utilize SQLite&#039;s cursors and create an ArrayList
     * that is passed back to the caller.
     *
     * @return List of Reminders
     */
    public List&lt;Reminder&gt; fetchAllReminders(){
    	Cursor cursor = fetchAllRemindersCursor();
        int idColumn = cursor.getColumnIndex(KEY_ROWID);
        int titleColumn = cursor.getColumnIndex(KEY_TITLE);
        int startColumn = cursor.getColumnIndex(KEY_STARTDATE);
        int endColumn = cursor.getColumnIndex(KEY_ENDDATE);

        List&lt;Reminder&gt; list = new ArrayList&lt;Reminder&gt;();
    	if(cursor != null){
            if(cursor.moveToFirst()){

                int count = cursor.getCount();
                Log.d(&quot;ReminderSqliteImpl&quot;, &quot;there are &quot; + count + &quot; records.&quot;);

                for(int i=0; i&lt;count; i++){
                    Reminder reminder = new Reminder();
                    reminder.setId(cursor.getLong(idColumn));
                    reminder.setTitle(cursor.getString(titleColumn));
                    reminder.setStart(cursor.getString(startColumn));
                    reminder.setEnd(cursor.getString(endColumn));

                    list.add(reminder);

                    cursor.moveToNext();
                }
            }
        }
    	return list;
    }
    /**
     * Fetch Individual Reminder.  We take the &#039;query by example&#039; approach, where we pass in
     * a Reminder.  This would allow us to query by Title if id wasn&#039;t set.
     *
     * @param r Reminder with id set to the Reminder we want fetched.
     * @return Reminder that was passed in, with data filled out from query.
     */
    public Reminder fetchReminder(Reminder r){
    	Cursor cursor = fetchReminderCursor(r.getId());
        int idColumn = cursor.getColumnIndex(KEY_ROWID);
        int titleColumn = cursor.getColumnIndex(KEY_TITLE);
        int startColumn = cursor.getColumnIndex(KEY_STARTDATE);
        int endColumn = cursor.getColumnIndex(KEY_ENDDATE);
    	if(cursor != null){
            r.setId(cursor.getLong(idColumn));
            r.setTitle(cursor.getString(titleColumn));
            r.setStart(cursor.getString(startColumn));
            r.setEnd(cursor.getString(endColumn));
    	}
    	return r;
    }
    /**
     * Update the reminder using the details provided. We pass in a
     * Reminder, create ContentValues from that Reminder, then update
     * the record based on rowID
     *
     * @param r the Reminder to update
     * @return true if the reminder was successfully updated, false otherwise
     */
    public boolean updateReminder(Reminder r) {
        ContentValues args = new ContentValues();
        args.put(KEY_TITLE, r.getTitle());
        args.put(KEY_STARTDATE, r.getStart());
        args.put(KEY_ENDDATE, r.getEnd());
        args.put(KEY_MODIFIED,convertDateToString(new Date()));

        return mDb.update(DATABASE_TABLE, args, KEY_ROWID + &quot;=&quot; + r.getId(), null) &gt; 0;
    }

    /**
     * Delete the reminder.  Rather than passing in the rowID, we pass the entire
     * reminder.  Again, by passing objects, our app is significantly simplified.
     *
     * @param r the Reminder to be deleted.
     * @return true if deleted, false otherwise
     */
    public boolean deleteReminder(Reminder r) {

        return mDb.delete(DATABASE_TABLE, KEY_ROWID + &quot;=&quot; + r.getId(), null) &gt; 0;
    }

    /**
     * Return a Cursor over the list of all reminders in the database.
     * This is more of a convenience function, as we don&#039;t allow outside
     * classes to use it anymore
     *
     * @return Cursor over all reminder
     */
    private Cursor fetchAllRemindersCursor() {

        return mDb.query(DATABASE_TABLE, new String[] {
        			KEY_ROWID,
        			KEY_TITLE,
        			KEY_STARTDATE,
        			KEY_ENDDATE,
        			KEY_MODIFIED
        			}, null, null, null, null, null);
    }

    /**
     * Return a Cursor positioned at the reminder that matches the given rowId
     * Again, a convenience function, as we don&#039;t allow outside classes ot use it
     *
     * @param rowId id of reminder to retrieve
     * @return Cursor positioned to matching reminder, if found
     * @throws SQLException if reminder could not be found/retrieved
     */
    private Cursor fetchReminderCursor(long rowId) throws SQLException {

        Cursor mCursor =

                mDb.query(true, DATABASE_TABLE, new String[] {
            			KEY_ROWID,
            			KEY_TITLE,
            			KEY_STARTDATE,
            			KEY_ENDDATE,
            			KEY_MODIFIED
            			}, KEY_ROWID + &quot;=&quot; + rowId, null,
                        null, null, null, null);
        if (mCursor != null) {
            mCursor.moveToFirst();
        }
        return mCursor;

    }

    /**
     * convertStringToDate will take a Sqlite String and convert it to a date
     * @param s String to convert to Date
     * @return Date object
     */
	private Date convertStringToDate(String s){
		Date date = null;
		DateFormat iso8601Format = new SimpleDateFormat(&quot;yyyy-MM-dd HH:mm:ss&quot;);
		try {
			date = iso8601Format.parse(s);
		} catch (ParseException e) {
			Log.e(&quot;Reminder.convertStringToDate&quot;, &quot;Parsing ISO8601 datetime failed&quot;, e);
		}
		return date;
	}

	/**
	 * convertDateToString will take a Date object and return a SQLite date string
	 * @param date Date
	 * @return String
	 */
	private String convertDateToString(Date date){
		long when = date.getTime();
		int flags = 0;
		flags |= android.text.format.DateUtils.FORMAT_SHOW_TIME;
		flags |= android.text.format.DateUtils.FORMAT_SHOW_DATE;
		flags |= android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
		flags |= android.text.format.DateUtils.FORMAT_SHOW_YEAR;

		String finalDateTime = android.text.format.DateUtils.formatDateTime(mCtx,
				when + TimeZone.getDefault().getOffset(when), flags);

		return finalDateTime;

	}

    /**
     * DatabaseHelper basically copied from Androids NotebookExample.
     * Here we short-circuit some functions to make our above code
     * more readable.
     */
    private static class DatabaseHelper extends SQLiteOpenHelper {

        DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL(DATABASE_CREATE);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            Log.w(TAG, &quot;Upgrading database from version &quot; + oldVersion + &quot; to &quot;
                    + newVersion + &quot;, which will destroy all old data&quot;);
            db.execSQL(&quot;DROP TABLE IF EXISTS &quot; + DATABASE_NAME);
            onCreate(db);
        }
    }

}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://hat6.com/2009/12/05/android-dataservices-sqlite/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Android DataServices</title>
		<link>http://hat6.com/2009/12/05/android-dataservices/</link>
		<comments>http://hat6.com/2009/12/05/android-dataservices/#comments</comments>
		<pubDate>Sun, 06 Dec 2009 01:34:31 +0000</pubDate>
		<dc:creator>Dusty</dc:creator>
				<category><![CDATA[Android]]></category>

		<guid isPermaLink="false">http://hat6.com/?p=71</guid>
		<description><![CDATA[So, you have an Android app, and you need to store your data.  The Android &#8216;Notepad&#8216; tutorial will show you the basics of SQLite, and I&#8217;ve modified their code quite a bit for my DataServices example project.  The one thing I don&#8217;t like about their example is that the app itself knows that the data [...]]]></description>
			<content:encoded><![CDATA[<p>So, you have an Android app, and you need to store your data.  The Android &#8216;<a title="Android Notepad Tutorial" href="http://developer.android.com/guide/tutorials/notepad/index.html" target="_blank">Notepad</a>&#8216; tutorial will show you the basics of SQLite, and I&#8217;ve modified their code quite a bit for my DataServices example project.  The one thing I don&#8217;t like about their example is that the app itself knows that the data is stored in SQLite.  While it is just an example project, I feel it&#8217;s setting a very bad example.  So I&#8217;ve created a bit of abstraction and added an interface so that the SQLite implementation can be swapped in and out for any other storage service.</p>
<p>Below we&#8217;ll examine the IReminderDataService interface, which provides some basic data storage functionality.  I&#8217;ve implemented two different storage mechanisms: visit <a href="http://hat6.com/2009/12/05/android-dataservices-sqlite/">SQLite</a> and <a href="http://hat6.com/2009/12/05/android-dataservices-db4o/">DB4O</a> posts for specifics.<br />
<span id="more-71"></span><br />
This interface is basic, a full-fledged interface would provide a bit more.  We have Create, Update, Delete and FetchAll functions.  You&#8217;ll notice that we&#8217;re still fully typed at this stage, ensuring that our App isn&#8217;t compromised by Casts or creating objects from a result row.  </p>
<pre class="brush: java">
package com.hat6.dataServiceExample.model;

import java.util.List;

public interface IReminderDataService {

	public abstract long createReminder(Reminder r);
	public abstract boolean updateReminder(Reminder r);
	public abstract boolean deleteReminder(Reminder r);
	public abstract List&lt;Reminder&gt; fetchAllReminders();

}
</pre>
<p>This makes our application very streamlined.  We simply instantiate an implementation, fetch all Reminders, then pass the ArrayList over to our ItemRenderers via the RenderedListAdapter (<a href="http://hat6.com/2009/11/22/introducing-android-to-the-concept-of-itemrenderers/">discussed here</a>). It isn&#8217;t as generic as a full-on ORM, but it&#8217;s very lightweight.</p>
<pre class="brush: java">
/*... imports removed ...*/
public class DataServiceExample1 extends ListActivity {
	private List&lt;Reminder&gt; reminders;

	/** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        IReminderDataService rds = new ReminderSQLiteImpl(this);
        //createReminders(rds);
        reminders = rds.fetchAllReminders();
        RenderedListAdapter rla = new RenderedListAdapter(this, reminders, ReminderListSimpletemRenderer.class);
        setListAdapter(rla);
    }
    private void createReminders(IReminderDataService rds){
        // Add four items
        Reminder r1 = new Reminder(
                &quot;Remember Once&quot;,&quot;today&quot;, &quot;tomorrow&quot;, getResources().getDrawable(R.drawable.finger) );
        Reminder r2 = new Reminder(
                &quot;Bell Reminder&quot;,&quot;today&quot;, &quot;tomorrow&quot;, getResources().getDrawable(R.drawable.bell));
        Reminder r3 = new Reminder(
                &quot;Laundry Reminder&quot;,&quot;today&quot;, &quot;tomorrow&quot;, getResources().getDrawable(R.drawable.laundry));
        Reminder r4 = new Reminder(
                &quot;Task Reminder&quot;,&quot;today&quot;, &quot;tomorrow&quot;, getResources().getDrawable(R.drawable.task));
    	rds.createReminder(r1);
    	rds.createReminder(r2);
    	rds.createReminder(r3);
    	rds.createReminder(r4);
    }
}
</pre>
<p>You can find the source code for the entire DataService project here: <a href="http://svn.hat6.com/hat6public/DataServiceExample/trunk">http://svn.hat6.com/hat6public/DataServiceExample/trunk</a></p>
]]></content:encoded>
			<wfw:commentRss>http://hat6.com/2009/12/05/android-dataservices/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Introducing Android to the concept of ItemRenderers</title>
		<link>http://hat6.com/2009/11/22/introducing-android-to-the-concept-of-itemrenderers/</link>
		<comments>http://hat6.com/2009/11/22/introducing-android-to-the-concept-of-itemrenderers/#comments</comments>
		<pubDate>Mon, 23 Nov 2009 03:03:48 +0000</pubDate>
		<dc:creator>Dusty</dc:creator>
				<category><![CDATA[Android]]></category>

		<guid isPermaLink="false">http://hat6.com/?p=37</guid>
		<description><![CDATA[Project With Source Now Posted, See: http://hat6.com/2009/11/27/itemrenderers-updated/
Coming from the Flex world, it&#8217;s strange not to see the idea of &#8220;ItemRenderers&#8221; in Android.  Customizing the way a List Item looks is much more manual than in Flex, so I&#8217;ve come up with a ListAdapter that allows for some of the flexibility/framework-ness that I enjoy in Flex.
I [...]]]></description>
			<content:encoded><![CDATA[<p><span style="color: #ff0000;"><em><strong>Project With Source Now Posted, See: <a title="Android ItemRenderers Updated" href="http://hat6.com/2009/11/27/itemrenderers-updated/" target="_self">http://hat6.com/2009/11/27/itemrenderers-updated/</a></strong></em></span></p>
<p>Coming from the Flex world, it&#8217;s strange not to see the idea of &#8220;ItemRenderers&#8221; in Android.  Customizing the way a List Item looks is much more manual than in Flex, so I&#8217;ve come up with a ListAdapter that allows for some of the flexibility/framework-ness that I enjoy in Flex.</p>
<p>I started from this <a title="ListActivity Customization" href="http://www.anddev.org/iconified_textlist_-_the_making_of-t97.html" target="_blank">tutorial</a> and modified it to be more Flex-esque.  I&#8217;ve tried to keep things as simple and generic as possible.  This is my first draft, so it&#8217;s pretty bare-bones, but it does what is needed initially.<br />
<span id="more-37"></span><br />
To have a List in an Android App, we extend the ListActivity class for a new Activity (I&#8217;m only focusing on Activities for now).  From this Activity, we declare and set an Adapter.  The <a title="ListView with ArrayAdapter" href="http://developer.android.com/guide/tutorials/views/hello-listview.html" target="_blank">sample code</a> shows using and ArrayAdapter, while <a title="ListView with SimpleCursorAdapter" href="http://www.anddev.org/queue_and_display_call_log_in_a_simple_list_names_only-t5338.html" target="_blank">this post</a> shows using a SimpleCursorAdapter.  Both of these examples show how to use layouts distributed with Android, but don&#8217;t allow much in the way of customization.  They&#8217;re poorly documented and searches for &#8220;simple_list_item_1&#8243; returns more questions than answers.</p>
<p>So I&#8217;ve written my own Adapter that allows you to pass a class to the adapter.  Simply implement IDataRenderer and provide the following constructor:  public MyDataRenderer(Context context)</p>
<p><strong>com.hatsix.ListRenderer.RenderedListAdapter.java:</strong></p>
<pre class="brush: java">
package com.hatsix.ListRenderer;

/*
*
* Copyright 2009 Dusty Jewett
*
* Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

public class RenderedListAdapter extends BaseAdapter {

/** Remember our context so we can use it when constructing views. */
private Context mContext;
private Class itemRenderer;

private List mItems;

public RenderedListAdapter(Context context, List items, Class renderer) {
mContext = context;
mItems = items;
itemRenderer = renderer;
}

public void setListItems(List list) { mItems = list; }

/** @return The number of items in the */
public int getCount() { return mItems.size(); }

public Object getItem(int position) { return mItems.get(position); }

public boolean areAllItemsSelectable() { return false; }

public boolean isSelectable(int position) {
/*
try{
return mItems.get(position).isSelectable();
}catch (IndexOutOfBoundsException aioobe){
//return super.isSelectable(position);
return false;
}
*/
return true;
}

/** Use the array index as a unique id. */
public long getItemId(int position) {
return position;
}

/** @param convertView The old view to overwrite, if one is passed
* @returns IDataRenderer View that has had it&#039;s data assigned to it */
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
try {
View idr;
Class[] rendArgsClass = new Class[] {Context.class};
Object[] rendArgs = new Object[] {mContext};
Constructor rendererConstructor = itemRenderer.getConstructor(rendArgsClass);
idr = (View) createObject(rendererConstructor, rendArgs);
if(idr instanceof IDataRenderer){
((IDataRenderer) idr).setData(mItems.get(position));
}

} catch (NoSuchMethodException e) {
e.printStackTrace();
}//(mContext, mItems.get(position));
}
return convertView;
}
public static Object createObject(Constructor constructor, Object[] arguments) {
Object object = null;
try {
object = constructor.newInstance(arguments);
System.out.println (&quot;Object: &quot; + object.toString());
return object;
} catch (InstantiationException e) {
System.out.println(e);
} catch (IllegalAccessException e) {
System.out.println(e);
} catch (IllegalArgumentException e) {
System.out.println(e);
} catch (InvocationTargetException e) {
System.out.println(e);
}
return object;
}
}
</pre>
<p>The Interface is super simple, just a setData method:</p>
<p><strong>com.hatsix.ListRenderer.IDataRenderer</strong></p>
<pre class="brush: java">
package com.hatsix.ListRenderer;

public interface IDataRenderer {
void setData(Object rawData);
Object getData();
}
</pre>
<p>This class is easy to instantiate in your application:</p>
<pre class="brush: java">
package com.hatsix;

import java.util.ArrayList;
import java.util.List;

import com.hatsix.ListRenderer.RenderedListAdapter;
import com.hatsix.constantreminder.Reminder;
import com.hatsix.constantreminder.ReminderListItemRenderer;

import android.app.ListActivity;
import android.os.Bundle;

public class RemindersList extends ListActivity {
/** Called when the activity is first created. */
private List&lt;Reminder&gt; reminders;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
reminders = new ArrayList&lt;Reminder&gt;();
// Add four items
reminders.add(new Reminder(&quot;Remember Once&quot;,&quot;today&quot;, &quot;tomorrow&quot;, getResources().getDrawable(R.drawable.finger) ));
reminders.add(new Reminder(&quot;Bell Reminder&quot;,&quot;today&quot;, &quot;tomorrow&quot;, getResources().getDrawable(R.drawable.bell)));
reminders.add(new Reminder(&quot;Laundry Reminder&quot;,&quot;today&quot;, &quot;tomorrow&quot;, getResources().getDrawable(R.drawable.laundry)));
reminders.add(new Reminder(&quot;Task Reminder&quot;,&quot;today&quot;, &quot;tomorrow&quot;, getResources().getDrawable(R.drawable.task)));

// Display it
RenderedListAdapter rla = new RenderedListAdapter(this, reminders, ReminderListItemRenderer.class);
setListAdapter(rla);
}
}
</pre>
<p>And the ItemRenderer is really easy.  We instantiate our controls, and set the values in setData():<br />
<strong>com.hatsix.constantreminder.ReminderListItemRenderer</strong></p>
<pre class="brush: java">
package com.hatsix.constantreminder;

import com.hatsix.ListRenderer.IDataRenderer;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

public class ReminderListItemRenderer extends LinearLayout implements IDataRenderer {
private Object data;
private Reminder theReminder;
private TextView mTitle;
private TextView mDescription;
private ImageView mIcon;
private LinearLayout mTextLayout;

public ReminderListItemRenderer(Context context, Object rawData) {
super(context);
this.setOrientation(HORIZONTAL);
/* We&#039;re setting up a view that has one icon on the left, and two lines
* of text on the right.
*
* First the Icon
**/
mIcon = new ImageView(context);
mIcon.setPadding(0, 2, 5, 0); // 5px to the right
// left, top, right, bottom (Can&#039;t we ever standardize TRBL?)
addView(mIcon,  new LinearLayout.LayoutParams(32,32));

/**
*  Now we do the text lines
*/
mTextLayout = new LinearLayout(context);
mTextLayout.setOrientation(VERTICAL);
addView(mTextLayout);

/* Title */
mTitle = new TextView(context);
mTextLayout.addView(mTitle, new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));

/* Description */
mDescription = new TextView(context);
mTextLayout.addView(mDescription, new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
setData(rawData);
}

public void setData(Object rawData){
data = rawData;
if(rawData.getClass() == Reminder.class){
theReminder = (Reminder) data;
mIcon.setImageDrawable(theReminder.getIcon());
mTitle.setText(theReminder.title);
mDescription.setText(theReminder.getDescription());
}
}
}
</pre>
<p>And finally, the POJO used to pass this data around:</p>
<p><strong>com.hatsix.constantreminder.Reminder</strong></p>
<pre class="brush: java">
package com.hatsix.constantreminder;

import android.graphics.drawable.Drawable;

public class Reminder {
public String title;
public String start;
public String end;
private Drawable mIcon;
private boolean mSelectable = true;

public Reminder(String t, String s, String e, Drawable icon){
title = t;
start = s;
end = e;
mIcon = icon;
}
public String getDescription(){
return start + &quot; - &quot; + end;
}
public Drawable getIcon(){
return mIcon;
}

}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://hat6.com/2009/11/22/introducing-android-to-the-concept-of-itemrenderers/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
