Android动态加载学习总结(二):资源访问

参考资料:
《Android开发艺术探索 –任玉刚》
Android中插件开发篇之—-应用换肤原理解析

博文涉及Demo:
宿主github地址:
https://github.com/codergz/ResourceLoading
插件github地址:
https://github.com/codergz/ResourceLoaderApk

前言:动态加载要解决的三个问题,分别是资源访问,Activity生命周期管理,类加载器的管理。前面一片文章总结了类加载器的学习,里面介绍了一些东西,对于管理类加载器还没有涉及。这篇是资源访问相关的学习,里面有用到类加载器文章中的PathClassLoader,如果对此没有什么了解的话,可以先去看看介绍Android动态加载学习总结(一):类加载器,本篇博文的Demo来自于博文
Android中插件开发篇之—-应用换肤原理解析,对于初步接触,为了更好的学习,我简略了一些内容。并且由于DexClassLoader的一些问题,我将博主的类加载方式更改成了PathClassLoader,既然是PathClassLoader,我们知道,这个类加载器只能加载dex文件,和已安装的apk文件,所以本篇博文的demo是访问已安装apk中的资源。

一、资源访问的问题

动态加载一个插件,如何访问它的资源?在我们宿主程序中,我们通过R文件访问资源,但是去访问插件的资源,明显是行不通的,我们在宿主程序中并没有插件的资源。

如果只是去解决资源访问的问题的话,我们的确有方法,比如提前在宿主程序中预置一份,那么我们就需要在一个插件发布的时候将资源复制到宿主程序。能解决资源访问吗?肯定可以,但是我们为什么要有插件化技术(动态加载)?为了减小宿主程序apk大小,为了降低宿主程序的更新频率,那么去复制到宿主程序明显违背了这项技术最初的目的。

那么我们的解决方案如下:

Context中有两个与资源有关的抽象方法:

public abstract AssetManager getAssets();
public abstract Resources getResources();

我们需要实现这两个方法,实现方式如下:

protected void loadResources(String dexPath) {
        //关于/assets目录下的文件,该目录下的文件不生成ID,如果我们要使用插件中该目录下的文件,我们需要指定文件的路径和文件名
        try {
            AssetManager assetManager = AssetManager.class.newInstance();
            //我们通过调用AssetManager中的addAssetPath方法,可以将一个apk中资源加载到Resources对象中,而addAssetPath是隐藏API,所以通过反射调用
            Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
            //我们将APK的路径传给这个方法,资源便加载到AssetManager中
            addAssetPath.invoke(assetManager, dexPath);
            mAssetManager = assetManager;
        } catch (Exception e) {
            e.printStackTrace();
        }

        Resources superRes = super.getResources();
        superRes.getDisplayMetrics();
        superRes.getConfiguration();
        //通过AssetManger创建一个新的Resources对象,通过这个对象去访问插件资源
        mResources = new Resources(mAssetManager, superRes.getDisplayMetrics(),superRes.getConfiguration());
        mTheme = mResources.newTheme();
        mTheme.setTo(super.getTheme());
    }

    @Override
    public AssetManager getAssets() {
        return mAssetManager == null ? super.getAssets() : mAssetManager;
    }

    @Override
    public Resources getResources() {
        return mResources == null ? super.getResources() : mResources;
    }

    @Override
    public Resources.Theme getTheme() {
        return mTheme == null ? super.getTheme() : mTheme;
    }

}

二、插件的设计

我们已经知道了解决方案,那么开始插件设计,新建一个工程,命名为ResourcesLoaderApk1。

  • MainActivity
public class MainActivity extends Activity {
   

    
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值