14

在Android 1.6上部署我的應用程序時遇到向後兼容性問題。 IM在這一段代碼得到一個的VerifyError:在API 1.6上部署VerifyError

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

因爲getActionBar()不存在預API 11這並不令人意外,但後1.6(?API 5及更高版本)生成的所有半擺好去根據在例如在API級別8設備上進行部署時獲得的logcat消息來解決這個問題;

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和更早的版本不會做這個,而是拋出的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) 

有沒有一種方法能夠完美地解決這個問題,並有向下兼容1.6?

編輯: 所以我結束了創建靜態方法HoneycombHelper類:

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

不知道這是最優雅的方式,但它似乎工作。

回答

24

當Dalvik將您的類/函數從字節碼編譯爲本地機器碼時,它將編譯所有語句,即使那些在if條件下的語句也是如此。在Android 1.6虛擬機上試圖解析(驗證)getActionBar函數,並且由於沒有這樣的函數,Dalvik會拋出VerifyError

你可以做下一個技巧:

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

... 

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

這樣ActioBarHelper類只會被編譯/驗證,當你在SDK 11+運行。這將反過來允許在不使用反射的情況下調用getActionBar函數(反射是解決此問題的另一種方法)。

+0

應該是一個靜態類是否正確? – schwiz