Sunday, April 6, 2014

SQLiteDatabase: Handling upgrades

When you're looking for tutorials online on how to create an SQLiteOpenHelper. You will probably find one where the onUpgrade() method drops your whole table and recreates it. In a lot of cases, you don't want the user to lose all their data whenever a database change has been made in a new version of the app.
It would be really bad practice when this would happen.

Now, how can we handle database upgrades then?
For this, let's have a look at the arguments that are passed in the onUpgrade() method. We have our SQLiteDatabase, the version number of the old database and the version number of the new database.

You could use a switch, checking the new version number and run some SQLite ALTER methods in the case block. That way, every time a new version is installed it will only run the ALTER methods of that new version. But when a user switches from version number 1 to version number 3, the changes for version number 2 will not have happened.

Next option is using a fall-through switch, where it jumps in on the right version number and runs all the changes that have happened since then. So suppose the version number is 3, then it will run all the changes for version 3 and version 2. The problem is, if the changes have already been done, it will try to run them again. This might cause a SQLiteDatabaseException for example when you're adding a new column, it might have a duplicate column name.

There's one way to solve this:
Use a fall-through switch and check if the old version number is the same as the case. When this happens, break out of the switch before running the changes.

Here's an example of this:

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  switch (newVersion) {
  case 3:
   if(oldVersion == 3) {
    break;
   }
   db.execSQL("ALTER TABLE " + CONTACTS_TABLE + " ADD COLUMN " + CONTACTS_EMAIL + " TEXT");
  case 2:
   if(oldVersion == 2) {
    break;
   }
   db.execSQL("ALTER TABLE " + CONTACTS_TABLE + " ADD COLUMN " + CONTACTS_AGE + " INTEGER");
   
  }
 }
This method might be helpful to you and your users.

At all costs, try to avoid this if it's possible:
@Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + CONTACTS_TABLE);
        onCreate(db);
    }

Thursday, February 6, 2014

Change default minSdk for new project in Android Studio

Does somebody still set API lvl 7 as their minimum required SDK when creating a new Android Project?

Indeed.

Android 2.1 Eclair currently represents less than 0.1% according to the Android Dashboards. So why does Android Studio still selects this as the default value for Minimum required SDK version?
I've written a post last week about adding a code template for Log.d in Android Studio and I was surprised about the interest of everybody. So I've decided to write about a little tweak in Android Studio again.

It took me quite some time and searching, but I've found out how you can change this to be something else, like 14 for example. Go to the android-studio directory and follow this path: plugins/android/lib/templates/gradle-projects/NewAndroidModule/template.xml

Open the file with your favourite editor and look for a parameter-tag with id="minApi".
Change the default to 14, save the file and (re)start Android studio. Now when you choose New Project, the default value for minimum required SDK will be put at 14.

I've been searching to change the default packageName as well because I always need to change it. There's a parameter in the template.xml file as well but I'm afraid it gets overwritten by another value that's probably hard-coded. However, if you would find out how to do that, let me know ;-)

Hope this helps you out a bit!

Wednesday, January 15, 2014

ImageView ScaleTypes

When there are images that need to be displayed in an Android app, we need to be careful with the way they are scaled. A first basic step is setting the right scaletype in your layout file.

The different scaletypes are:

  • center
  • centerInside
  • centerCrop
  • fitXY
  • fitStart
  • fitCenter (which is the default)
  • fitEnd
  • matrix (can be used for transformations but is not covered here)


This post will just simple show the different scaletypes with a screenshot of how it looks in the app.
Here's the code of my layout:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/logo"
        android:scaleType="centerCrop" />

</RelativeLayout>

Image larger than its given space


center
centerInside
centerCrop
fitXY
fitStart
fitCenter (default)

fitEnd

Image smaller than its given space



center
centerInside
centerCrop
fitXY
fitStart

fitCenter

fitEnd