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

Thursday, October 10, 2013

Create Code Template for Log.d in Eclipse and Android Studio

Hi,

I've just found a way to save a lot of time while developing Android apps using Eclipse or Android Studio, by creating a shortcut for the typical Log.d statement.

Eclipse (or ADT)

In Eclipse go to Preferences > Java > Editor > Templates and click on "New...".
This will let you create a new Code Template.

Fill in the form as followed:

  • Name = logd
  • Context = Java statements
  • Select 'Automatically insert'
  • Description = Log.d shortcut
  • Pattern = ${:import(android.util.Log)}Log.d("${enclosing_type}", "${enclosing_method}: ${cursor}");
Press OK to save the template and choose OK to close and apply the changes.

Now go inside your Java-file where you want to place a new Log.d, type "logd" and press CTRL + Space.

The code template will be printed in your editor and you can start writing what you want. For example it will print Log.d("MainActivity", "onCreate: "); and your cursor will be ready after "onCreate: "
It will also automatically import android.Util.Log.

Android Studio (or intelliJ)

In Android Studio it's pretty much the same. Go to Settings and select Live Templates in the list under IDE Settings. I've selected output in the list of Live Templates and pressed the plus sign on the right-hand side to add a new Live Template.

Fill in the form as followed:
  • Abbreviation = logd
  • Description = Prints a Log.d statement
  • Template text = android.util.Log.d("$CLASS_NAME$", "$METHOD_NAME$ (line $LINE$): $MESSAGE$");$END$
  • Shorten FQ names = checked
Next, go to Edit Variables and fill in the table as followed:
  • MESSAGE
    • Default value: "Write a log message"
  • LINE
    • Expression: lineNumber()
    • Skip if defined: checked
  • METHOD_NAME
    • Expression: methodName()
    • Skip if defined: checked
  • CLASS_NAME
    • Expression: qualifiedClassName()
    • Skip if defined: checked
Last but not least, select an applicable context. I've just selected the whole Java field.
Here's a screenshot of what it should look like


Apply changes and you're done.
Just type logd and hit tab (unless you've changed it to something else). Your Log.d message will be displayed, start typing the preferred message and hit Enter. Here's an example of output:
Log.d("com.bon_app_etit.android.test.MainActivity", "onCreateOptionsMenu (line 43): Write a log message");
Once again, the Log class will automatically be added to the imports.

Good luck with this and don't forget to share ;-)

Sunday, August 25, 2013

Android Bug: StringSet in SharedPreferences

I've been using SharedPreferences a lot last week and  I think I've noticed a bug in the Android platform.

I had to update a Set<String> in my SharedPreferences and there seems to be an error when I tried to remove a String out of the Set<String>

Set<String> set = prefs.getStringSet("set", new HashSet<String>());
set.add("one");
set.add("two");
set.add("three");
editor.putStringSet("set", set);
editor.commit();
showSet(prefs.getStringSet("set", new HashSet<String>()));

This shows the three elements correctly.
After restarting the application, the Set is correctly stored in SharedPreferences.
But then I ran this code:
Set<String> set = prefs.getStringSet("set", new HashSet<String>());
set.remove("three");
editor.putStringSet("set", set);
editor.commit();
showSet(prefs.getStringSet("set", new HashSet<String>()));

At first this seems to work fine as well. It shows the elements "one" and "two".
The strange thing happens when I now stop the application from running, and restart it.
Now when I want to get the Set<String> out of the SharedPreferences, it has all three elements again.
"one", "two" and "three". Although I removed it...

Note: if you have this error, you can make your code work by first removing the Set<String>, commiting it, and then putting it in the SharedPreferences again

You can download a sample project on this here

Sunday, April 28, 2013

The dark side of AsyncTask

Hi everyone,

In this post I'm going to talk about some of the (less known) problems of AsyncTask. I've written my first post on how to use AsyncTask about half a year ago. Now I'm going to tell you what problems they might cause, how you can fix this and what other options you have.

AsyncTask (°2009 - ...)

AsyncTask was added to Android in API level 3 (Android 1.5 Cupcake) and was said to help developers manage their threads. It's actually also available for 1.0 and 1.1, under the name of UserTask. It has the same API as AsyncTask. You should just copy the source code in your application to use it. But according to the Android Dashboards, there are less 0.1% of all Android devices that run on these API levels, so I mostly don't bother to support them.

Right now, AsyncTask is probably the most commonly used technique on Android for background execution. It's really easy to work with and that's what developers love about it. But this class has a couple of downsides and we are not always aware of them.

Lifecycle

There is quite a misunderstanding about our AsyncTask. Developers might think that when the Activity that created the AsyncTask has been destroyed, the AsyncTask will be destroyed as well. This is not the case. The AsyncTask keeps on running, doing his doInBackground() method until it is done. Once this is done it will either go to the onCancelled(Result result) method if cancel(boolean) is invoked or the onPostExecute(Result result) method if the task has not been cancelled.

Suppose our AsyncTask was not cancelled before our Activity was destroyed. This could make our AsyncTask crash, because the view it wants to do something with, does not exist anymore. So we always have to make sure we cancel our task before our Activity is destroyed.  The cancel(boolean) method needs one parameter: a boolean called mayInterruptIfRunning. This should be true if the thread executing this task should be interrupted; otherwise, in-progress tasks are allowed to complete. If there is a loop in our doInBackground() method, we might check the boolean isCancelled() to stop further execution.

So we have to make sure the AsyncTask is always cancelled properly. 

Does cancel() really work?

Short answer: Sometimes.
If you call cancel(false), it will just keep running until its work is done, but it will prevent onPostExecute() to be called. So basically, we let our app do pointless work. So let's just always call cancel(true) and the problem is fixed, right? Wrong. If mayInterruptIfRunning is true, it will try to finish our task early, but if our method is uninterruptable such as BitmapFactory.decodeStream(), it will still keep doing the work. You could close the stream prematurely and catch the Exception it throws, but this makes cancel() a pointless method.

Memory leaks

Because an AsyncTask has methods that run on the worker thread (doInBackground()) as well as methods that run on the UI (e.g. onPostExecute()), it has took keep a reference to it's Activity as long as it's running. But if the Activity has already been destroyed, it will still keep this reference in memory. This is completely useless because the task has been cancelled anyway.

Losing your results

Another problem is that we lose our results of the AsyncTask if our Activity has been recreated. For example when an orientation change occurs. The Activity will be destroyed and recreated, but our AsyncTask will now have an invalid reference to its Activity, so onPostExecute() will have no effect. There is a solution for this. You can hold onto a reference to AsyncTask that lasts between configuration changes (for example using a global holder in the Application object). Activity.onRetainNonConfigurationInstance() and Fragment.setRetainedInstance(true) may also help you in this case.

Serial or parallel?

There is a lot of confusion about AsyncTasks running serial or parallel. This is normal because it has been changed a couple of times. You could probably be wondering what I mean with 'running serial or parallel'. Suppose you have these two lines of code somewhere in a method:

new AsyncTask1().execute();
new AsyncTask2().execute();

Will these two tasks run at the same time or will AsyncTask2 start when AsyncTask1 is finished?
Short answer: It depends on the API level.

Before API 1.6 (Donut):

In the first version of AsyncTask, the tasks were executed serially. This means a task won't start before a previous task is finished. This caused quite some performance problems. One task had to wait on another one to finish. This could not be a good approach.

API 1.6 to API 2.3 (Gingerbread):

The Android developers team decided to change this so that AsyncTasks could run parallel on a separate worker thread. There was one problem. Many developers relied on the sequential behaviour and suddenly they were having a lot of concurrency issues.

API 3.0 (Honeycomb) until now

"Hmmm, developers don't seem to get it? Let's just switch it back." The AsyncTasks where executed serially again. Of course the Android team provided the possibility to let them run parallel. This is done by the method executeOnExecutor(Executor). Check out the API documentation for more information on this.

If we want to make sure we have control over the execution, whether it will run serially or parallel, we can check at runtime with this code to make sure it runs parallel:

 
 public static void execute(AsyncTask as) {
  if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR1) {
   as.execute();
  } else {
   as.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
  }
 }
(This code does not work for API lvl 1 to 3)

Do we need AsyncTasks?

Not really. It is an easy way to implement background features in our app without having to write a lot of code, but as you can see, if we want it to work properly we have to keep a lot of things in mind. Another way of executing stuff in background is by using Loaders. They were introduced in Android 3.0 (Honeycomb) and are also available in the support library. Check out the developer guide for more information. I'll probably write a tutorial on how to use Loaders somewhere in the near future, so be sure to check out my blog later (or my website www.bon-app-etit.com if it's finished...)


Wednesday, April 24, 2013

Parcelable versus Serializable

In this post I'm going to talk about the differences between Parcelables and Serializables.

Android Activities are great, aren't they? They allow you to structure your app in a nice and easy way. Switching between two Activities is also really easy. Just write this.startActvitiy(intent) somewhere in your first Activity and you're done.
There's only one thing that's not so easy to do, and that's passing data between these two Activities. If we want to pass data we have to put it in an Intent or a Bundle. This is quite easy for primitive classes such as String or int, but it's a bit harder for other (custom) objects.

If you have some experience in Java, you probably know something about 'serialization'. Since we're using Java in our Android app, we could let our object implement Serializable and we're done, right? Well, not quite. Android provides us with another interface called Parcelable to do this and there's a reason why.

Serializable

First of all let's have a look at our TestObject that implements Serializable.
public class TestObject implements Serializable{



 private static final long serialVersionUID = 643301981519798569L;

 private String mString;

 private int mInt;

 private List<String> mList;

 

 public TestObject() {

  this.mString = "This is a String";

  this.mInt = 777;

  mList = new ArrayList<String>();

  for(int i=0; i<100; i++){

   mList.add(String.valueOf(i));

  }

 }

    //Getters and Setters...

}

The only thing we had to do to make sure TestObject could be passed with an Intent or Bundle, was implementing it with java.io.Serializable and add a generated serialVersionUID. Now let's have a look at the same class but as a Parcelable.

Parcelable

This is our TestObject, implementing android.os.Parcelable.

public class TestObject implements Parcelable{



 private String mString;

 private int mInt;

 private List<String> mList;



 public TestObject() {

  this.mString = "This is a String";

  this.mInt = 777;

  mList = new ArrayList<String>();

  for(int i=0; i<100; i++){

   mList.add(String.valueOf(i));

  }

 }

 

 public TestObject(Parcel in) {

  mString = in.readString();

  mInt = in.readInt();

  mList = new ArrayList<String>();

  in.readStringList(mList);

 }



 @Override

 public int describeContents() {

  return 0;

 }



 @Override

 public void writeToParcel(Parcel dest, int flags) {

  dest.writeString(mString);

  dest.writeInt(mInt);

  dest.writeStringList(mList);

  

 }

 

 public static final Parcelable.Creator<TestObject> CREATOR = new Parcelable.Creator<TestObject>() {

        public TestObject createFromParcel(Parcel in) {

            return new TestObject(in); 

        }



        public TestObject[] newArray(int size) {

            return new TestObject[size];

        }

    };

    

    //Getters and Setters...

}
The first thing we notice here is that our class just became a lot bigger. As you can see we have to override two methods, write a Parcelable.Creator and write a new Constructor. Why should you go through all this trouble if you can just simple use Serializable instead? The answer is performance.

Parcelable splits your object up into primitives, sends those primitives and rebuilds the object afterwards. By doing this, it should run a lot faster. Serializable creates a lot of temporary objects and this causes quite some garbage collection, which should always be avoided, especially on mobile devices.

Putting it to the test

Of course, I ran a small test on this. I created an instance of TestObject, added it to an Intent, started another Activity and took our TestObject out of the Intent. I used TraceView for to check how long this process took for Parcelable and Serializable.
Here's our result for using the Serializable interface:


So we can see this whole process took 248ms. 
Now let's have a look at the results of using the Parcelable interface:

As you can see, for only this one object, the process was completed in less than half of the time for our first way. And let's not forget, this is the whole process of switching to another Activity, not just writing and reading the object!

Conclusion

Parcelable works a lot faster than Serializable and is the best way to go. But if we don't need to be faster, and it's possible to just use Serializable (e.g. android.graphics.Bitmap causes problems), just use Serializable and you don't have to bother about anything anymore.

Important notes:

  • Read from the Parcel in the same order that you wrote to it
  • Don't use raw Creators (specify by adding <TestObject> in this example)