編輯:關於Android編程
在介紹Android的類加載機制之前,我們需要先了解一下Java的類加載機制。
Dalvik虛擬機如同其他Java虛擬機一樣,在運行程序時首先需要將對應的類加載到內存中。而在Java標准的虛擬機中,類加載可以從class文件中讀取,也可以是其他形式的二進制流。因此,我們常常利用這一點,在程序運行時手動加載Class,從而達到代碼動態加載執行的目的。
然而Dalvik虛擬機畢竟不算是標准的Java虛擬機,因此在類加載機制上,它們有相同的地方,也有不同之處。我們必須區別對待。例如,在使用標准Java虛擬機時,我們經常自定義繼承自ClassLoader的類加載器。然後通過defineClass方法來從一個二進制流中加載Class。然而,這在Android裡是行不通的,
Android的類加載器主要有兩個PathClassLoader和DexClassLoader,其中PathClassLoader是默認的類加載器,下面我們就來說說兩者的區別與聯系。
PathClassLoader:支持加載DEX或者已經安裝的APK(因為存在緩存的DEX)。 DexClassLoader:支持加載APK、DEX和JAR。DexClassLoader和PathClassLoader都屬於符合雙親委派模型的類加載器(因為它們沒有重載loadClass方法)。也就是說,它們在加載一個類之前,回去檢查自己以及自己以上的類加載器是否已經加載了這個類。如果已經加載過了,就會直接將之返回,而不會重復加載。
無論是PathClassLoader還是DexClassLoader都是繼承於BaseClassLoader,那麼我們就先來看一下BaseCLassLoader的實現。
【android-21】BaseDexClassLoader的源碼如下所示:
package dalvik.system;
import java.io.File;
import java.net.URL;
import java.util.Enumeration;
public class BaseDexClassLoader
extends ClassLoader
{
public BaseDexClassLoader(String dexPath, File optimizedDirectory, String libraryPath, ClassLoader parent)
{
throw new RuntimeException(Stub!);
}
protected Class findClass(String name)
throws ClassNotFoundException
{
throw new RuntimeException(Stub!);
}
protected URL findResource(String name)
{
throw new RuntimeException(Stub!);
}
protected Enumeration findResources(String name)
{
throw new RuntimeException(Stub!);
}
public String findLibrary(String name)
{
throw new RuntimeException(Stub!);
}
protected synchronized Package getPackage(String name)
{
throw new RuntimeException(Stub!);
}
public String toString()
{
throw new RuntimeException(Stub!);
}
}
【android-21】PathClassLoader的源碼如下所示:
package dalvik.system;
import java.io.File;
public class PathClassLoader
extends BaseDexClassLoader
{
public PathClassLoader(String dexPath, ClassLoader parent)
{
super((String)null, (File)null, (String)null, (ClassLoader)null);throw new RuntimeException(Stub!);
}
public PathClassLoader(String dexPath, String libraryPath, ClassLoader parent)
{
super((String)null, (File)null, (String)null, (ClassLoader)null);throw new RuntimeException(Stub!);
}
}
從源碼可以看出,PathClassLoader有兩個構造函數,函數中的參數含義如下所示:
String dexPath:加載APK、DEX和JAR的路徑。 String libraryPath:加載DEX的時候需要用到的lib庫,libraryPath一般包括/vendor/lib和/system/lib。 ClassLoader parent:DEXClassLoader指定的父類加載器PathClassLoader
【android-21】DexClassLoader的源碼如下所示:
package dalvik.system;
import java.io.File;
public class DexClassLoader
extends BaseDexClassLoader
{
public DexClassLoader(String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent)
{
super((String)null, (File)null, (String)null, (ClassLoader)null);throw new RuntimeException(Stub!);
}
}
從源碼可以看出,DexClassLoader只有一個構造函數,該函數中的參數含義如下所示:
String dexPath:加載APK、DEX和JAR的路徑。 String optimizedDirectory:是DEX的輸出路徑。 String libraryPath:加載DEX的時候需要用到的lib庫,libraryPath一般包括/vendor/lib和/system/lib。 ClassLoader parent:DEXClassLoader指定的父類加載器大家可以發現DexClassLoader的構造函數比PathClassLoader多了一個String optimizedDirectory參數,這是因為PathClassLoader是加載/data/app中的APK,而這部分的APK都會解壓釋放dex到指定的目錄。
DexClassLoader和PathClassLoader其實都是通過DexFile這個類來實現類加載的。這裡需要順便提一下的是,Dalvik虛擬機識別的是dex文件,而不是class文件。因此,我們供類加載的文件也只能是dex文件,或者包含有dex文件的.apk或.jar文件。
也許有人想到,既然DexFile可以直接加載類,那麼我們為什麼還要使用ClassLoader的子類呢?DexFile在加載類時,具體是調用成員方法loadClass或者loadClassBinaryName。其中loadClassBinaryName需要將包含包名的類名中的”.”轉換為”/”。我們看一下loadClass代碼就清楚了。
【android-21】DexFile源碼如下所示:
package dalvik.system;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Enumeration;
public final class DexFile
{
public DexFile(File file)
throws IOException
{
throw new RuntimeException(Stub!);
}
public DexFile(String fileName)
throws IOException
{
throw new RuntimeException(Stub!);
}
public static DexFile loadDex(String sourcePathName, String outputPathName, int flags)
throws IOException
{
throw new RuntimeException(Stub!);
}
public String getName()
{
throw new RuntimeException(Stub!);
}
public String toString()
{
throw new RuntimeException(Stub!);
}
public void close()
throws IOException
{
throw new RuntimeException(Stub!);
}
public Class loadClass(String name, ClassLoader loader)
{
throw new RuntimeException(Stub!);
}
public Enumeration entries()
{
throw new RuntimeException(Stub!);
}
protected void finalize()
throws Throwable
{
throw new RuntimeException(Stub!);
}
public static native boolean isDexOptNeeded(String paramString)
throws FileNotFoundException, IOException;
}
舉例
Context.class.getClassLoader();
上述代碼得到的結果表明系統類的加載器是BootClassLoader。
ClassLoader.getSystemClassLoader().getParent();
上述代碼表明系統加載器的父類加載器還是
舉例
getClassLoader();
上述代碼得到的結果表明應用程序的加載器是PathClassLoader
getClassLoader().getParent();
上述代碼得到的結果表明應用程序的家在啟動餓父類加載器是BootClassLoader。
IOS相比於Android,動畫效果是一方面優勢,IOS相機切換時滑動的動畫很不錯,看著是有一個3D的效果,而且變化感覺很自然。Android也可以通過Graphics下
Android中常用的5大布局方式有以下幾種:線性布局(LinearLayout):按照垂直或者水平方向布局的組件。幀布局(FrameLayout):組件從屏幕左上方布局
許多應用可能需要加入進度,例如下載、播放視頻、音頻、讀取數據庫等等,都需要一個等待狀態的進度條。原生的進度條的確不美觀,今天這篇小案例,就讓咱們的進度條“靓起
Android基礎入門教程——10.3 AudioManager(音頻管理器)標簽(空格分隔): Android基礎入門教程本節引言: 在多媒體的