Android Plugin (ii): Use Dexclassloader to dynamically load apk in assets

Source: Internet
Author: User

Android Plugin (ii): Using Dexclassloader to dynamically load APK introduction in assets

In a previous blog post, we can use Multidex.java to load an offline APK file. It is important to note that the classes in the APK are loaded into the current pathclassloader, and if there are too many apk files, the ANR situation may occur. So, can we use Dexclassloader to load the APK? Of course you can! First look at the doc documentation.

A class loader that loads classes from .jar and .apk files containing a classes.dex entry. This can be used to execute code not installed as part of an application.

In other words, dexclassloader can load a compressed package containing classes.dex files, either as a jar or as an apk. So what do I need to be aware of when loading an offline APK file?

    • 1.DexClassLoader Method of Construction:
      Dexclassloader (String Dexpath, String optimizeddirectory, String LibraryPath, ClassLoader parent)

    • 2. Private Directory
      This class loader requires a application-private, writable directory to cache optimized classes.

Knowing the above two points, we can dynamically load the APK in the assets according to the parameters required by Dexclassloader.

Source
Bundleclassloadermanager

This class is primarily responsible for managing these dexclassloader, first, we define a class called Bundledexclassloader, which inherits from Dexclassloader, which is used to load the offline APK file. Each apk file corresponds to a bundledexclassloader, and Bundleclassloadermanager saves a list, which is used to find the class when it is loaded. The specific code is as follows:

 Packagenet.mobctrl.hostapk;ImportJava.io.File;ImportJava.io.FilenameFilter;ImportJava.util.ArrayList;ImportJava.util.List;ImportAndroid.annotation.TargetApi;ImportAndroid.content.Context;ImportAndroid.os.Build;/** * @Author Zheng haibo * @PersonalWebsite http://www.mobctrl.net * @version $Id: Bundle Classloadermanager.java, v 0.1 December 11, 2015 PM 7:30:59 * MOCHUAN.ZHB EXP $ * @Description  */@TargetApi(Build.version_codes. Ice_cream_sandwich) Public  class bundleclassloadermanager {     Public StaticList<bundledexclassloader> bundledexclassloaderlist =NewArraylist<bundledexclassloader> ();/** * Load APK file in assets * @param Context * *     Public Static void Install(Context context) {assetsmanager.copyallassetsapk (context);//Get a list of Dex filesFile Dexdir = Context.getdir (Assetsmanager.apk_dir, context.mode_private); file[] Szfiles = Dexdir.listfiles (NewFilenameFilter () {@Override             Public Boolean Accept(File dir, String filename) {returnFilename.endswith (Assetsmanager.file_filter); }        }); for(File f:szfiles) {System.out.println ("Debug:load file:"+ F.getname ()); Bundledexclassloader Bundledexclassloader =NewBundledexclassloader (F.getabsolutepath (), Dexdir.getabsolutepath (),NULL, Context.getclassloader ());        Bundledexclassloaderlist.add (Bundledexclassloader); }    }/** * Find class * * @param className * @return * @throws classnotfoundexcept Ion * /     Public StaticClass<?>LoadClass(Context context,string ClassName)throwsclassnotfoundexception {Try{class<?> clazz = Context.getclassloader (). LoadClass (ClassName);if(Clazz! =NULL) {System.out.println ("Debug:class Find in main ClassLoader");returnClazz; }        }Catch(Exception e)        {E.printstacktrace (); } for(Bundledexclassloader bundledexclassloader:bundledexclassloaderlist) {Try{class<?> clazz = Bundledexclassloader.loadclass (className);if(Clazz! =NULL) {System.out.println ("Debug:class Find in bundle ClassLoader");returnClazz; }            }Catch(Exception e)            {E.printstacktrace (); }        }Throw NewClassCastException (ClassName +"Not found exception"); }}

Note the point:

    • 1.install method
      The install method is mainly to copy the assets apk into a private directory, then traverse the private directory, use Bundledexclassloader to load the apk file, and then save these bundledexclassloader in the array.

    • 2.loadClass method
      The method first looks for the required class from the current ClassLoader, and if not found, traverses the lookup from the list.

Demo Run

In Mainactivity, we can call methods in the APK class in the following ways:

      Private void loadapk() {Try{class<?> clazz = Bundleclassloadermanager.loadclass (Getapplicationcontext (),"Net.mobctrl.normal.apk.Utils");            constructor<?> Constructor = Clazz.getconstructor ();            Object bundleutils = Constructor.newinstance (); Method Printsummethod = Clazz.getmethod ("Printsum", Context.class,int. class,int. class, String.class); Printsummethod.setaccessible (true); Integer sum = (integer) printsummethod.invoke (Bundleutils, Getapplicationcontext (),Ten, -,"Calculation Results"); System.out.println ("debug:sum ="+ sum); }Catch(ClassNotFoundException e)        {E.printstacktrace (); }Catch(SecurityException e)        {E.printstacktrace (); }Catch(Nosuchmethodexception e)        {E.printstacktrace (); }Catch(IllegalArgumentException e)        {E.printstacktrace (); }Catch(Instantiationexception e)        {E.printstacktrace (); }Catch(Illegalaccessexception e)        {E.printstacktrace (); }Catch(InvocationTargetException e)        {E.printstacktrace (); }    }

Unlike Multidex, we load classes by Bundleclassloadermanager instead of the current ClassLoader.

Improvement Programme

As the LoadClass method in Bundleclassloadermanager, in fact we create a ClassLoader object, by overriding the current ClassLoader Findclass method, Then in the Findclass method of override, the class is first looked up from the current ClassLoader and then traversed from the bundledexclassloader, so that the classes in the bundle can be called in the host project. You can also call a class in host in the bundle.

       new ClassLoader(super.getClassLoader()) {            @Override            protectedfindClass(String className)                    throws ClassNotFoundException {                Class clazz = BundleClassLoaderManager.loadClass(context,className);                ifnull) {                    thrownew ClassNotFoundException(className);                }                return clazz;            }        };
Summarize

The previous blog and this blog post will be loaded with classes. If the class you need to load is a tool class, there is no need to load resources, and so on, the above scenario is fine. But what if the loaded class is a UI such as fragment or activity, and you need to reference the resource file?

Next blog post: Offline loading of Android resources.

Reference

1.BaseDexClassLoader Source Code

Android Plugin (ii): Use Dexclassloader to dynamically load apk in assets

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.