换肤,我们都很熟悉,像XP的主题,塞班的主题。看过国外的一些技术博客,就会发现国内和国外对软件的,或者说移动开发的软件的需求的不同。国外用户注重社交、邮件等功能,国内用户则重视音乐、小说、皮肤等功能,国内有很多的软件都支持换肤,像腾讯微博、墨迹天气等。

Android系统通过XML 形式描述各种资源,包括布局、字符串、样式、交互风格等,通常存放在res目录中,使应用逻辑和界面设计分离开来,让开发者可以专注于代码逻辑。

换肤就是换掉皮肤包括的部分或所有资源。皮肤一般含有多个文件,例如图片、配置等文件,分散的文件不利于传输和使用,最好打包。打包的格式一般选择zip格式。这里分两种情况,一种是apk,例如腾讯微博,它的皮肤格式是一个apk;另一种是自定义扩展名,例如小米主题的扩展名为mtz,墨迹天气皮肤扩展名是mja,搜狗输入法皮肤扩展名为ssf,本质都是zip格式。

本节课程就来讲解Android应用程序如何实现换肤功能。

软件换肤从功能上可以划分三种:

1) 软件内置多个皮肤,不可由用户增加或修改;
  最低的自由度,软件实现相对于后两种最容易。
2) 官方提供皮肤供下载,用户可以使用下载的皮肤;
  用户可以下载自己喜欢的皮肤,然后安装使用,如腾讯微博中就提供了四种皮肤,用户可以下载使用。

3) 官方提供皮肤制作工具或方法,用户可自制皮肤。
  这种方式使用户有参与感,自由度较高。用户可根据自己的喜好定制软件的皮肤。

软件换肤从实现上可以划分三种:

1.一个应用中放置几个固定的皮肤,皮肤之间的控制由程序来控制实现。
   优点:实现简单。
   缺点:拥有多套皮肤(图片,布局文件定义),动态的修改布局。这样会让工程比较大,不仅不够灵活,而且生成的安装包太大,要增加新的皮肤需更新应用。

实现技术:这个很简单,可以通过sharereference统一控制皮肤的前后缀或者路径来实现一个通用的换肤目的。

2. zip压缩包式皮肤。应用可设置一个默认路径。如果用户选择某个皮肤,则解压该皮肤.zip到这个文件夹中。
   优点:无需安装,即使卸载掉皮肤应用,该皮肤仍然可用,不会影响正常使用。
   缺点:可能会因为用户的误操作,使皮肤文件损坏,资源访问的效率低。

实现技术: 该技术重点在于如何去读取zip文件中的资源以及皮肤文件存放策略。
  方案:如果软件每次启动都去读取SD卡上的皮肤文件,速度会比较慢。较好的做法是提供一个皮肤设置的界面,用户选择了哪一个皮肤,就把那个皮肤文件解压缩到”/data/data/[package name]/skin”路径下,这样不需要跨存储器读取,速度较快,而且不需要每次都去zip压缩包中读取,不依赖SD卡中的文件,即使皮肤压缩包文件被删除了也没有关系。

实现方法:
  1. 在软件的帮助或者官网的帮助中提示用户将皮肤文件拷贝到SD卡指定路径下
  2. 在软件中提供皮肤设置界面。可以在菜单或者在设置中。可参考墨迹天气(zip格式)等支持换肤的软件。
  3. 加载指定路径下的皮肤文件,读取其中的缩略图,在皮肤设置界面中显示,将用户选中的皮肤文件解压缩到”/data/data/[package name]/skin”路径下。
  4. 软件中优先读取”/data/data/[package name]/skin/”路径下的资源。如果没有则使用apk中的资源.

实现实例:墨迹天气下载的皮肤就是一个mja格式的压缩包,在应用的时候把皮肤资源释放到墨迹天气应用的目录下,更换皮肤时新的皮肤资源会替换掉老的皮肤资源每次加载的时候就是从手机硬盘上读取图片,这些图片资源的命名和程序中的资源的命名保持一致,一旦找不到这些资源,可以选择到系统默认中查找。(注:墨迹天气应用在设置中可以让用户自己控制插件皮肤是否装入内存)

下面是一个简单的例子:

下载zip资源包(略)----->解压zip到指定路径,应用程序加载时加载该路径下的资源。

   private String basePathString = "/data/data/com.wts.skin/Skin_kris";

   private String skinBasePath = basePathString + "/skin/";

//把zip格式的资源包解压到指定路径下:

ZipUtil zipp = new ZipUtil(2049);

zipp.unZip("/sdcard/skin.zip",basePathString);

//为button和背景设置资源

Bitmap bmp =BitmapFactory.decodeFile(skinBasePath+"test.png");

BitmapDrawable bd=new BitmapDrawable(bmp);

btnSet.setBackgroundDrawable(bd);

layout.setBackgroundDrawable(new  BitmapDrawable(

BitmapFactory.decodeFile(skinBasePath +"bg/bg.png")));

3. manifest中设置android:sharedUserId,通过这种方式可以达到不同应用相互访问数据的目的,以实现换肤功能。此外需要注意,皮肤apk和应用要有相同签名。

优点:可定期提供换肤包供下载,换肤方式灵活,同时效率比较高。
    缺点:如需使用某个皮肤,必须安装该皮肤。但其实现起来还是用代码的方式来提供置换的。同时,让两个工程来共享一个进程,这样做十分的危险。此外,安装了很多皮肤后,应用程序列表里面会有很多皮肤程序。在主程序卸载后,皮肤工程不能同样的卸载。如卸载腾讯微博之后,安装的皮肤apk没有被卸载。

实现技术:该技术的重点是怎样实现一个应用如何读取另一个apk中的资源。
  在android系统中,apk之间可以相互读取数据的条件是:有同样的签名,并且manifest中配置的android:sharedUserId属性值相同,那么两个apk运行在同一个进程中,可以互相访问任意数据.注意:只访问资源时不需要添加该属性值。

实现方法:

1)应用程序和皮肤程序的AndroidManifest.xml中配置minifest属性
   例如: android:sharedUserId="com.wwwww.skin",值可以是做任意的。

2) 文件与应用apk中对同一功能的皮肤文件名要一致
  例如:应用程序的背景图片路径:\WBlogSkin\res\drawable-hdpi\bg.png
   则皮肤apk中的背景图片文件路径也应该是SkinApk\res\drawable-hdpi\bg.png
3)访问资源的方法

  Context context =createPackageContext("com.wts.skin.night.hdpi",

Context.CONTEXT_IGNORE_SECURITY);

获取到皮肤包包名(com.wts.skin.night.hdpi)对应Context,通过返回的context对象就可以访问com.wts.skin.night.hdpi中的任何资源。
  例如:应用apk要获得皮肤apk中的xml资源(mSkin为包名)

Context context = mApp.createPackageContext(mSkin, 0);

mSkinResources = context.getResources();

int configResId = mSkinResources.getIdentifier(CONFIG_XML_NAME,"xml", mSkin);

XmlPullParser xmlpull = mSkinResources.getXml(configResId);

这样就得到了对xml资源的引用,其他资源文件的获取方式也是类似的。

注意:通过当前工程的R.id来调用被调用工程的资源,这是错误的,因为R是自动生成的,两个应用的id是没有办法对应的,所以需要通过getIdentifier来查找。

实现实例:腾讯微博等。

从上面可以看出,只有后两种实现(apk方式和zip方式)可以做到皮肤与应用程序实现分离

Android应用换肤总结的更多相关文章

  1. Android主题换肤实现

    本系列文章主要是对一个Material Design的APP的深度解析,主要包括以下内容 基于Material Design Support Library作为项目整体框架.对应博文:Android ...

  2. Android主题换肤 无缝切换

    2016年7月6日 更新:主题换肤库子项目地址:ThemeSkinning,让app集成换肤更加容易.欢迎star以及使用,提供改进意见. 更新日志: v1.3.0:增加一键切换切换字体(初版)v1. ...

  3. Android动态换肤(二、apk免安装插件方式)

    在上一篇文章Android动态换肤(一.应用内置多套皮肤)中,我们了解到,动态换肤无非就是调用view的setBackgroundResource(R.drawable.id)等方法设置控件的背景或者 ...

  4. Android实现换肤功能(一)

    上周有个朋友给建议说讲讲换肤吧,真巧这周公司的工作安排也有这个需求,换的地方之多之繁,让人伤神死了.正所谓磨刀不误砍柴工,先磨下刀,抽出一个工具类,写了个关于换肤的简单demo. Android中换肤 ...

  5. Android一键换肤功能:一种简单的实现

     Android一键换肤功能:一种简单的实现 现在的APP开发,通常会提供APP的换肤功能,网上流传的换肤代码和实现手段过于复杂,这里有一个开源实现,我找了一大堆,发现这个项目相对较为简洁:htt ...

  6. 一种简单的实现:Android一键换肤功能

    现在的APP开发,通常会提供APP的换肤功能,网上流传的换肤代码和实现手段过于复杂,我把原作者的代码重新整理抽取出来,转换成Eclipse项目,重新整理成正确.可直接运行的项目. 代码运行结果如图. ...

  7. Android动态换肤(一、应用内置多套皮肤)

    动态换肤在很多android应用中都有使用,用户根据自己的喜好设置皮肤主题,可以增强用户使用应用的舒适度. Android换肤可以分为很多种,它们从使用方式,用户体验以及项目框架设计上体现了明显的差异 ...

  8. Android实现换肤功能(二)

    前两天写的上章关于换肤的功能获得了很好的反响,今天为大家介绍另一种方式.今天实现的策略也是网友建议的,然后我自己去写了个demo,大家自己评估下相比第一种方式的优势和劣势在哪里. 简单介绍下关于第一种 ...

  9. Android插件换肤 一.实现原理

    学习缺的不是时间,而是耐心 目的 1.搞懂系统获取资源文件到在加载布局的整个流程是自己实现换肤功能的理论基础 2.提高分析源码.追踪源码的能力 要点 1.XmlResourceParser (通过这个 ...

随机推荐

  1. 物理地址为20位 如10000H 用段地址*16+偏移地址表示

    段地质在cpu中,为16位 段地质*16则变成物理首地址20位,这个物理首地址必定是16的倍数. 偏移地址16位, 则表明一个段的大小为64k. 同时也表明16位地址的寻址能力为64kb

  2. hdu 4878 ZCC loves words AC自动机+中国剩余定理+快速幂

    题意就不说了. 分析:折腾好几天自己写的代码还是看了别人代码后发现几乎没什么复杂度的差别,可是就是一直超时,后来干脆照着别人写啊,一直WA,就在准备放弃干脆先写这篇博客的时候,又看了一眼WA的代码,发 ...

  3. 李洪强漫谈iOS开发[C语言-024]-表达式与赋值运算符

  4. easyui源码翻译1.32--Menu(菜单)

    前言 使用$.fn.menu.defaults重写默认值对象.下载该插件翻译源码 菜单组件通常用于快捷菜单.他是构建其他菜单组件的必备基础组件.比如:menubutton和splitbutton.它还 ...

  5. Linux伙伴系统1

    (一)--伙伴系统的概述 Linux内核内存管理的一项重要工作就是如何在频繁申请释放内存的情况下,避免碎片的产生.Linux采用伙伴系统解决外部碎片的问题,采用slab解决内部碎片的问题,在这里我们先 ...

  6. VC C运行时库(CRTL)的几个版本及选用

    分类: Windows 2008-12-23 10:01 987人阅读 评论(0) 收藏 举报ciostreammfclibrary多线程import最近做项目碰到了一个关于在动态库中使用MFC以及在 ...

  7. Android 常用UI控件之TabHost(3)在4.0不显示图标的解决方案

    1,自定义 TabWidget 上每个tab的view 2,用多个图片

  8. 【HDOJ】1033 Edge

    题目英文太多,简单翻译了一下:1. For products that are wrapped in small packings it is necessary that the sheet of ...

  9. MySQL导入数据非常慢的解决办法

    MySQL导出的SQL语句在导入时有可能会非常非常慢,经历过导入仅45万条记录,竟用了近3个小时.在导出时合理使用几个参数,可以大大加快导入的速度. -e 使用包括几个VALUES列表的多行INSER ...

  10. bzoj1797

    其实我觉得这种题目风格很像今天省选第三轮D1T1 都是在一个算法模型上去探索规律: 首先我们要做一遍最大流毫无疑问 第一问看起来很好想,只要是满流边就可以了? 错,反例不难找到 如:1--->2 ...