2016-07-15 3 views
0

verwenden wir benutzerdefinierte MyClassLoader erweitert ClassLoader Standard PathClassLoader, wie zu ersetzen:Warum MyFragment von PathClassLoader nicht geladen wird myClassLoader

Context mBase = (Context) getFieldValue(application, "mBase"); 
    Object mPackageInfo = getFieldValue(mBase, "mPackageInfo"); 
    ORIGINAL_CLASS_LOADER = (ClassLoader) getFieldValue(mPackageInfo, "mClassLoader"); 
    CUSTOMED_CLASS_LOADER = new MyClassLoader(ORIGINAL_CLASS_LOADER); 

ausgeführt, wenn die Anwendung ist onCreat.

Das erste Problem ist, dass nicht alle Klassen von MyClassLoader zuerst geladen wird, nur MyActivitys und MyViews von MyClassLoader geladen werden, werden MyFragments noch von PathClassLoader geladen. Hat das etwas mit Context zu tun?

In MyClassLoader wir Klasse laden, indem

public Class<?> loadClass(String className) 
      throws ClassNotFoundException { 
     try { 
      ClassLoader myDexClassLoader = loaders.get("DEX"); 
      if(myDexClassLoader != null){ 
       Class<?> c = null; 
       try { 
        c = myDexClassLoader.loadClass(className); 
        // c = loader.findClass(className); 
       } catch (ClassNotFoundException e) { 
       } 
       if (c != null) { 
        return c; 
       } 
      } 
     } 
     return super.loadClass(className); 
    }` 

und myDexClassLoader ist definiert als

public static class MyDexClassLoader extends DexClassLoader { 

    public MyDexClassLoader(String dexPath, String dexOutputDir, 
      String libPath, ClassLoader parent) { 
     super(dexPath, dexOutputDir, libPath, parent); 
    } 

    @Override 
    protected Class<?> findClass(String name) throws ClassNotFoundException { 
     return super.findClass(name); 
    } 

    @SuppressLint("NewApi") 
    @Override 
    public Class<?> loadClass(String className) 
      throws ClassNotFoundException { 
     Class<?> clazz = null; 
     try { 
      clazz = findClass(className); 
     } catch (ClassNotFoundException e) { 
     } 
     if (clazz != null) { 
      return clazz; 
     } 
     return super.loadClass(className); 
    } 

} 

MyDexClassLoader ist inited mit PatchDex Datei enthält Klassen wie A1 und C1.

PathClassLoader ist sowohl MyDexClassLoader als auch MyClassLoader Elternteil.

Und in OriginalApk haben wir die ursprüngliche Klasse A1B1C1.

Das zweite Problem ist, dass wir in der loadClass Methode drucken können, dass neue A1 von PatchDex von MyDexClassLoader (genannt von MyClassLoader),

geladen wird, sondern als Klasse B1 ist nicht in der PatchDex, MyDexClassLoader schließlich (warum nicht zuerst von MyClassLoader genannt) verwendet es Eltern ( PathClassLoader), die alte B1 zu laden

Klasse B1 C1 wird mit direkt, so haben wir cla laden ss C1. Durch die print loadClass-Methode haben wir festgestellt, MyDexClassLoader hat die Kontrolle übernommen, aber es ist nicht PatchDex, nur mit Eltern PathClassLoaderalten C1.

Wie passiert das? Warum MyDexClassLoader laden Klasse C1 direkt von seiner Eltern, aber es ist nicht PatchDex wenn es hat?

Vielen Dank im Voraus.

+0

Ich vergesse, es gibt ein anderes Problem, warum 'MyClassLoader' ist nicht immer der erste aufgerufene Classloader? Manchmal wird 'loadClass' von' MyDexClassLoader' direkt aufgerufen, ohne ''loadClass'' MyClassLoader' aufzurufen. – oscarthecat

Antwort

1

Die Classloader in andorid für dex unterscheidet sich von Java Classloader.

Beispiel: pathclassloader und dexclassloader verweisen nicht mehr auf child. Dieser Classloader hat seine eigenen Dex-Dateilisten für die Ladeklasse von registrierten Dex-Dateien.

also, verwenden Sie nicht zuerst Super-Klasse. muss die Klasse zuerst von Ihrem eigenen benutzerdefinierten Klassenlader finden.

+0

Vielen Dank, Sie sparen meinen Tag! Ich habe Quellcode überprüft, es ist 'private final DexPathList pathList;' in BaseDexClassLoader, so dass alle find selbst die DexPathList-Pfadliste findet. – oscarthecat

+0

ja, Sie korrigieren. gute Arbeit: D – hanbumpark