Google+ Badge

Sunday, September 30, 2012

Intel Atom emulator crashes with DatePicker

I love the new Intel Atom (x86) emulator for Android development. It starts up quickly and runs at real hardware speeds. I did have one big issue, every time I brought up a view with a DatePicker control in it the emulator would crash to the desktop. Not acceptable.

Running the same code on my phone or in the emulator using ARM worked like a champ. So what should a developer do? This is a bug in the emulator code, not my code. Doing a little research shows that it could be the hardware acceleration at fault. You can shut that off with a setting the android:layerType="software" in your XML file or with a call to setLayerType(View.LAYER_TYPE_SOFTWARE, null); 

The problem is I am developing my app for 2.2 and beyond. That call does not show up until a much later version of the Android platform. Time for some reflection.

Add the following as a new file to your project


import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.graphics.Paint;
import android.view.View;

public class NewerMethods {
    private static Method LayerType;

    static {
        initMethods();
    }

    private static void initMethods() {
        try {
            LayerType = View.class.getMethod("setLayerType", new Class[] {int.class, Paint.class});
            /* success, this is a newer device */
        }
        catch (NoSuchMethodException nsme) {
            /* failure, must be older device */
        }
    }

    public static void setLayerType(View view, int layerType, Paint paint) throws IOException {
        try {
            if (LayerType != null) {
                LayerType.invoke(view, layerType, paint);
            }
        }
        catch (InvocationTargetException ite) {
            /* unpack original exception when possible */
            Throwable cause = ite.getCause();
            if (cause instanceof IOException) {
                throw (IOException) cause;
            }
            else if (cause instanceof RuntimeException) {
                throw (RuntimeException) cause;
            }
            else if (cause instanceof Error) {
                throw (Error) cause;
            }
            else {
                /* unexpected checked exception; wrap and re-throw */
                throw new RuntimeException(ite);
            }
        }
        catch (IllegalAccessException ie) {
            System.err.println("unexpected " + ie);
        }
    }
}

Add the following to your onCreate method of the Activity that uses a DatePicker in its view. I have it right after my call to setConventView(...)


        try {
            NewerMethods.setLayerType(findViewById(android.R.id.content), 1, null);
        }
        catch (IOException e) {
            // Just doing this on newer stuff to avoid emulator crash
        }
        
I know, I am using a magic number in the call. I can't use View.LAYER_TYPE_SOFTWARE because Eclipse has no idea about it when compiling 2.2 code.

This allows my code to run just fine in the emulator. I am running 2.2 code in a 4.0.3 emulator as that is the super fast Intel based emulator. I also run the code on my actual 2.2 phone from time to time to make sure everything is fine. Just easier to stick on the computer using the keyboard and mouse while doing initial development and only test on hardware as needed.