• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >Android > Android动态资源加载原理和应用

Android动态资源加载原理和应用

作者:网友 字体:[增加 减小] 来源:互联网 时间:2017-05-26

网友通过本文主要向大家介绍了android 动态添加控件,android 动态权限,android 动态加载布局,android 动态添加布局,android 动态注册广播等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

Android动态资源加载原理和应用


动态加载资源原理

通常我们调用getResources()方法获取资源文件

public Resources getResources() {
    return mResources;
}
mResources是在创建ContextImp对象后的init方法里面创建的
mResources = mPackageInfo.getResources(mainThread);
调用了LoadedApk的getResources方法
public Resources getResources(ActivityThread mainThread) {
    if (mResources == null) {
        mResources = mainThread.getTopLevelResources(mResDir,
                Display.DEFAULT_DISPLAY, null, this);
    }
    return mResources;
}
又调用到了ActivityThread类的getTopLevelResources方法
Resources getTopLevelResources(String resDir, int displayId, Configuration overrideConfiguration, CompatibilityInfo compInfo) {
    ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfiguration, compInfo.applicationScale, compInfo.isThemeable);
    Resources r;
    synchronized (mPackages) {
        // ...
        WeakReference wr = mActiveResources.get(key);
        r = wr != null ? wr.get() : null;
        if (r != null && r.getAssets().isUpToDate()) {
            if (false) {
                Slog.w(TAG, "Returning cached resources " + r + " " + resDir
                        + ": appScale=" + r.getCompatibilityInfo().applicationScale);
            }
            return r;
        }
    }
    
    AssetManager assets = new AssetManager();
    assets.setThemeSupport(compInfo.isThemeable);
    if (assets.addAssetPath(resDir) == 0) {
        return null;
    }

    // ...

    r = new Resources(assets, dm, config, compInfo);
    if (false) {
        Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
                + r.getConfiguration() + " appScale="
                + r.getCompatibilityInfo().applicationScale);
    }

    synchronized (mPackages) {
        WeakReference wr = mActiveResources.get(key);
        Resources existing = wr != null ? wr.get() : null;
        if (existing != null && existing.getAssets().isUpToDate()) {
            // Someone else already created the resources while we were
            // unlocked; go ahead and use theirs.
            r.getAssets().close();
            return existing;
        }
        
        // XXX need to remove entries when weak references go away
        mActiveResources.put(key, new WeakReference(r));
        return r;
    }
}
ResourcesKey使用resDir和其他参数来构造,这里主要是resDir参数,表明资源文件所在的路径。也就是APK程序所在路径。
ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfiguration, compInfo.applicationScale, compInfo.isThemeable);
上面代码的主要逻辑是获取Resources对象,从一个Map变量mActiveResources获取,这个Map维护了ResourcesKey和WeakReference的对应关系。如果不存在就创建它,并且添加到Map中。

因此只要这个Map中包含多个指向不同资源路径的Resources对象或者说我们有指向不同路径的资源的Resources对象,就可以访问多个路径的资源,即有实现访问其他APK文件中的资源的可能。

创建Resources对象的主要逻辑为

AssetManager assets = new AssetManager();
assets.setThemeSupport(compInfo.isThemeable);
    if (assets.addAssetPath(resDir) == 0) {
        return null;
}
 r = new Resources(assets, dm, config, compInfo);
首先创建AssetManager对象,然后用其创建Resources对象。我们以前使用getAssets方法读取assets文件夹中的文件,其实他就是在这里创建的。

AssetManager的构造函数:

public AssetManager() {
    synchronized (this) {
        if (DEBUG_REFS) {
            mNumRefs = 0;
            incRefsLocked(this.hashCode());
        }
        init();
        if (localLOGV) Log.v(TAG, "New asset manager: " + this);
        ensureSystemAssets();
    }
}
init()函数也是一个native函数,其native代码在android_util_AssetManager.cpp中
static void android_content_AssetManager_init(JNIEnv* env, jobject clazz)
{
    AssetManager* am = new AssetManager();
    if (am == NULL) {
        jniThrowException(env, "java/lang/OutOfMemoryError", "");
        return;
    }
    // 将Framework的资源文件添加到AssertManager对象的路径中。
    am->addDefaultAssets();

    ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
    env->SetIntField(clazz, gAssetManagerOffsets.mObject, (jint)am);
}

bool AssetManager::addDefaultAssets()
{
	// /system
    const char* root = getenv("ANDROID_ROOT");
    LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_ROOT not set");

    String8 path(root);
    // kSystemAssets定义为static const char* kSystemAssets = "framework/framework-res.apk";
    // 因此,path为/system/framework/framework-res.apk,framework对应的资源文件
    path.appendPath(kSystemAssets);

    return addAssetPath(path, NULL);
}
到此为止,在创建AssetManager的时候完成了添加framework资源,然后添加本应用的资源路径,即调用addAssetPath方法
/**
 * Add an additional set of assets to the asset manager.  This can be
 * either a directory or ZIP file.  Not for use by applications.  Returns
 * the cookie of the added asset, or 0 on failure.
 * {@hide}
 */
public native final int addAssetPath(String path);
也是一个native方法,其native代码在android_util_AssetManager.cpp中
static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz, jstring path)
{
    ScopedUtfChars path8(env, path);
    if (path8.c_str() == NULL) {
        return 0;
    }
    AssetManager* am = assetManagerForJavaObject(env, clazz);
    if (am == NULL) {
        return 0;
    }

    void* cookie;
    // 在native代码中完成添加资源路径的工作
    bool res = am->addAssetPath(String8(path8.c_str()), &cookie);

    return (res) ? (jint)cookie : 0;
}
可以看到,Resources对象的内部AssetManager对象包含了framework的资源还包含了应用程序本身的资源,因此这也就是为什么能使用getResources函数获得的resources对象来访问系统资源和本应用资源的原因。

 

受此过程的提醒,我们是不是可以自己创建一个Resources对象,让它的包含我们指定路径的资源,就可以实现访问其他的资源了呢?答案是肯定的,利用这个思想可以实现资源的动态加载,换肤、换主题等功能都可以利用这种方法实现。

于是,主要思想就是创建一个AssetManager对象,利用addAssetPath函数添加指定的路径,用其创建一个Resources对象,使用该Resources对象获取该路径下的资源。

需要注意的是addAssetPath函数是hide的,可以使用反射调用。

public void loadRes(String path){
	try {
		assetManager = AssetManager.class.newInstance();
		Method addAssetPath = AssetManager.class.getMethod("addAssetPath", String.class);
		addAssetPath.invoke(assetManager, path);
	} catch (Exception e) {
	}
	resources = new Resources(assetManager, super.getResources().getDisplayMetrics(), super.getResources().getConfiguration());
	// 也可以根据资源获取主题
}
这里的参数path就是APK文件的路径,可以通过以下方式获取
getPackageManager().getApplicationInfo("xxx", 0).sourceDir;
并且还可以重写Context的getResources方法,getAsset方法,提高代码的一致性。
@Override
public Resources getResources() {
	return resources == null ? super.getResources() : resources;
}
@Override
public AssetManager getAssets() {
	return assetManager == null ? super.getAssets() : assetManager;
}
于是在加载了资源之后就可以通过该Resources对象获取对应路径下面的资源了。

动态加载资源

两种不同风格的按钮,默认的是本应用提供的资源,还有一种作为另一个单独的插件APK程序存放在手机的其他路径中,当选择不同的风格时加载不同的图片资源。

\\

插件APK仅仅包含了一些资源文件。

宿主程序的代码具体如下

 

privat



 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • Android动态资源加载原理和应用
  • Android自定义控件系列案例【四】
  • Android自定义控件(二),android自定义控件
  • android自定义控件(二),简易的数值输入器

相关文章

  • 2017-05-26在Android Studio 配置OpenCV 3.1
  • 2017-05-26解析BroadcastReceiver之你需要了解的一些东东,broadcastreceiver
  • 2017-05-26Android中资源文件的Shape使用总结
  • 2017-05-26WEB服务器、应用程序服务器、HTTP服务器区别
  • 2017-05-26Activity按下2次退出,Activity2次退出
  • 2017-05-26Android开发艺术探索学习笔记(三),android艺术探索
  • 2017-05-26Android—基于Socket与上传图片到客户端,
  • 2017-05-26Android新手入门2016(13)--阻塞对话框PopupWindow
  • 2017-05-26Android安全专项-利用androguard分析微信
  • 2017-05-26Android第一天-->布局,android第一天--

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • Android 贝塞尔曲线实现QQ拖拽清除效果
    • Android刷机教程之LG Nexus 5X线刷官方Nexus系列教程,androidnexus
    • 手势事件,html5手势事件
    • Kotlin与Android SDK 集成(KAD 05),kotlinandroid
    • 硅谷社交6--添加联系人--发送添加好友邀请,硅谷6--
    • 算法导论--平摊分析之聚集分析,算法导论--平摊
    • 几个常用的adb命令,常用adb命令
    • andriod 带看括弧的计算器,andriod括弧计算器
    • 9套Android实战经典项目资料分享给大家,9套android
    • nginx rewrite常用示例

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有