The second part of Android plug-in development [dynamic loading apk optimization]

introduction


In the last article , we mentioned the ClassLoader class loader. Through learning, we learned that there are two types of class loaders provided by the system: * PathClassLoader* and * DexClassLoader* . Their differences are:
* PathClassLoader can only load apk in the system /data/data/package name directory;
* DexClassLoader can load jar/apk/dex, and apk that can be loaded from SD card;

When the Android application is started, a PathClassLoader will be created to load the classes in its own apk. The installBundleDexs method we used in the previous article is to load the classes of the plug-in apk into the App's PathClassLoader . Two issues are mentioned at the end of the article:
1. Dex loading is closely related to the system version, which may cause the new version system to fail to load.
2. When the size of the plug-in apk increases, the increase in the number of methods will inevitably lead to long loading. A view on the Internet believes that when the number of methods in the same ClassLoader increases, the time to findClass will become longer, which will affect the search speed.

This article optimizes these two problems by using DexClassLoader .

Demo creation


Modify the loading method in AssetsDexLoader.java to:

private static List<DexClassLoader> bundleDexClassLoaderList = new ArrayList<DexClassLoader>();
private static void installBundleDexs(ClassLoader loader, File dexDir, List<File> files) {
    if (!files.isEmpty()) {
        for (File f : files) {
            DexClassLoader bundleDexClassLoader = new DexClassLoader(
                    f.getAbsolutePath(), dexDir.getAbsolutePath(), null,                    loader);
            bundleDexClassLoaderList.add(bundleDexClassLoader);
        }
    }
}

Added a method to obtain Class:

public static Class<?> loadClass(String className) throws ClassNotFoundException {
    try {
        Class<?> clazz = Class.forName(className);
        if (clazz != null) {
            System.out.println("debug: class find in main classLoader");
            return clazz;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    for (DexClassLoader bundleDexClassLoader : bundleDexClassLoaderList) {
        try {
            Class<?> clazz = bundleDexClassLoader.loadClass(className);
            if (clazz != null) {
                System.out.println("debug: class find in bundle classLoader");
                return clazz;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    throw new ClassCastException(className + " not found exception");
}

[ Demo can refer to here ]

explain


Use the plug-in apk to directly create the system's DexClassLoader . When calling reflectively, first check whether PathClassLoader exists, and if it does not exist, search it in the DexClassLoader list .

Summarize


Using DexClassLoader instead of PathClassLoader can not only solve the problem that Dex loading is closely related to the system version, but also copy the third-party apk to the external SD card to reduce the size of the application after installation. As for the opinion circulating on the Internet that splitting ClassLoader can improve the efficiency of findClass, I don't know whether it is true. But in general it is more appropriate to use DexClassLoader instead of PathClassLoader.

So lightweight plug-in development is more suitable to use DexClassLoader to achieve.

In the next article, we will learn how to share and use resources in plug-in development.

Guess you like

Origin blog.csdn.net/h3c4lenovo/article/details/50730418