`
ishelf
  • 浏览: 106353 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Bitmap 详解(1)- 提高Bitmap解析速度( Resources , BitmapFactory , AssetManager ,主题定制 )

阅读更多

      图片是应用里面最常用的资源,在canvas里面使用需要将其解析成Bitmap的方式(例如倒影效果)。这里给出几个可能会有的场景,探讨一下如何使用:

  • 应用主题转化:当某个应用希望换掉整个生命周期中的一些背景图片,例如从卡通主题转化到草原主题,这样会涉及到Button、Tab、Layout等各式各样图片的替换。
  • 动画播放:例如关机动画、闹铃提醒(当然简单的动作除外)

      转载请注明http://ishelf.iteye.com/blog/1032563

      场景一中,可以通过apk升级来实现,也可以通过调用外部资源来实现。这两种方式比较简单,问题也就显而易见。第一种apk升级很烦人,至少我自己都懒得去。第二种,外部资源是简单,不过图片的解析速度一定会比从apk中调用drawable资源要慢好几倍,对于配置很好的机器这个速度不是问题,可是中下的机器可就够受了(最近试了试中兴的平板,和三星的对比太鲜明了)。这两个的前提都是对图片显示要求不是非常的很高,例如图片预览

      在场景二中,需要考虑到定制的问题。你给国内和国外的关机动画不能一样吧,给联通和给电信定制的不能一样吧(这个也根据需求而定,不排除都一样的可能)。这样当需求变化时,难道你的代码也要跟着变化么? 这样的话真给Java显眼了,O(∩_∩)O。 其实在场景一中的主题替换也是一个定制的问题。

      如何能在保证即不修改代码又能保证图片解析速度尽可能快的前提下,做到图片资源的定制是接下来要讨论的问题。首先看代码

 

 

orginalbm = BitmapFactory.decodeFile(Path);
//解析源图片文件,根据需要可以放在任何地方。

orginalbm = BitmapFactory.decodeResource(resources,source_id);
//解析apk中的资源图片。可以放置到一个不包含任何Java文件的apk包中去。
 

 

      第二种方式一定是比第一种方式速度快(大家有什么异议可以讨论一下)。接下来就是如何用apk解析的方式来动态的加载外部的图片资源(也可以包括Layout,anim和xml资源)。

 

     第一步就是解决如何解析apk包,并将资源加载进来。这要分两种情况:一是在应用中使用,而是在framework框架中。

 

 

这样也就有两种方式,首先介绍第一种,直接看代码

 

		try {
			// apk包的文件路径
			// 这是一个Package 解释器, 是隐藏的
			// 构造函数的参数只有一个, apk文件的路径
			// PackageParser packageParser = new PackageParser(apkPath);
			Class pkgParserCls = Class.forName(PATH_PackageParser);
			Class[] typeArgs = new Class[1];
			typeArgs[0] = String.class;
			Constructor pkgParserCt = pkgParserCls.getConstructor(typeArgs);
			Object[] valueArgs = new Object[1];
			valueArgs[0] = apkPath;
			Object pkgParser = pkgParserCt.newInstance(valueArgs);
			Log.d("ANDROID_LAB", "pkgParser:" + pkgParser.toString());
			// 这个是与显示有关的, 里面涉及到一些像素显示等等, 我们使用默认的情况
			DisplayMetrics metrics = new DisplayMetrics();
			metrics.setToDefaults();
			// PackageParser.Package mPkgInfo = packageParser.parsePackage(new
			// File(apkPath), apkPath,
			// metrics, 0);
			typeArgs = new Class[4];
			typeArgs[0] = File.class;
			typeArgs[1] = String.class;
			typeArgs[2] = DisplayMetrics.class;
			typeArgs[3] = Integer.TYPE;
			Method pkgParser_parsePackageMtd = pkgParserCls.getDeclaredMethod(
					"parsePackage", typeArgs);
			valueArgs = new Object[4];
			valueArgs[0] = new File(apkPath);
			valueArgs[1] = apkPath;
			valueArgs[2] = metrics;
			valueArgs[3] = 0;
			Object pkgParserPkg = pkgParser_parsePackageMtd.invoke(pkgParser,
					valueArgs);
			// 应用程序信息包, 这个公开的, 不过有些函数, 变量没公开
			// ApplicationInfo info = mPkgInfo.applicationInfo;
			Field appInfoFld = pkgParserPkg.getClass().getDeclaredField(
					"applicationInfo");
			ApplicationInfo info = (ApplicationInfo) appInfoFld
					.get(pkgParserPkg);
			// uid 输出为"-1",原因是未安装,系统未分配其Uid。
			Log.d("ANDROID_LAB", "pkg:" + info.packageName + " uid=" + info.uid);
			Class assetMagCls = Class.forName(PATH_AssetManager);
			Constructor assetMagCt = assetMagCls.getConstructor((Class[]) null);
			Object assetMag = assetMagCt.newInstance((Object[]) null);
			typeArgs = new Class[1];
			typeArgs[0] = String.class;
			Method assetMag_addAssetPathMtd = assetMagCls.getDeclaredMethod(
					"addAssetPath", typeArgs);
			valueArgs = new Object[1];
			valueArgs[0] = apkPath;
			assetMag_addAssetPathMtd.invoke(assetMag, valueArgs);
			Resources res = getResources();
			typeArgs = new Class[3];
			typeArgs[0] = assetMag.getClass();
			typeArgs[1] = res.getDisplayMetrics().getClass();
			typeArgs[2] = res.getConfiguration().getClass();
			Constructor resCt = Resources.class.getConstructor(typeArgs);
			valueArgs = new Object[3];
			valueArgs[0] = assetMag;
			valueArgs[1] = res.getDisplayMetrics();
			valueArgs[2] = res.getConfiguration();
			res = (Resources) resCt.newInstance(valueArgs);

       代码是参考来源:http://blog.csdn.net/sodino/archive/2011/03/01/6215224.aspx    。这里主要使用了Java反射机制,得到了res(Resources)(这个博主挺nb的,O(∩_∩)O)。 Resources类是实现apk资源解码的核心,具体类的作用这里就不介绍了(不懂得看源码去)。

       如果是在framework中使用就简单了,看代码

 

        AssetManager assets = new AssetManager();
        String resDir = "/sdcard/extern-sd/xxx.apk";
        if (assets.addAssetPath(resDir) == 0) {
            Log.e(TAG, "parse failed");
            return;
        }
        resources = new Resources(assets, null, null, null);

        这样很简单就得到了Resources类。

 

     第二步是解决如何得到drawble资源的id值。这里我们根据需要为每个drawable添加相应的参数,例如在哪个类里面使用、名称等各种信息。

       先看代码:

 

 

		int all_view_id = resources.getIdentifier("image_ids", "xml",
				"com.xxx.resource");
		XmlResourceParser parser = resources.getXml(all_view_id);
		try {
			int type;
			while ((type = parser.next()) != XmlPullParser.START_TAG
					&& type != XmlPullParser.END_DOCUMENT) {;}

			if (type != XmlPullParser.START_TAG) {
				Log.e(TAG, "No start tag found in package manager 	settings");
			}
			int outerDepth = parser.getDepth();
			while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
					&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
				if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
					continue;
				}
				String tagName = parser.getName();
			}
		} catch (XmlPullParserException e) {
			Log.e(TAG, "Error reading package manager settings", e);
		} catch (java.io.IOException e) {
			Log.e(TAG, "Error reading package manager settings", e);
		}

 

      通过getIdentifier可以得到需要的xml文件id值。

 

 resources.getIdentifier("image_ids", "layout","com.xxx.resource");

 

     //字段“layout”,表示资源文件在layout文件夹中

     //字段“com.xxx.resource”表示该apk的包名(packagename)

     需要注意一点在自己配置的xml文件中,要使用android:drawable这样的属性名定义,否则不会编译成int类型的id号。

 


     最后一步就是如何调用通过id调用图片。

 

BitmapFactory.decodeResource(resources, source_id);

     resources就是第一步得到的Resources类,id则是第二部得到的id号。需要注意一点就是变量的作用域。

 

 

经过上面三步可以很容易的实现使用apk的方式调用外部的图片资源。

 

 

 

 

 

 

 

 

 

 

 

 

 

1
2
分享到:
评论

相关推荐

    Bitmap加载、变换、显示图片

    - **从Assets目录加载**:通过`AssetManager`的`open(String fileName)`方法获取到输入流,然后使用`BitmapFactory`的`decodeStream(InputStream is)`方法解析成Bitmap。 - **从SD卡加载**:使用`FileInputStream`...

    BitmapFactory.Options

    BitmapFactory.Options是Android系统中处理图像资源的核心类之一,它在`android.graphics.BitmapFactory`包中,用于控制Bitmap对象的创建过程。这个类提供了多种选项和设置,可以帮助开发者优化内存使用,提高应用...

    Android图片大小调整

    ### Android图片大小调整详解 在Android开发过程中,对图片进行大小调整是一项常见需求。无论是为了优化用户界面(UI)布局,还是为了节省内存资源、提高加载速度,掌握图片大小调整的技术都是十分必要的。本文将...

    Android 加载assets文件夹的文本文件 图片

    Bitmap bitmap = BitmapFactory.decodeStream(inputStream); ``` - **显示图片**:现在,你可以将`Bitmap`对象设置给ImageView或者其他可以显示图像的视图: ```java ImageView imageView = findViewById(R.id...

    Android 获得图片的方法

    类似地,也可以使用`BitmapFactory.decodeStream()`方法从输入流中解析出`Bitmap`对象: ```java Bitmap bitmap = BitmapFactory.decodeStream(is); ``` #### 四、从SD卡获取图片资源 当图片存储在外部存储...

    android--imgtest加载assets目录中的图片

    Bitmap bitmap = BitmapFactory.decodeStream(inputStream); ``` 注意,为了防止内存泄漏,确保在不再使用时关闭输入流: ```java inputStream.close(); ``` 4. 显示图片: 现在你可以将`Bitmap`对象设置给...

    android 从assets获取图片

    3. **解析图片**:利用`BitmapFactory`类将输入流转换为`Bitmap`对象。 4. **关闭输入流**:处理完图片后,不要忘记关闭输入流以释放系统资源。 #### 三、代码实现 下面通过一个具体的例子来展示如何实现从`assets...

    图片资源获取

    接着,对于每个文件,我们打开一个InputStream,使用`BitmapFactory.decodeStream()`方法将流转换为Bitmap对象,最后将Bitmap显示在ImageView上。记得在使用完毕后关闭输入流,以释放系统资源。 值得注意的是,`...

    AndEngine LoadResouresDemo

    Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(file)); Texture texture = new Texture(bitmap); ``` 或者,如果你已经将资源打包成ZIP文件,可以使用`ZipFile`来解压并加载: ```java ...

    SkinTest简易更换皮肤

    另外,还可以使用LruCache或 Glide 等库进行图片缓存,提高加载速度。 7. **用户体验**: 考虑到用户体验,皮肤更换应提供平滑过渡效果,如淡入淡出,使得换肤过程更为自然。此外,确保所有界面元素都支持所选皮肤...

    Android读取assets下面文件的代码例子

    Bitmap bitmap = BitmapFactory.decodeStream(inputStream); // 使用解码得到的Bitmap对象,如显示到ImageView } catch (IOException e) { e.printStackTrace(); } finally { if (inputStream != null) { try {...

    Android读取assets与sdcard中的ini文件与图片

    1. **读取图片**:对于assets中的图片,可以使用`AssetManager`的`open`方法得到`InputStream`,然后用`BitmapFactory.decodeStream`创建`Bitmap`对象。对于sdcard上的图片,使用`FileInputStream`打开文件,然后...

    火山移动动态读取ASSETS图片.zip

    // 然后可以使用inputStream加载图片,例如使用BitmapFactory解码为Bitmap } catch (IOException e) { e.printStackTrace(); } finally { if (inputStream != null) { try { inputStream.close(); } catch ...

    BitmapFun.zip

    BitmapFun项目很可能包含了一些最佳实践,例如使用BitmapFactory加载图片,选择合适的解码选项,以及使用内存和磁盘缓存来优化性能。 2. **Resources and Asset Management**: "resources.ap_" 文件是Android应用...

    showbase64

    1. **Base64编码**:Base64是一种用于将二进制数据编码为ASCII字符串的方法,以便在电子邮件、JSON或其他需要文本格式的场景中传输。它将每3个字节的二进制数据转化为4个字符的Base64编码,确保了编码后的字符串只...

    Android编程实现获取图片资源的四种方法

    如果图片位于项目的`res/drawable`目录下,可以使用`Resources`对象的`getIdentifier()`方法获取资源ID,再通过`decodeResource()`方法得到`Bitmap`。首先需要获取到`ApplicationInfo`,然后根据资源类型(如`...

    Android读取assets目录下的所有图片并显示的方法

    1. 获取AssetManager引用: 在需要访问assets目录的类(通常是Activity)中,可以通过getAssets()方法获取AssetManager的引用,这通常是Activity的一个成员变量: ```java AssetManager assetManager = ...

    Android FoldableLayout展开效果.rar

    Bitmap bitmap = BitmapFactory.decodeStream(inputStream); // 将bitmap设置给ImageView或其他视图 } catch (IOException e) { e.printStackTrace(); } finally { if (inputStream != null) { try { ...

    ME上Layer,LayerManager,Sprite,TiledLayer移植到android

    - 资源管理:Android的资源管理与J2ME不同,需要适配Android的`BitmapFactory`、`AssetManager`等工具加载和管理图像、音频等资源。 - 性能优化:考虑到Android设备的多样性,移植时要关注性能优化,如适当的缓存...

    Android游戏开发教程

    Android中,静态资源通常存放在`assets`文件夹中,通过`AssetManager`获取文件流,再用`BitmapFactory.decodeStream()`解析成`Bitmap`对象,用于显示图像。动态资源,如音效和音乐,通常使用`.mp3`或`.ogg`格式。...

Global site tag (gtag.js) - Google Analytics