android动态加载外部资源文件

项目需求:

进入程序时下载不同的资源文件包对应不同的图片、文字和颜色(有点类似替换主题)

实现原理:

通过ClassLoader获取apk中资源的.R返回资源id,创建Resources对象设置资源id得到具体的图片、文字和颜色

效果图:

在这里插入图片描述

核心代码:

public class LoadResourceUtil {
    private static final String TAG = LoadResourceUtil.class.getSimpleName();
    private static final String RESOURCE_TYPE_DRAWABLE = "drawable";// 图片
    private static final String RESOURCE_TYPE_STRING = "string";// 文字
    private static final String RESOURCE_TYPE_COLOR = "color";// 颜色

    private Context mContext;
    private String mDexDir;// 资源路径
    private static LoadResourceBean mResourceLoadBean;// 资源对象

    /**
     * 静态内部类
     */
    private static class LoadResourceUtilHolder {
        private static final LoadResourceUtil INSTANCE = new LoadResourceUtil();
    }

    /**
     * 单例模式
     * @return
     */
    public static final LoadResourceUtil getInstance() {
        return LoadResourceUtilHolder.INSTANCE;
    }

    /**
     * 初始化
     *
     * @param context
     * @param resourcePath 本地资源路径
     */
    public void init(Context context, String resourcePath) {
        Log.e(TAG, "init");
        mContext = context.getApplicationContext();
        File dexDir = mContext.getDir("dex", Context.MODE_PRIVATE);
        if (!dexDir.exists()) {
            dexDir.mkdir();
        }
        mDexDir = dexDir.getAbsolutePath();
        mResourceLoadBean = getResourceLoad(resourcePath);
    }

    /**
     * 加载未安装资源包
     *
     * @param resourcePath 未安装资源包
     * @return
     */
    public LoadResourceBean getResourceLoad(String resourcePath) {
        Log.e(TAG, "getLoadResource");
        LoadResourceBean resourceLoadBean = null;
        // 获取未安装APK的PackageInfo
        PackageInfo info = queryPackageInfo(resourcePath);
        if (info != null) {
            // 获取成功
            try {
                // 创建AssetManager实例
                AssetManager assetManager = AssetManager.class.newInstance();
                Class cls = AssetManager.class;
                Method method = cls.getMethod("addAssetPath", String.class);
                // 反射设置资源加载路径
                method.invoke(assetManager, resourcePath);
                // 构造出正确的Resource
                Resources resources = new Resources(assetManager, mContext.getResources().getDisplayMetrics(),
                        mContext.getResources().getConfiguration());
                resourceLoadBean = new LoadResourceBean();
                resourceLoadBean.setResources(resources);
                resourceLoadBean.setPackageName(info.packageName);
                // 设置正确的类加载器, 因为需要去加载R文件
                resourceLoadBean.setClassLoader(new DexClassLoader(resourcePath, mDexDir, null,
                        mContext.getClassLoader()));
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        return resourceLoadBean;
    }

    /**
     * 重新加载未安装应用资源包
     *
     * @param resourcePath 未安装资源包路径
     * @return
     */
    public void setLoadResource(String resourcePath) {
        // 保存资源包路径 下次进入程序默认加载
        SharedPreferencesUtil.put(SPConsts.SP_RESOURCE_PATH, resourcePath);
        mResourceLoadBean = getResourceLoad(resourcePath);
    }

    /**
     * 获取未安装资源包信息
     *
     * @param resourcePath 未安装资源包路径
     * @return
     */
    private PackageInfo queryPackageInfo(String resourcePath) {
        return mContext.getPackageManager().getPackageArchiveInfo(resourcePath, PackageManager.GET_ACTIVITIES);
    }

    /**
     * 获取未安装资源Drawable
     *
     * @param fieldName 资源名
     * @return
     */
    public Drawable getDrawable(String fieldName) {
        Drawable drawable = null;
        int resourceID = getResourceID(mResourceLoadBean.getPackageName(), RESOURCE_TYPE_DRAWABLE, fieldName);
        if (mResourceLoadBean != null) {
            drawable = mResourceLoadBean.getResources().getDrawable(resourceID);
        }
        return drawable;
    }

    /**
     * 获取未安装资源String
     *
     * @param fieldName 资源名
     * @return
     */
    public String getString(String fieldName) {
        String string = null;
        int resourceID = getResourceID(mResourceLoadBean.getPackageName(), RESOURCE_TYPE_STRING, fieldName);
        if (mResourceLoadBean != null) {
            string = mResourceLoadBean.getResources().getString(resourceID);
        }
        return string;
    }

    /**
     * 获取未安装资源color
     *
     * @param fieldName 资源名
     * @return
     */
    public int getColor(String fieldName) {
        int color = 0;
        int resourceID = getResourceID(mResourceLoadBean.getPackageName(), RESOURCE_TYPE_COLOR, fieldName);
        if (mResourceLoadBean != null) {
            color = mResourceLoadBean.getResources().getColor(resourceID);
        }
        return color;
    }

    /**
     * 获取未安装资源的ID
     *
     * @param packageName 包名
     * @param type        资源类型
     * @param fieldName   资源名
     * @return
     */
    public int getResourceID(String packageName, String type, String fieldName) {
        int resID = 0;
        String rClassName = packageName + ".R$" + type;
        try {
            Class cls = mResourceLoadBean.getClassLoader().loadClass(rClassName);
            resID = (Integer) cls.getField(fieldName).get(null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resID;
    }
}

注意事项:

新建资源文件项目时不用选activity直接选择Add No Activity即可
在这里插入图片描述
添加完点击Build->Make Project生成apk
在这里插入图片描述
生成的apk在下图中
在这里插入图片描述
记住不要忘了添加读取权限

下载地址:LoadResourceDemo
github地址:LoadResourceDemo

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤独的冥王星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值