欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android开发中类加载器DexClassLoader的简单使用讲解

程序员文章站 2024-02-28 10:22:52
简介 “类装载器”(classloader),顾名思义,就是用来动态装载class文件的。标准的java sdk中有个classloader类,借助此类可以装载需要的cl...

简介
“类装载器”(classloader),顾名思义,就是用来动态装载class文件的。标准的java sdk中有个classloader类,借助此类可以装载需要的class文件,前提是classloader类初始化必须制定class文件的路径。

import关键字引用的类文件和classloader动态加载类的区别:

import引用类的两个特点:

1、必须存在于本地,当程序运行该类时,内部类装载器会自动装载该类。

2、编译时必须在现场,否则编译过程会因找不到引用文件而不能正常编译。

classloader的特点正好于import相反,而且更*灵活。

每一个classloader必须有一个父classloader,在装载class文件时,子classloader会先请求其父classloader加载该文件,只有当其父classloader找不到该文件时,子classloader才会继承装载该类。这是一种安全机制。对于android而言,最终的apk文件包含的是dex类型的文件,dex文件是将class文件重新打包,打包的规则又不是简单地压缩,而是完全对class文件内部的各种函数表,变量表进行优化,产生一个新的文件,即dex文件。因此加载这种特殊的class文件就需要特殊的类加载器dexclassloader。

在java中涉及到的类加载器就是classloader这个类,通过classloader.forname()的方法可以加载我们需要的类,从而实现在运行时动态加载类库的需求。但是在android中直接使用classloader是行不通的,因为classloader加载的java的字节码文件,而在android中使用的是dex格式的字节码,对此android专门提供了一个dexclassloader类来完成动态加载apk的需求。

实例
下面用一个简单的例子来说明一下dexclassloader这个类的使用,这个例子涉及到两个知识点:跨包取资源 & 反射调用方法。 首先建立一个client工程,这个工程很简单,只有一个简单的layout和一个sayhello()的方法。

public class main extends activity {
 
  @override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    this.setcontentview(r.layout.main);
  }
   
  @suppresswarnings("unused")
  private void sayhello(string msg){
    log.d("mmtag",msg);
  }
   
}

接着建立另外一个工程,在这个工程中调用client工程中的view和调用sayhello()方法。在这个类中主要涉及到了dexclassloader这个类的使用。

package com.example.dexclassloaderserver;
 
import java.lang.reflect.method;
import java.util.collections;
import java.util.list;
 
import dalvik.system.dexclassloader;
import android.annotation.suppresslint;
import android.app.activity;
import android.content.intent;
import android.content.pm.activityinfo;
import android.content.pm.packagemanager;
import android.content.pm.resolveinfo;
import android.os.bundle;
import android.util.log;
 
public class mainactivity extends activity {
 
  @override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.activity_main);
    usedexclassloader();
  }
 
  @suppresslint("newapi")
  public void usedexclassloader() {
 
    intent mintent = new intent();
    mintent.setclassname("com.example.dexclassloaderclient",
        "com.example.dexclassloaderclient.mainactivity");
    packagemanager pm = this.getpackagemanager();
    list<resolveinfo> mlist = pm.queryintentactivities(mintent,
        packagemanager.match_default_only);
    resolveinfo info = mlist.get(0);
     
    string apkpath = info.activityinfo.applicationinfo.sourcedir;
    string optpath = this.getcodecachedir().getabsolutepath();
    string libpath = info.activityinfo.applicationinfo.nativelibrarydir;
     
    dexclassloader clsloader = new dexclassloader(apkpath, optpath,
        libpath, this.getclass().getclassloader());
    try {
 
      class cls = clsloader
          .loadclass("com.example.dexclassloaderclient.mainactivity");
      object obj = cls.newinstance();
      method invokemethod = cls.getdeclaredmethod("sayhello",
          new class[] { string.class });
      invokemethod.setaccessible(true);
      invokemethod.invoke(obj, "hello world,dexclassloader");
 
    } catch (exception e) {
      e.printstacktrace();
    }
  }
}


生成的结果为:

i/dex2oat (20250): dex2oat took 1.547s (threads: 4)
 
d/mmtag  (20229): hello world,dexclassloader
 
d/openglrenderer(20229): render dirty regions requested: tru

这样就成功的调用了其他的apk中的方法。