移動開發:Android升級ADT22後會報ClassNotFoundException的原因分析

轉載:http://www.xue5.com/Mobile/Mobile/705347.html


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

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

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

問題解決了,但爲什麼要這麼做呢?之前ADT21爲何又不需要呢?我另一臺機器使用的還是ADT21,因此我把兩個版本的ADT工程屬性比較了一下,發現還真不一樣。下面這個是ADT21的:


wKiom1L9f-7TJ7xYAARi8argdho809.jpg


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


wKioL1L9gA6QAduOAAR9jvVX4P4195.jpg


顯然,ADT21把所有引用的JAR包都歸納爲Android Dependencies,而ADT22是自動將JAR分成Android Private Libraries和Android Dependencies兩類了。ADT21不需要勾選Export就能自動將所有引用的JAR包導出並打包到APK,而ADT22則給開發人員選擇權限,讓開發人員自己決定哪些包要導出到APK裏。比如程序面向的是高版本的Android系統,可以選擇不需要導出低版本的某些支持包。

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


wKiom1L9gFfiH47CAAK2W0Q_4kA111.jpg


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

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

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章