Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android類加載器

Android類加載器

編輯:關於Android編程

 

在介紹Android的類加載機制之前,我們需要先了解一下Java的類加載機制。

 

一 Dalvik虛擬機與Java虛擬機

Dalvik虛擬機如同其他Java虛擬機一樣,在運行程序時首先需要將對應的類加載到內存中。而在Java標准的虛擬機中,類加載可以從class文件中讀取,也可以是其他形式的二進制流。因此,我們常常利用這一點,在程序運行時手動加載Class,從而達到代碼動態加載執行的目的。

然而Dalvik虛擬機畢竟不算是標准的Java虛擬機,因此在類加載機制上,它們有相同的地方,也有不同之處。我們必須區別對待。例如,在使用標准Java虛擬機時,我們經常自定義繼承自ClassLoader的類加載器。然後通過defineClass方法來從一個二進制流中加載Class。然而,這在Android裡是行不通的,

二 Android類加載器

Android的類加載器主要有兩個PathClassLoader和DexClassLoader,其中PathClassLoader是默認的類加載器,下面我們就來說說兩者的區別與聯系。

PathClassLoader:支持加載DEX或者已經安裝的APK(因為存在緩存的DEX)。 DexClassLoader:支持加載APK、DEX和JAR。

DexClassLoader和PathClassLoader都屬於符合雙親委派模型的類加載器(因為它們沒有重載loadClass方法)。也就是說,它們在加載一個類之前,回去檢查自己以及自己以上的類加載器是否已經加載了這個類。如果已經加載過了,就會直接將之返回,而不會重復加載。

無論是PathClassLoader還是DexClassLoader都是繼承於BaseClassLoader,那麼我們就先來看一下BaseCLassLoader的實現。

2.1 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!);
  }
}

2.2 PathClassLoader

【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

2.3 DexClassLoader

【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到指定的目錄。

2.4 DexFile

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;
}

三 Android類加載機制

3.1類加載器結構

3.1.1 系統類加載器

舉例

Context.class.getClassLoader();

上述代碼得到的結果表明系統類的加載器是BootClassLoader。

ClassLoader.getSystemClassLoader().getParent();

上述代碼表明系統加載器的父類加載器還是

3.2.2 應用程序加載器

舉例

getClassLoader();

上述代碼得到的結果表明應用程序的加載器是PathClassLoader

getClassLoader().getParent();

上述代碼得到的結果表明應用程序的家在啟動餓父類加載器是BootClassLoader。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved