程序編制一般需經編輯、編譯、鏈接、加載和運行幾個步驟。在我們的應用中,有一些公共代碼是需要反復使用,就把這些代碼編譯為“庫”文件;在鏈接步驟中,連接器將從庫文件取得所需的代碼,復制到生成的可執行文件中。這種庫稱為靜態庫,其特點是可執行文件中包含了庫代碼的一份完整拷貝;缺點就是被多次使用就會有多份冗余拷貝。
為了克服這個缺點可以采用動態鏈接庫。這個時候鏈接器僅僅是在可執行文件中打上標志,說明需要使用哪些動態連接庫;當運行程序時,加載器根據這些標志把所需的動態鏈接庫加載到內存。 另外在當前的編程環境中,一般都提供方法讓程序在運行的時候把某個特定的動態連接庫加載并運行,也可以將其卸載(例如Win32的LoadLibrary()&FreeLibrary()和Posix的dlopen()&dlclose())。這個功能被廣泛地用于在程序運行時刻更新某些功能模塊或者是程序外觀。 與普通程序不同的是,Java程序(class文件)并不是本地的可執行程序。當運行Java程序時,首先運行JVM(Java虛擬機),然后再把Java class加載到JVM里頭運行,負責加載Java class的這部分就叫做Class Loader。通常class文件僅在需要使用時才加載。 這本身就是一種動態鏈接。 Java作為一種天生的動態鏈接語言,無法支持靜態鏈接。但C語言的靜態庫除了靜態鏈接的概念外,還隱含了一層意思,即庫中的代碼會打包到可執行文件中。JAVA中的JAR某種程度上類似一個可執行文件或庫,借用C語言中靜態庫和動態庫的概念,這里把最終會合并到生成的JAR文件中的JAR包叫靜態庫,反之僅僅在編譯中使用,并不打包到生成的JAR包中,運行時需系統自行提供的JAR包叫動態庫。 C的靜態鏈接只把需要的代碼復制過來,而Java用類似Fat Jar的方法,把所有的依賴庫打包到最后的庫中,眉毛胡子一把抓。這個問題可以用ProGuard解決,用它自己的話說是 It detects and removes unused classes, fields, methods, and
attributes。 Eclipse中對JAR包的使用方式有兩種,library和user libraries,其中library在工程中通過add jars...或add external jars...添加,出現在Referenced Libraries中,而user libraries需要在工作空間中管理,再在工程中通過add library...添加。這兩種使用方式本身并沒有靜態庫和動態庫的區別,需要在打包或部署時再行指定。但user libraries的方式明顯更方便管理多個工程共同使用的多個庫,而系統庫往往都有這種特性。 android的apk比JAR更類似可執行程序,而且因為標準庫隱藏了很多功能,我們常常需要使用自己構建的系統庫來編譯。但android的ADT工具并沒有提供是否將library或user libraries打包的選項。根據我的經驗,ADT默認將library打包到apk中,而user libraries則僅用于編譯,運行時再請求系統加載相關類。哪位同學有更明確的信息,還望指教,我短期內恐怕不會有時間去研究這個問題。 因此,可以這么說,在android中,library用來添加靜態庫,而user libraries用來管理動態庫。千萬不能弄錯了,如果把靜態庫錯誤地加入動態庫,運行時會出現找不到對應的class的錯誤,但因為Java語言的動態鏈接機制,只有運行到庫中代碼時才會出錯;反之,如果把動態庫做成了靜態庫,問題就更隱蔽了,可能只是dex文件特別大,而沒有其它問題,也可能因加載了錯誤版本的系統代碼,出現一些稀奇古怪的問題。慎之,慎之... 附:向eclispe中添加user Libraries的步驟: |
|