Introducing Android migrations

1 2 3 Page 3
Page 3 of 3
Updated Activity to interact with SQLite
<span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<code class='java'><span class='line'><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">b50</span><span class="o">.</span><span class="na">db</span><span class="o">.</span><span class="na">ex</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.app.Activity</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.database.Cursor</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.database.sqlite.SQLiteDatabase</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.os.Bundle</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.widget.ListAdapter</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.widget.ListView</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.widget.SimpleCursorAdapter</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">MainActivity</span> <span class="kd">extends</span> <span class="n">Activity</span> <span class="o">{</span>
</span><span class='line'>  
</span><span class='line'>  <span class="kd">protected</span> <span class="n">SQLiteDatabase</span> <span class="n">db</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>  <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">onCreate</span><span class="o">(</span><span class="n">Bundle</span> <span class="n">savedInstanceState</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="kd">super</span><span class="o">.</span><span class="na">onCreate</span><span class="o">(</span><span class="n">savedInstanceState</span><span class="o">);</span>
</span><span class='line'>    <span class="n">setContentView</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">layout</span><span class="o">.</span><span class="na">activity_main</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">this</span><span class="o">.</span><span class="na">db</span> <span class="o">=</span> <span class="o">(</span><span class="k">new</span> <span class="n">DatabaseHelper</span><span class="o">(</span><span class="k">this</span><span class="o">)).</span><span class="na">getWritableDatabase</span><span class="o">();</span>
</span><span class='line'>    <span class="n">ListView</span> <span class="n">list</span> <span class="o">=</span> <span class="o">(</span><span class="n">ListView</span><span class="o">)</span> <span class="n">findViewById</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">list</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">ListAdapter</span> <span class="n">adapter</span> <span class="o">=</span> <span class="n">getAdaptorForQuery</span><span class="o">(</span><span class="s">"SELECT _id, name, description FROM hops ORDER BY name ASC"</span><span class="o">,</span> <span class="kc">null</span><span class="o">);</span>
</span><span class='line'>    <span class="n">list</span><span class="o">.</span><span class="na">setAdapter</span><span class="o">(</span><span class="n">adapter</span><span class="o">);</span>
</span><span class='line'>  <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="kd">private</span> <span class="n">ListAdapter</span> <span class="nf">getAdaptorForQuery</span><span class="o">(</span><span class="n">String</span> <span class="n">queryString</span><span class="o">,</span> <span class="n">String</span><span class="o">[]</span> <span class="n">parameters</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="n">Cursor</span> <span class="n">cursor</span> <span class="o">=</span> <span class="k">this</span><span class="o">.</span><span class="na">db</span><span class="o">.</span><span class="na">rawQuery</span><span class="o">(</span><span class="n">queryString</span><span class="o">,</span> <span class="n">parameters</span><span class="o">);</span>
</span><span class='line'>    <span class="k">return</span> <span class="k">new</span> <span class="nf">SimpleCursorAdapter</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="n">R</span><span class="o">.</span><span class="na">layout</span><span class="o">.</span><span class="na">list_item</span><span class="o">,</span> <span class="n">cursor</span><span class="o">,</span>
</span><span class='line'>              <span class="k">new</span> <span class="n">String</span><span class="o">[]</span> <span class="o">{</span> <span class="s">"name"</span><span class="o">,</span> <span class="s">"description"</span> <span class="o">},</span> <span class="k">new</span> <span class="kt">int</span><span class="o">[]</span> <span class="o">{</span> <span class="n">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">hopName</span><span class="o">,</span> <span class="n">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">description</span> <span class="o">},</span> <span class="mi">0</span><span class="o">);</span>
</span><span class='line'>  <span class="o">}</span>
</span><span class='line'><span class="o">}</span>
</span></code>

As you can see from the code above, the app now makes a query to the underlying SQLite instance and builds a ListView from the result set of the query.

The key line is how the SQLiteDatabase instance is obtained: this.db = (new DatabaseHelper(this)).getWritableDatabase(); – that is where all the magic takes place. Droid Migrate passes along the version number to the Android platform and if there is a change, the Android platform will call a series of life-cycle methods, which Droid Migrate wires up with your migrations.

For instance, let’s imagine that a subsequent release of this app adds more data to the hops table. Therefore, I’ll generate a new migration. This is done by typing the following command within the root directory of your project like so:

Generating a new migration
<span class='line-number'>1</span>
<code class='bash'><span class='line'><span class="nv">$></span> droid-migrate generate up
</span></code>

The up flag signifies an increase in the database version (i.e. version++) and down indicates a rollback (i.e. version–). If you take a look at your app’s code, you’ll notice a new class: DBVersion2 and your migrations.xml file has been updated: the database_version value is now 2.

I’ll implement my DBVersion2 class like so:

Implementing DBVersion2 to add one more row of data
<span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<code class='java'><span class='line'><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">b50</span><span class="o">.</span><span class="na">db</span><span class="o">.</span><span class="na">ex</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kn">import</span> <span class="nn">com.b50.migrations.AbstractMigration</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">DBVersion2</span> <span class="kd">extends</span> <span class="n">AbstractMigration</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">up</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>      <span class="n">execSQL</span><span class="o">(</span><span class="s">"INSERT INTO 'hops' VALUES(100,'Zythos','New IPA style hop blend created to optimize and exceed the aroma characteristics of the traditional, and sometimes hard to get, IPA hops.','Amarillo, Columbus, Cascade','9.5 to 12','IPAs','Bittering and Aroma', '');"</span><span class="o">);</span>
</span><span class='line'>  <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">down</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>      <span class="n">execSQL</span><span class="o">(</span><span class="s">"DELETE from 'hops' where _id = 100"</span><span class="o">);</span>
</span><span class='line'>  <span class="o">}</span>
</span><span class='line'><span class="o">}</span>
</span></code>

Now if I fire up my app, the ListView will have 2 items in it!

What about if you need to rollback? That’s just as easy. Imagine that the addition of that second row of data was a gigantic mistake and instead I really only want one row (i.e. I only want the data originally created in DBVersion1). All I have to do is type within the root of my project:

Rollbacks in Droid Migrate are just as easy
<span class='line-number'>1</span>
<code class='bash'><span class='line'><span class="nv">$></span> droid-migrate generate down
</span></code>

After typing the above command, you should see the following output:

Rollback to version 1!
<span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<code class='bash'><span class='line'>Generating a rollback migration...
</span><span class='line'>Rolling back your migrations.xml file to indicate database version 1
</span><span class='line'>Done!
</span></code>

The only thing that’ll change in your project is the migrations.xml file – the database_version value will be rolled back to 1 (or what ever 1 minus the current version is).

Fire the app back up, and behold: one value is displayed because DBVersion2’s down method was executed!

Droid Migrate makes upgrades and rollbacks to your underlying SQLite database a breeze; what’s more, it can handle upgrades or rollbacks beyond just one version. That is, if an app instance is upgraded from version 2 to version 6, each migration will be run in order (3, 4, 5, and 6). The same is true of a rollback.

If you are working with SQLite in an Android app, I highly recommend you take a look at Droid Migrate!

This story, "Introducing Android migrations" was originally published by JavaWorld.

Related:

Copyright © 2013 IDG Communications, Inc.

1 2 3 Page 3
Page 3 of 3
InfoWorld Technology of the Year Awards 2023. Now open for entries!