Bitmap Zombieee

When working with bitmaps, there is an issue that shows in the device but not in the
android emulator.

I was always thinking that after using the method empty(), I did not have to worry about the reference variable no more. I did this assumption because in the android developers guide like establish that “Free the native object associated with this bitmap, and clear the reference to the pixel data.” (http://developer.android.com/reference/android/graphics/Bitmap.html). Therefore, I was assuming that the Garbage Collector would take care of it:

Bitmap bitmap = null;
bitmap = BitmapFactory.decodeFile(uri.getPath());
if (bitmap != null) {
   ...
   bitmap.recycle();
}
..

However, I was proven wrong after repeated problem I was facing when running the program inside the device.
After searching online for hours, I found out that the bitmap reference have to be set to null after using the recycle() method:

Bitmap bitmap = null;
bitmap = BitmapFactory.decodeFile(uri.getPath());
if (bitmap != null) {
   ...
   bitmap.recycle();
   bitmap = null;
}
...

Just to clarify, there is no obligation in using the recycle() method; however, it is a good practice using it.

Another thing to have in consideration is that when you pass a bitmap object to another object, you need to know if that object would make a copy or use the bitmap object that you provide. If the bitmap object provided is the one that will be use, then make sure to not recycle or null the bitmap object else you will get a run-time error.

Bitmap bitmap = null;
bitmap = BitmapFactory.decodeFile(uri.getPath());
if (bitmap != null) {
    imageButtonPicture.setImage(bitmap); // do not null or recycle bitmap
}
...
Share
Leave a comment

No External Storage Issue

I notice an error when I was trying to access to the external storage.
The method getRoot() that I implemented was returning null instead of the external storage directory:

public static File getRoot() {
    Log.d(TAG, 'getRoot()');
    return (ExternalStorage.isAvailable()) ? Environment.getExternalStorageDirectory() : null;
}

After thinking, I remember that I choose the option Disk drive instead of HTC Sync as I always do:

I reconnected the device and choose HTC Sync instead of Disk Drive.
This solve the problem; however, I must add the steps needed to working with this kind of issues. I was not expected for the external storage to be unavailable if connected to the PC.

Share
Leave a comment

Working with SQLite Cursors

A common mistake is the improper way to use cursors. It is very common to use a cursor and forget to close it. This produce an IllegalStateException.

A code similar to the following code example will produce an error the moment you leave the activity:

private void readContactData(long contactDataId) {
   Log.d(TAG, 'readContactData()');
   dbContact.open();
   Cursor cursor = dbContact.getContact(contactDataId);
   if (cursor.moveToFirst()) {
     ...
   } else {
     ...
   }
   dbContact.close();
   ...
}

The problem is that you are not closing the cursor properly.
You could try the following variable of the previous code:

private void readContactData(long contactDataId) {
   Log.d(TAG, 'readContactData()');
   dbContact.open();
   Cursor cursor = dbContact.getContact(contactDataId);
   if (cursor.moveToFirst()) {
     ...
   } else {
     ...
   }
   cursor.close();
   dbContact.close();
   ...
}

However, there are cases that this code produce a warning when cursor calls the method finalizer(). This seems to be a problem with Droid 2.

This method seems to work better:

private void readContactData(long contactDataId) {
    Log.d(TAG, 'readContactData()');
    Cursor cursor = null;
    try{
        dbContact.open();
        cursor = dbContact.getContact(contactDataId);
        if (cursor.moveToFirst()) {
            ...
        } else {
            ...
        }
        dbContact.close();
    }finally{
        if (cursor != null){
            cursor.deactivate();
            cursor.close();
        }
    }
}

Finally, there is always the option of using startManagingCursor(); however, this will be deprecated and replaced with CursorLoader class when using API 11.

Share
Leave a comment