Android升級ADT22後會報ClassNotFoundException的緣由分析

最近有個同事跟我報怨說,他的系統重裝Eclipse使用新的ADT22後,編譯的android apk運行總會報ClassNotFoundException錯誤。我說這怎麼可能,谷歌這麼大的公司出來的東西怎麼可能有這種問題。他說不信你試試,我說試試就試試。我以前用的是ADT21,結果升到ADT22後一運行,暈,不得不服,還果然是ClassNotFound了。 android

接下來我又換了幾個工程編譯運行,發現並不必定是全部工程都有錯,而是部分使用了第三方JAR包或庫工程的APK纔會出錯,也就是說,NotFound的Class都是在引用的JAR包裏的。 eclipse

接下來天然是在網上找解決辦法了,最後也找到了,就是在.classpath裏給com.android.ide.eclipse.adt.LIBRARIES加exported=true,或者在工程屬性Java Build Path的Order and Export裏勾選Android Private Libraries,將相關的庫導出到APK裏。 ide

問題解決了,但爲何要這麼作呢?以前ADT21爲什麼又不須要呢?我另外一臺機器使用的仍是ADT21,所以我把兩個版本的ADT工程屬性比較了一下,發現還真不同。下面這個是ADT21的: 工具

其中相互對應的包和源碼我用紅線相連起來了以便分析。下面這個是ADT22的: ui

顯然,ADT21把全部引用的JAR包都概括爲Android Dependencies,而ADT22是自動將JAR分紅Android Private Libraries和Android Dependencies兩類了。ADT21不須要勾選Export就能自動將全部引用的JAR包導出並打包到APK,而ADT22則給開發人員選擇權限,讓開發人員本身決定哪些包要導出到APK裏。好比程序面向的是高版本的Android系統,能夠選擇不須要導出低版本的某些支持包。 spa

顯然ADT22比ADT21更合理,用戶沒勾選的包天然是不該該導出的。但話說回來,其實基本上大部分狀況下咱們既然把包加到工程裏就是須要導出的。在上圖狀況下,要達到ADT21版本的導出效果,其實只須要把最後兩項勾選上,以下圖: .net

這樣ADT就會把相應的JAR包裏的類也打包到APK裏,再運行就不會找不到類了。 翻譯

其實要說ClassNotFound這個問題,安卓的開發人員應該都已經不是第一次趕上,在從ADT16升級到ADT17時,就已經搞過一回。再ADT17以前,只要是在工程Build Path裏的JAR,無論放在哪,ADT都會自動編譯進APK裏;但到了ADT17就得把要導出的包全放在libs目錄下。爲此我還翻譯了老外一篇文章,參見:http://blog.csdn.net/huzgd/article/details/7604069blog

從任何JAR都自動導出,到只導出libs目錄的JAR,到只導出勾選的JAR,應該說ADT是在改進,但也帶來升級的麻煩。總得來講並非ADT22有問題,而是ADT21以前的編譯工具不規範,ADT22只是更規範。就說嘛谷歌不會這麼容易使人失望的,但就是會折騰人。 ip

相關文章
相關標籤/搜索