14

He encontrado un problema de compatibilidad con versiones anteriores al implementar mi aplicación en Android 1.6. Im conseguir un VerifyError en este pedazo de código:Implementación de VerifyError en la API 1.6

if(android.os.Build.VERSION.SDK_INT >= 11) { 
    getActionBar().setBackgroundDrawable(getResources().getDrawable(R.drawable.actionbar_bg)); 
} 

Esto no es inesperado ya que getActionBar() no existe API pre 11, sin embargo posterior a la 1.6 (? 5 de la API y superior) construye todo semi-gracia ir alrededor de esto de acuerdo con el mensaje logcat que recibo al implementar, por ejemplo, en un dispositivo de nivel 8 de API;

06-27 16:47:04.333: INFO/dalvikvm(11529): Could not find method com.me.app.MyActivity.getActionBar, referenced from method com.me.app.MyActivity.init 
06-27 16:47:04.333: WARN/dalvikvm(11529): VFY: unable to resolve virtual method 1090: Lcom.me.app.MyActivity;.getActionBar()Landroid/app/ActionBar; 
06-27 16:47:04.333: DEBUG/dalvikvm(11529): VFY: replacing opcode 0x6e at 0x004f 
06-27 16:47:04.333: DEBUG/dalvikvm(11529): VFY: dead code 0x0052-005f in Lcom.me.app.MyActivity;.init (Z)V 

1,6 y anterior suele hacer esto, pero en cambio lanzar una VerifyError:

06-27 16:23:45.561: ERROR/dalvikvm(427): Could not find method com.me.app.MyActivity.getActionBar, referenced from method com.me.app.MyActivity.init 
06-27 16:23:45.561: WARN/dalvikvm(427): VFY: unable to resolve virtual method 1090: Lcom/me/app/MyActivity;.getActionBar()Landroid/app/ActionBar; 
06-27 16:23:45.561: WARN/dalvikvm(427): VFY: rejecting opcode 0x6e at 0x004f 
06-27 16:23:45.561: WARN/dalvikvm(427): VFY: rejected Lcom/me/app/MyActivity;.init (Z)V 
06-27 16:23:45.561: WARN/dalvikvm(427): Verifier rejected class Lcom/me/app/MyActivity; 
06-27 16:23:45.561: WARN/dalvikvm(427): Class init failed in newInstance call (Lcom/me/app/MyActivity;) 
06-27 16:26:44.841: ERROR/AndroidRuntime(427): Uncaught handler: thread main exiting due to uncaught exception 
06-27 16:26:44.941: ERROR/AndroidRuntime(427): java.lang.VerifyError: com.me.app.MyActivity 
06-27 16:26:44.941: ERROR/AndroidRuntime(427):  at java.lang.Class.newInstanceImpl(Native Method) 
06-27 16:26:44.941: ERROR/AndroidRuntime(427):  at java.lang.Class.newInstance(Class.java:1472) 
06-27 16:26:44.941: ERROR/AndroidRuntime(427):  at android.app.Instrumentation.newActivity(Instrumentation.java:1097) 
06-27 16:26:44.941: ERROR/AndroidRuntime(427):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2316) 
06-27 16:26:44.941: ERROR/AndroidRuntime(427):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2417) 
06-27 16:26:44.941: ERROR/AndroidRuntime(427):  at android.app.ActivityThread.access$2100(ActivityThread.java:116) 
06-27 16:26:44.941: ERROR/AndroidRuntime(427):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794) 
06-27 16:26:44.941: ERROR/AndroidRuntime(427):  at android.os.Handler.dispatchMessage(Handler.java:99) 
06-27 16:26:44.941: ERROR/AndroidRuntime(427):  at android.os.Looper.loop(Looper.java:123) 
06-27 16:26:44.941: ERROR/AndroidRuntime(427):  at android.app.ActivityThread.main(ActivityThread.java:4203) 
06-27 16:26:44.941: ERROR/AndroidRuntime(427):  at java.lang.reflect.Method.invokeNative(Native Method) 
06-27 16:26:44.941: ERROR/AndroidRuntime(427):  at java.lang.reflect.Method.invoke(Method.java:521) 
06-27 16:26:44.941: ERROR/AndroidRuntime(427):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791) 
06-27 16:26:44.941: ERROR/AndroidRuntime(427):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549) 
06-27 16:26:44.941: ERROR/AndroidRuntime(427):  at dalvik.system.NativeStart.main(Native Method) 

¿Hay una manera de solucionar este problema con elegancia y tienen compatibilidad con versiones anteriores a 1.6?

Editar: Así que acabó creando una clase con métodos estáticos HoneycombHelper:

public class HoneycombHelper { 
    public static void setActionBarBackgroundDrawable(Activity a, Drawable d) { 
     a.getActionBar().setBackgroundDrawable(d); 
    } 
    ... 
} 

No estoy seguro si esta es la forma más elegante, pero parece que no funciona.

Respuesta

24

Cuando Dalvik compila su clase/función de bytecode en código máquina nativo, compila todas las instrucciones, incluso aquellas que están dentro de las condiciones if. En la máquina virtual Android 1.6 intenta resolver (verificar) la función getActionBar, y como no existe tal función, Dalvik lanza VerifyError.

Usted puede hacer siguiente truco:

class ActionBarHelper{ 
    void setBackground(){ 
     getActionBar().setBackgroundDrawable(...); 
    } 
} 

... 

if(android.os.Build.VERSION.SDK_INT >= 11) { 
    new ActionBarHelper().setBackground();  
} 

De esta manera sólo se compila ActioBarHelper clase/verifica cuando se está ejecutando el SDK de 11+. Esto a su vez permitirá llamar a la función getActionBar sin usar la reflexión (la reflexión es otra posible solución a este problema).

+0

debería ser una clase estática correcta? – schwiz

Cuestiones relacionadas