前言

动态加载系列文章
Android 动态加载(一) - 基础篇(一)
Android 动态加载(二) - 基础篇(二)
Android 动态加载(三) - 类的加载流程源码分析
Android 动态加载(四) - 简单demo实现
Android 动态加载(五) - 借尸还魂之代理Activity模式
Android 动态加载(六) - 360开源框架DroidPlugin的使用介绍

1. 动态加载?


此处的动态加载指的是从服务器或者其他地方获取 jar包,在运行的时候,加载jar包,然后与app中的jar包互相调用,这里为了方便演示效果,直接把 jar包放在 assets目录下,在程序运行的时候直接从 获取assets下边的jar包,来模拟从服务器端获取

2. 动态加载原理?


Android程序是运行在Dalvik/ART 虚拟机中,而 Dalvik/ART 虚拟机执行 dex文件,dex文件是在 打包apk过程会生成,可以把apk后缀改为 zip,然后解压会看到,如下图所示
打包apk之后不能修改里面的 dex文件,我们只能加载外部SD卡的dex文件或者从网络上边下载 dex文件,通过 DexClassLoader或者PathClassLoader这两个类加载器加载 dex文件中的类,通过反射invoke调用dex类中的方法。

这样做的好处是:可以让用户不用卸载、不用重新安装apk,通过替换外部加载的 dex文件,实现动态加载、动态更新apk的目的。

图片.png

3. Dalvik虚拟机类加载机制


Dalvik虚拟机与JVM虚拟机类加载机制一样,都是在运行程序时候首先把对应的类加载到内存中,Dalvik虚拟机不能直接用ClassLoader加载 .dex文件,Android从ClassLoader派生出两个类,DexClassLoader和PathClassLoader,这两个类是我们加载 dex文件的关键,二者区别在于:

  • DexClassLoader:可以加载jar/apk/dex,可以从SD卡中加载未安装的 apk;
  • PathClassLoader:只能加载已经安装的 apk文件;

所以,下边我们就采用 DexClassLoader来写一个小的示例代码:动态的加载dex文件中的资源文件(其实就是 dex文件中的一个类Dynamic中的一个 sayHello()方法);

这个实例代码是参照网上一个大神的写的

4. 代码如下


项目目录如下,这里为了演示,直接把 dex文件放到 assets下,来模拟从服务器中下载的插件:


图片.png

1>:MainActivity代码如下:

/** * Email: 2185134304@qq.com * Created by Novate 2018/5/11 7:53 * Version 1.0 * Params: * Description:    点击Button按钮 ,加载dex文件中的 class,并调用其中的 sayHello()方法 */public class MainActivity extends AppCompatActivity {    private Dynamic dynamic;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //添加一个点击事件        findViewById(R.id.tx).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                loadDexClass();            }        });    }    /**     * 加载dex文件中的class,并调用其中的sayHello方法     */    private void loadDexClass() {        File cacheFile = FileUtils.getCacheDir(getApplicationContext());        String internalPath = cacheFile.getAbsolutePath() + File.separator + "dynamic_dex.jar";        File desFile = new File(internalPath);        try {            if (!desFile.exists()) {                desFile.createNewFile();                // 从assets目录下 copy 文件到 app/data/cache目录                FileUtils.copyFiles(this, "dynamic_dex.jar", desFile);            }        } catch (IOException e) {            e.printStackTrace();        }        // 这里由于是加载 jar文件,所以采用DexClassLoader        //下面开始加载dex class        DexClassLoader dexClassLoader = new DexClassLoader(internalPath, cacheFile.getAbsolutePath(), null, getClassLoader());        try {            // 类加载器负责读取 .class文件,并把它转为 Class实例,这个实例就表示一个java类            // 加载 dex文件中的Class,格式是:包名+类名(全类名)            Class libClazz = dexClassLoader.loadClass("wangyang.zun.com.mydexdemo.dynamic.impl.IDynamic");            // 调用Class的 newInstance()方法,创建Class的对象 dynamic            // Dynamic 是 dex文件中之前的一个接口类            dynamic = (Dynamic) libClazz.newInstance();            if (dynamic != null)                Toast.makeText(this, dynamic.sayHelloy(), Toast.LENGTH_LONG).show();        } catch (Exception e) {            e.printStackTrace();        }    }}

2>:FileUtils工具类如下:

/** * Email: 2185134304@qq.com * Created by Novate 2018/5/11 7:53 * Version 1.0 * Params: * Description:    从assets目录下 copy 文件到 app/data/cache目录 */public class FileUtils {    public static void copyFiles(Context context, String fileName, File desFile) {        InputStream in = null;        OutputStream out = null;        try {            in = context.getApplicationContext().getAssets().open(fileName);            out = new FileOutputStream(desFile.getAbsolutePath());            byte[] bytes = new byte[1024];            int i;            while ((i = in.read(bytes)) != -1)                out.write(bytes, 0 , i);        } catch (IOException e) {            e.printStackTrace();        }finally {            try {                if (in != null)                    in.close();                if (out != null)                    out.close();            } catch (IOException e) {                e.printStackTrace();            }        }    }    public static boolean hasExternalStorage() {        return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);    }    /**     * 获取缓存路径     *     * @param context     * @return 返回缓存文件路径     */    public static File getCacheDir(Context context) {        File cache;        if (hasExternalStorage()) {            cache = context.getExternalCacheDir();        } else {            cache = context.getCacheDir();        }        if (!cache.exists())            cache.mkdirs();        return cache;    }}

3>:Dynamic接口如下,与 dex文件中类一样:

public interface Dynamic {    String sayHelloy();}

具体代码已上传至github:
https://github.com/shuai999/MyDexDemo.git

更多相关文章

  1. Android(安卓)动态加载(六) - 360开源框架DroidPlugin的使用介绍
  2. Android下载文件(一)下载进度&断点续传
  3. 【Android布局】在程序中设置android:gravity 和 android:layo..
  4. 自定义android开机动画
  5. 创建android文件系统(Root file system)
  6. android 的一些小知识
  7. Android有用代码片段(四)
  8. Android(安卓)android:gravity属性介绍及效果图
  9. Android(安卓)之不要滥用 SharedPreferences(下)

随机推荐

  1. Android(安卓)简单的Http框架
  2. Android — 制作悬浮窗口
  3. Android Media Scanner Process
  4. android折叠展开列表测试
  5. android Dialog无法获取窗口问题闪退
  6. Android Handler leak 分析及解决办法
  7. Android当方法总数超过64K时(Android Stu
  8. Android 子线程中更新UI
  9. android ViewPager 使用方法
  10. Unity 3.3增加了对Android的支持