Android资源访问机制

AndroidResourceManager:Android Resource Manager应用程序具有许多功能,例如图像调整大小,颜色,尺寸和代码分析,以管理和分析您的应用程序资源 Android资源管理器 作为Android开发人员的跨平台工具,AndroidResourceManager-ARM为您提供五项主要服务 图像调整服务 您可以轻松地调整可绘制,mipmap或普通图像的大小,不受大小限制,默认大小为7,即ldpi,mdpi,tvdpi,hdpi,xhdpi,xxhdpi,xxxhdpi,还可以添加或删除大小并预览图像。 关键字搜寻服务 选择项目目录并放入搜索关键字后,ARM将在所有Java,Kotlin,C ++,Xml和常规文本文件中搜索该关键字,并向您显示搜索的详细信息,文件名,开始和结束位置。 颜色分析服务 选择项目目录并单击搜索后,ARM将在布局资源中搜索每个十六进制颜色值并将其显示给您,因此您应将它们放在color.xml中并清除资源 尺寸分析服务 选择项目目录并单击搜索后,ARM会在布局资源中搜索每个尺寸值并将其显示给您,因此您应将它们放在d 立即下载

Android经常使用getResources()方法获取app的一些资源,getResource()方法是Context接口的方法,具体是有ContextImpl类实现的,Activity、Service、Application都是继承自Context接口。

资源获取的方式是context.getResources,而真正的实现位于ContextImpl中的getResources方法,在ContextImpl中有一个私有成员Resources mResources,getResources方法返回的结果就是该对象成员,mResources的赋值则是在ContextImpl的构造函数中:

private ContextImpl(ContextImpl container, ActivityThread mainThread,
      LoadedApk packageInfo, IBinder activityToken, UserHandle user, Boolean restricted,
      Display display, Configuration overrideConfiguration) {
	.......
	  Resources resources = packageInfo.getResources(mainThread);
	if (resources != null) {
		if (activityToken != null
		              || displayId != Display.DEFAULT_DISPLAY
		              || overrideConfiguration != null
		              || (compatInfo != null && compatInfo.applicationScale
		                      != resources.getCompatibilityInfo().applicationScale)) {
			resources = mResourcesManager.getTopLevelResources(packageInfo.getResDir(),
			                  packageInfo.getSplitResDirs(), packageInfo.getOverlayDirs(),
			                  packageInfo.getApplicationInfo().sharedLibraryFiles, displayId,
			                  overrideConfiguration, compatInfo, activityToken);
		}
	}
	mResources = resources;

而mPackageInfo是LoadedAPK类,所以就是调用到LoadedAPK的getResource(ActivityThread)方法中:

public Resources  getResources(ActivityThread mainThread) {
	if (mResources == null) {
		mResources = mainThread.getTopLevelResources(mResDir, mSplitResDirs, mOverlayDirs,
		                 mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, null, this);
	}
	return mResources;
}

而ActivityThread类型的mainThread一个应用中只有一个,函数调用如下

Resources getTopLevelResources(String resDir, String[] splitResDirs, String[] overlayDirs,
       String[] libDirs, int displayId, Configuration overrideConfiguration,
       LoadedApk pkgInfo) {
	return mResourcesManager.getTopLevelResources(resDir, splitResDirs, overlayDirs, libDirs,
	           displayId, overrideConfiguration, pkgInfo.getCompatibilityInfo(), null);
}

下面看一下ResourcesManager的getTopLevelResources方法,

public Resources getTopLevelResources(String resDir, String[] splitResDirs,
        String[] overlayDirs, String[] libDirs, int displayId,
        Configuration overrideConfiguration, CompatibilityInfo compatInfo, IBinder token) {
	final float scale = compatInfo.applicationScale;
	ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfiguration, scale, token);
	Resources r;
	synchronized (this) {
		// Resources is app scale dependent.
		if (false) {
			Slog.w(TAG, "getTopLevelResources: " + resDir + " / " + scale);
		}
		WeakReference<Resources> wr = mActiveResources.get(key);
		r = wr != null ? wr.get() : null;
		//if (r != null) Slog.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate());
		if (r != null && r.getAssets().isUpToDate()) {
			if (false) {
				Slog.w(TAG, "Returning cached resources " + r + " " + resDir
				                        + ": appScale=" + r.getCompatibilityInfo().applicationScale);
			}
			return r;
		}
	}
	//if (r != null) {
	//    Slog.w(TAG, "Throwing away out-of-date resources!!!! "
	//            + r + " " + resDir);
	//}
	AssetManager assets = new AssetManager();
	// resDir can be null if the 'android' package is creating a new Resources object.
	// This is fine, since each AssetManager automatically loads the 'android' package
	// already.
	if (resDir != null) {
		if (assets.addAssetPath(resDir) == 0) {
			return null;
		}
	}
	if (splitResDirs != null) {
		for (String splitResDir : splitResDirs) {
			if (assets.addAssetPath(splitResDir) == 0) {
				return null;
			}
		}
	}
	if (overlayDirs != null) {
		for (String idmapPath : overlayDirs) {
			assets.addOverlayPath(idmapPath);
		}
	}
	if (libDirs != null) {
		for (String libDir : libDirs) {
			if (assets.addAssetPath(libDir) == 0) {
				Slog.w(TAG, "Asset path '" + libDir +
				                        "' does not exist or contains no resources.");
			}
		}
	}
	//Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
	DisplayMetrics dm = getDisplayMetricsLocked(displayId);
	Configuration config;
	Boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
	final Boolean hasOverrideConfig = key.hasOverrideConfiguration();
	if (!isDefaultDisplay || hasOverrideConfig) {
		config = new Configuration(getConfiguration());
		if (!isDefaultDisplay) {
			applyNonDefaultDisplayMetricsToConfigurationLocked(dm, config);
		}
		if (hasOverrideConfig) {
			config.updateFrom(key.mOverrideConfiguration);
		}
	} else {
		config = getConfiguration();
	}
	r = new Resources(assets, dm, config, compatInfo, token);
	if (false) {
		Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
		                + r.getConfiguration() + " appScale="
		                + r.getCompatibilityInfo().applicationScale);
	}
	synchronized (this) {
		WeakReference<Resources> 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<Resources>(r));
		return r;
	}
}

这个方法的思想是这样的:在ResourcesManager中,所有的资源对象都被存储在ArrayMap中,首先根据当前的请求参数去查找资源,如果找到了就返回;否则就创建一个资源对象放到ArrayMap中。为什么会有多个资源对象,因为res下可能存在多个适配不同设备、不同分辨率、不同系统版本的目录,按照android系统的设计,不同设备在访问同一个应用的时候访问的资源可以不同,比如drawable-hdpi和drawable-xhdpi就是典型的例子。

根据上述代码和ResourcesManager采用单例模式,这样就保证了不同的ContextImpl访问的是同一套资源,注意,这里说的同一套资源未必是同一个资源,因为资源可能位于不同的目录,但它一定是我们的应用的资源。或许这样来描述更准确,在设备参数和显示参数不变的情况下,不同的ContextImpl访问到的是同一份资源。设备参数不变是指手机的屏幕和android版本不变,显示参数不变是指手机的分辨率和横竖屏状态。也就是说,尽管Application、Activity、Service都有自己的ContextImpl,并且每个ContextImpl都有自己的mResources成员,但是由于它们的mResources成员都来自于唯一的ResourcesManager实例,所以它们看似不同的mResources其实都指向的是同一块内存(C语言的概念),因此,它们的mResources都是同一个对象(在设备参数和显示参数不变的情况下)。在横竖屏切换的情况下且应用中为横竖屏状态提供了不同的资源,处在横屏状态下的ContextImpl和处在竖屏状态下的ContextImpl访问的资源不是同一个资源对象。

public static ResourcesManager getInstance() {
	synchronized (ResourcesManager.class) {
		if (sResourcesManager == null) {
			sResourcesManager = new ResourcesManager();
		}
		return sResourcesManager;
	}
}

Resources对象的创建过程

通过阅读Resources类的源码可以知道,Resources对资源的访问实际上是通过AssetManager来实现的,那么如何创建一个Resources对象呢,有人会问,我为什么要去创建一个Resources对象呢,直接getResources不就可以了吗?我要说的是在某些特殊情况下你的确需要去创建一个资源对象,比如动态加载apk。很简单,首先看一下它的几个构造方法:

public Resources (AssetManager assets, DisplayMetrics metrics, Configuration config) {
	this(assets, metrics, config, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
}

public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config,
         CompatibilityInfo compatInfo, IBinder token) {
	mAssets = assets;
	mMetrics.setToDefaults();
	if (compatInfo != null) {
		mCompatibilityInfo = compatInfo;
	}
	mToken = new WeakReference<IBinder>(token);
	updateConfiguration(config, metrics);
	assets.ensureStringBlocks();
}

从简单起见,我们应该采用第一个public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config)

它接受3个参数,第一个是AssetManager,后面两个是和设备相关的配置参数,我们可以直接用当前应用的配置就好,所以,问题的关键在于如何创建AssetManager,下面请看分析,为了创建一个我们自己的AssetManager,我们先去看看系统是怎么创建的。还记得getResources的底层实现吗,在ResourcesManager的getTopLevelResources方法中有这么两句:

    AssetManager assets = new AssetManager();  
    if (assets.addAssetPath(resDir) == 0) {  
        return null;  
    }  

这两句就是创建一个AssetManager对象,后面会用这个对象来创建Resources对象,AssetManager就是这么创建的,assets.addAssetPath(resDir)这句话的意思是把资源目录里的资源都加载到AssetManager对象中,具体的实现在jni中,大家感兴趣自己去了解下。而资源目录就是我们的res目录,当然resDir可以是一个目录也可以是一个zip文件。有没有想过,如果我们把一个未安装的apk的路径传给这个方法,那么apk中的资源是不是就被加载到AssetManager对象里面了呢?事实证明,的确是这样。addAssetPath方法的定义如下,注意到它的注释里面有一个{@hide}关键字,这意味着即使它只是给Framework自己使用的,因此只能通过反射来调用。

public final int addedAssetPath(String path) {
	synchronized (this) {
		int res = addAssetPathNative(path);
		makeStringBlocks(mStringBlocks);
		return res;
	}
}

有了AssetManager对象后,我们就可以创建自己的Resources对象了,代码如下:

try {
	AssetManager assetManager = AssetManager.class.newInstance();
	Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
	addAssetPath.invoke(assetManager, mDexPath);
	mAssetManager = assetManager;
}
catch (Exception e) {
	e.printStackTrace();
}
Resources currentRes = this.getResources();
mResources = new Resources(mAssetManager, currentRes.getDisplayMetrics(), currentRes.getConfiguration());

有了Resources对象,我们就可以通过Resources对象来访问里面的各种资源了,通过这种方法,我们可以完成一些特殊的功能,比如换肤、换语言包、动态加载apk等。

另外,除了通过Context的getResource()方法访问android应用的资源外,还可以通过PackageManger来获取。

PackageManager本身只是一个抽象类,具体是由ApplicationPackageManager实现的,获取了PackageManager以后就可以调用PacakageManager的getResourcesForApplication(ApplicationInfo app)来获取Resources对象了,代码如下:

public Resources getResourcesForApplication(
     ApplicationInfo app) throws NameNotFoundException {
	if (app.packageName.equals("system")) {
		return mContext.mMainThread.getSystemContext().getResources();
	}
	final Boolean sameUid = (app.uid == Process.myUid());
	Resources r = mContext.mMainThread.getTopLevelResources(
	             sameUid ? app.sourceDir : app.publicSourceDir,
	             sameUid ? app.splitSourceDirs : app.splitPublicSourceDirs,
	             app.resourceDirs, app.sharedLibraryFiles, Display.DEFAULT_DISPLAY,
	             null, mContext.mPackageInfo);
	if (r != null) {
		return r;
	}
	throw new NameNotFoundException("Unable to open " + app.publicSourceDir);
}

其实PackageManager方式同Context方式最终还是一致的,都是通过mMainThread.getTopLevelResource()方法来获取Resources的。

Python实战:超分辨率图像质量评估全攻略——PSNR、SSIM、LPIPS与NIQE的代码实现与优化 本文详细介绍了在Python中实现超分辨率图像质量评估的完整方案,涵盖PSNR、SSIM、LPIPS和NIQE四大核心指标。通过模块化代码设计、多进程并行处理和GPU加速优化,帮助开发者构建高效、可扩展的评估系统,并提供了实战避坑指南与结果解读方法。 阅读详情

相关推荐

【漏洞修复】Diffie-Hellman Key Agreement Protocol 资源管理错误漏洞(CVE-2002-20001)

Diffie-Hellman Key Agreement Protocol 存在安全漏洞,远程攻击者可以发送实际上不是公钥的任意数字,并触发服务器端DHE模幂计算。

我的博客 1万+

ResourcesManager资源管理

一个Activity在初始化的时候会调用attach方法绑定一个ContextImpl对象,这个ContextImpl对象会一直到该页面销毁,一直保持不变,上面我们知道一个ContextImpl对象中会持有一个Resources对象,当我们切换语言的时候页面的时候ContextImpl是没有变的,要保证app资源的正确性,这个时候就要替换掉ContextImpl对象里面的Resources对象,这也就是一个Activity可能有多个Resources的原因。ResourcesManager中的。

842

专有钉钉小程序(浙政钉)开发搭建流程总览

最近公司有一个项目要做浙政钉,让我来负责做。靠,我一脸懵,开发了两年多不知道浙政钉是啥,感觉我眼界还是低了。然后就去百度、同事问了一圈才知道就是个钉钉小程序嘛,然后发布到浙政钉上了。就搭建项目跑起来我都肥了很多事,中间走了很多坑。正好领导让我写《钉钉小程序前端开发流程》,这想着也写个博客吧。下面就是整个流程及我所遇到的坑!

m0_53910290的博客 6355

39、Android编写应用-使用Resource Manager管理应用的界面资源

使用 Resource Manager 管理应用的界面资源 Resource Manager 是一个用于导入、创建、管理和使用应用资源的工具窗口。您可以通过以下方式打开该工具窗口:从菜单栏中依次选择View > Tool Windows > Resource Manager,或在左侧栏中选择Resource Manager。 图 1:Resource Manager 点击Add图标可向项目添加新的资源。您可以添加图像资源、矢量资源、字体、资源文件和值,也可以将资源导入到...

w00347190的博客 1641

flink新版本无bat启动文件的解决办法

flink

6 4932

Cadence Allegro安装全攻略:从准备到优化的完整指南

本文提供了一份详尽的Cadence Allegro安装教程,涵盖从系统准备、硬件要求到获取安装文件的完整前期工作。指南逐步解析了自定义安装、路径选择及核心组件配置,并重点阐述了许可证服务器的环境变量设置与服务启动等关键激活步骤,最后给出了首次启动验证、个性化优化及常见问题排错方案,助您高效完成安装与配置。

weixin_29243063的博客 185

Android资源管理框架-------之资源的缓存和preload(十)

        对于integer、bool等values类型的资源还好,对于比较大的资源比如Drawable等,如果我们每次去获取,都要从resources.arsc中查寻资源相关的信息(对于Drawable来说就是资源路径),然后在根据资源信息(路径)去加载图片,那么这个过程将会非常耗时。所以,为了加快资源的获取速...

大勇的专栏 2321

LABVIEW学习之MODBUS-TCP通讯

LABVIEW学习之MODBUS-TCP通讯 1,MODBUS-TCP通讯介绍: MODBUS通讯是工业上面经常用到的一种通讯协议。该协议的原理及介绍不在此累述,下面直接介绍LABVIEW对此协议的应用。 2,MODBUS通讯所需的函数: 安装了DSC模块之后可以在数据通信内找到相关函数 3 ,主VI 主要思路就是使用状态机来进行连接 读取 写入 断开。使用枚举类型来选择状态: 1,连接 2,写入多个M继电器: 3,写入单个M继电器 4,写入双字节D...

风动9527的博客 2万+

Android 中的Resource Manager的学习

ResourceManager是Android资源管理的核心,开发者需熟练使用其API及开发工具(如Android Studio的Resource Manager)来优化资源管理。理解资源编译机制与动态加载流程,有助于实现高效、兼容性强的应用。对于复杂场景(如插件化、动态主题),可结合第三方工具或系统底层API扩展功能。

m0_65342408的博客 806

【存算一体架构实战】四、突破编译壁垒:手把手实现AI模型到存算硬件的自动映射

摘要:存算一体硬件的性能优势难以充分释放,核心瓶颈在于传统编译器无法高效适配"计算-存储融合"的新型架构。本文系统剖析传统编译流程在存算硬件上的三大痛点:数据布局不匹配导致90%带宽浪费、算子映射效率低使硬件利用率不足30%、缺乏专用优化_pass导致延迟居高不下。通过构建MLIR-PIM编译框架,实现从AI模型到存算硬件的全自动化映射,核心流程包括:TensorFlow模型→MLIR Dialect转换→存算优化_pass→硬件指令生成。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 241

Y-Branch and a closed y-branch loop

双臂后面的区域,我们将它的双臂使用一个波导进行了连接,使得它本身形成了一个闭合回路,因此,该结构被称作。它们均是用来对经过它们的光束能量进行分割的一种器件。首先,我们知道一点,在光波导层面,今天给大家介绍一下,什么是。

u011699626的博客 627

Android资源知识(一)之Resources概览

资源(Resources)是指应用中的图片、媒体文件、字符串、颜色值等。Android程序员在开发过程中随时要和Resources打交道,比如R.layout.activity_main、@string/hello…… 一、Android应用资源的构成 Android系统提供了一套强大的资源管理框架Resources和AssetManager,下面我们从工程目录结构来学习下Android应用资源体...

极客神殿 1692

YOLOv8改进,YOLOv8添加DCNv3可变性卷积,无需编译

DCNv3在DCNv2版本上进行了改进,上一期我们在YOLOv8中添加了DCNv2,这一期我们将添加DCNv3,DCNv3代码详解可以参考链接:代码详解——可变形卷积(DCNv3)

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 5020

android 资源访问机制,安卓核心基础知识梳理之Android消息处理机制

Looper、Message、Handler的关系当我们的Android应用程序的进程一创建的时候,系统就给这个进程提供了一个Looper,Looper是一个死循环,它内部维护这个一个消息队列。Looper不停地从消息队列中取消息(Message),取到消息就发送给了Handler,最后Handler根据接收到的消息去修改UI。Handler的sendMessage方法就是将消息添加到消息队列中。...

weixin_35046143的博客 147

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

android系统资源访问机制的探讨,Android资源加载机制

获取资源的方式先通过Context.getResources();获取Resources对象,有了Resources对象就可以访问各种资源了。资源加载机制通过Context获取Resources,实际是通过ContextImpl的getResources()方法;ContextImpl内部有一个成员mResources,它就是getResources()方法返回的结果;Context.getRes...

weixin_29736885的博客 255

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Android资源访问机制—获取Resources对象

Android资源访问机制—获取Resources对象

weixin_44128805的博客 2486

Android 开发 - Android 模块构建机制与资源访问机制

Android 开发 - Android 模块构建机制、资源访问机制

weixin_52173250的博客 247

Android资源访问机制--getResource()

在开发当中需要引用程序资源,如工程之中assets和res目录下的图片、layout、values等或者需要系统内置的资源。 获取Resources的过程: (1)将framework/framework-res.apk和应用资源apk装载为Resources对象。 (2)获取Resources对象 获取Resources对象有两种方式,第一种通过Context,第二种通过PackageM...

Axe_Ishmael 4507

Android之资源访问机制

我们知道在开发中,需要应用程序资源,如应用工程中assets和res目录下的图片,layout,values等,或者需要系统内置的资源。我们获取这些资源的入口对象都是Resources对象。   获取Resources的过程: (1)将framework/framework-res.apk和应用资源apk装载为Resources对象。 (2)获取Resources对象 获取Resou

way 4125

android系统资源访问机制的探讨,Android_资源访问机制

我们知道在开发中,需要应用程序资源,如应用工程中assets和res目录下的图片,layout,values等,或者需要系统内置的资源。我们获取这些资源的入口对象都是Resources对象。获取Resources的过程:(1)将framework/framework-res.apk和应用资源apk装载为Resources对象。(2)获取Resources对象获取Resources对象有两种方式,第...

weixin_30726605的博客 253

android资源访问机制

文章出处:http://blog.youkuaiyun.com/shif 前言:一般应用开发的时候,都会通过getResources().getXXX()来获取资源信息,例如getDrawable、getDimension、getString等,这里我小结了资源加载的机制以及加载过程的实现。

私房菜 3410

(转)Android资源访问机制——获取Resources对象

转载自: Android资源访问机制——获取Resources对象 我们知道在开发中,需要应用程序资源,如应用工程中assets和res目录下的图片,layout,values等,或者需要系统内置的资源。我们获取这些资源的入口对象都是Resources对象,并博文将分析如何获取Resources对象。 获取Resources的过程: (1)将framework/framework-r...

weixin_30821731的博客 88

Android资源访问机制——获取Resources对象

我们知道在开发中,需要应用程序资源,如应用工程中assets和res目录下的图片,layout,values等,或者需要系统内置的资源。我们获取这些资源的入口对象都是Resources对象,并博文将分析如何获取Resources对象。   获取Resources的过程: (1)将framework/framework-res.apk和应用资源apk装载为Resources对象。 (2)...

willsunforitcast的博客 944

Android_资源访问机制

我们知道在开发中,需要应用程序资源,如应用工程中assets和res目录下的图片,layout,values等,或者需要系统内置的资源。我们获取这些资源的入口对象都是Resources对象。   获取Resources的过程: (1)将framework/framework-res.apk和应用资源apk装载为Resources对象。 (2)获取Resources对象 获取Res

zimo2013的技术博客 1622
上一篇: Android资源知识(一)之Resources概览
下一篇: Android Service生命周期浅析
.NET跨平台
博客等级 码龄15年 6066粉丝 738原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值