1). 换肤思路

在源应用APP中,下载皮肤包,使得对应的文件资源得以应用。使用DexClassLoader加载资源包,使用反射来获取资源ID.

2). 创建SkinChange工程
图1.png

app是应用Module,spinone和spintwo是皮肤插件工程

3). app Module
  • BaseActivity
/*** Activity基类* Created by mazaiting on 2018/6/27.*/public abstract class BaseActivity extends AppCompatActivity {/**资源管理器*/protected AssetManager mAssetManager;/**资源*/protected Resources mResources;/**主题*/protected Theme mTheme;/*** 加载资源* @param dexPath dex路径*/protected void loadResources(String dexPath) {try {AssetManager assetManager = AssetManager.class.newInstance();Method addAssetPath = assetManager.getClass().getMethod("addAssetPath",String.class);addAssetPath.invoke(assetManager, dexPath);mAssetManager = assetManager;} catch (Exception e) {e.printStackTrace();}Resources superRes = super.getResources();superRes.getDisplayMetrics();superRes.getConfiguration();mResources = new Resources(mAssetManager, superRes.getDisplayMetrics(), superRes.getConfiguration());mTheme = mResources.newTheme();mTheme.setTo(super.getTheme());}@Overridepublic AssetManager getAssets() {return mAssetManager == null ? super.getAssets() : mAssetManager;}@Overridepublic Resources getResources() {return mResources == null ? super.getResources() : mResources;}@Overridepublic Theme getTheme() {return mTheme == null ? super.getTheme() : mTheme;}
}
  • MainActivity
public class MainActivity extends BaseActivity {private static final String TAG = "MainActivity";private TextView mTextView;private ImageView mImageView;private ClassLoader mClassLoader;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mTextView = findViewById(R.id.tv_show);mImageView = findViewById(R.id.iv_show);}/*** 切换主题1*/public void changeThemeOne(View view) {// 获取缓存路径String fileDir = getCacheDir().getAbsolutePath();// 获取文件路径String filePath = fileDir + File.separator + "spinone-release.apk";mClassLoader = new DexClassLoader(filePath, fileDir, null, getClassLoader());loadResources(filePath);setContentOne();}/*** 切换主题2*/public void changeThemeTwo(View view) {// 获取缓存路径String fileDir = getCacheDir().getAbsolutePath();// 获取文件路径String filePath = fileDir + File.separator + "spintwo-release.apk";mClassLoader = new DexClassLoader(filePath, fileDir, null, getClassLoader());loadResources(filePath);setContent();}/*** 设置主题内容*/private void setContent() {try {Class clazz = mClassLoader.loadClass("com.mazaiting.UiUtil");// 设置TextView内容Method method = clazz.getMethod("getTextString", Context.class);String string = (String) method.invoke(null, this);mTextView.setText(string);// 设置ImageView背景method = clazz.getMethod("getImageDrawable",Context.class);Drawable drawable = (Drawable) method.invoke(null,this);mImageView.setBackground(drawable);} catch (Exception e) {e.printStackTrace();}}/*** 设置主题1*/private void setContentOne() {int stringId = getTextStringId();int drawableId = getImgDrawableId();Log.d(TAG, "stringId: " + stringId + ",  drawableId: " + drawableId);}/*** 获取图片ID* @return*/private int getImgDrawableId() {try {// "com.mazaiting.spinone.R$color" -- spinone module 下的R.color.imgClass clazz = mClassLoader.loadClass("com.mazaiting.spinone.R$color");Field field = clazz.getField("img");int resId = (int) field.get(null);return resId;} catch (Exception e) {e.printStackTrace();}return 0;}/*** 获取字符串ID* @return*/private int getTextStringId() {try {// "com.mazaiting.spinone.R$string" -- spinone module下的R.string.textClass clazz = mClassLoader.loadClass("com.mazaiting.spinone.R$string");Field field = clazz.getField("text");int resId = (int) field.get(null);return resId;} catch (Exception e) {e.printStackTrace();}return 0;}
}
  • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.mazaiting.skinchange.MainActivity"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><Buttonandroid:onClick="changeThemeOne"android:text="主题1"android:layout_width="wrap_content"android:layout_height="wrap_content"/><Buttonandroid:onClick="changeThemeTwo"android:text="主题2"android:layout_width="wrap_content"android:layout_height="wrap_content"/></LinearLayout><LinearLayoutandroid:paddingTop="50dp"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><TextViewandroid:id="@+id/tv_show"android:text="@string/text"android:layout_width="match_parent"android:layout_height="wrap_content"/><ImageViewandroid:id="@+id/iv_show"android:background="@color/img"android:layout_width="200dp"android:layout_height="200dp"/></LinearLayout></android.support.constraint.ConstraintLayout>
  • 资源文件

    图2.png

4). 插件Module

spinone和spintwo中同样使用一个类,包的全路径名与MainActivity中setContent方法中的Class clazz = mClassLoader.loadClass("com.mazaiting.UiUtil");com.mazaiting.UiUtil相同。并在插件Module中使用相同的资源文件名进行替换。

package com.mazaiting;
/*** Created by mazaiting on 2018/6/27.*/public class UiUtil {/*** 获取字符串*/public static String getTextString(Context ctx) {return ctx.getResources().getString(R.string.text);}/*** 获取图片*/public static Drawable getImageDrawable(Context ctx) {return ctx.getResources().getDrawable(R.color.img);}public static int getTextStringId(){return R.string.text;}public static int getImageDrawableId(){return R.color.img;}
}
5). 运行

安装app Module 至手机,spinone和spintwo Module打包为apk文件,使用命令安装至手机,此处必须将spinone-release.apk文件push到/data/data/<包名>/cache/目录下

adb push C:\Users\mazaiting\Desktop\release\s
pinone-release.apk /data/data/com.mazaiting.skinchange/cache

示例效果:

图4.gif

6). 残留的问题
  • 每个插件包都包含一个UiUtil文件,造成代码冗余(主题2的加载)
  • 主工程无法获取插件包的应用包名,从而实现动态加载。(主题1的加载)(能想到的解决办法:插件的文件名即包名)
代码下载

Android 换肤相关推荐

  1. Android 换肤demo,轻量快捷接入集成,判断是否夜间模式

    true为黑夜模式 //检查当前系统是否已开启暗黑模式 public static boolean getDarkModeStatus(Context context) {int mode = con ...

  2. android换肤哪个简单,Android换肤

    这是一个Android换肤的库,代码量极少,支持换肤的情况还比较多,提供了以下功能: 无需重启,一键换肤效率高 支持App内多套皮肤换肤 支持插件式动态换肤 支持Activity,Fragment,以 ...

  3. android换肤动画,Android换肤(二) — 插件式换肤

    ###前言 上节我们讲到了`Android-skin-support`库的应用内换肤,大家感兴趣的可以参看文章: [Android换肤(一) - 应用内换肤](http://www.demodashi ...

  4. Android-skin-support 一款用心去做的Android 换肤框架

    介绍 Github地址: https://github.com/ximsfei/Android-skin-support Android-skin-support: 一款用心去做的Android 换肤 ...

  5. Android换肤总结

    文章目录 换肤方案 Theme换肤 Resouce换肤 2.拿到皮肤包Resource对象 3.标记需要换肤的View 4.缓存需要换肤的View 5.切换时即时刷新页面 6.制作皮肤包 UiMode ...

  6. Android 换肤之旅——主题切换

    随着手机应用的成熟发展,市面上的应用已不在以简单的实现功能为目标了,它们反而会更加注重用户体验.我们常说的换肤(主题)功能--针对用户的喜好来提供一个可选的主题也是提高用户体验的方式之一.换肤功能不仅 ...

  7. Android 换肤方案详解(一)

    引言 在我们的开发中,也许有些项目会有换肤的需求,这个时候会比较头疼怎么做才能做到一键换肤呢?大家肯定是希望只要一行代码就能调用最好.下面我们先分析一下换肤的本质是什么? 原理 换肤,其本质无非就是更 ...

  8. Android 换肤原理分析

    当了解了一些知识,应该用文字记录它,再抽个时间再看它,永远记住它 Android 换肤的理论知识和文章已经很多了,这里记录一下自己对这块的理解.本文效果如下: 工程:一键换肤的快乐 一.换肤的由来 首 ...

  9. android 换肤框架搭建及使用 (3 完结篇)

    本系列计划3篇: Android 换肤之资源(Resources)加载(一) setContentView() / LayoutInflater源码分析(二) 换肤框架搭建(三) - 本篇 tips: ...

  10. android换肤动画,Android-换肤ThemeSkinning使用

    1.png 2.png 3.png 1.集成步骤: 1.添加依赖 compile 'com.solid.skin:skinlibrary:1.4.3' 参考源码版本 2.让你的 Application ...

最新文章

  1. python graph_python graph什么意思
  2. 8086汇编4位bcd码_逆向工程——汇编基础[一]
  3. 数学建模——智能优化之粒子群模型详解Python代码
  4. 第五天学习Java的笔记(if,switch顺序结构)
  5. Loj#6485. LJJ 学二项式定理
  6. 为什么虚拟助手的前途一片光明
  7. 【Python 必会技巧】判断字符串是否为字母/数字/大小写/空白字符/有效标识符/可打印字符
  8. UNIX(多线程):24---哪些STL容器是线程安全的
  9. SAP中的“定单状态”
  10. 游戏编程编程学习推荐
  11. @value注解取不到值_教学笔记:Java注解及自定义注解示例
  12. 自动化专业是计算机相关专业吗,自动化专业属于什么学科门类
  13. 使用百度开发者工具 4.0 搭建专属的小程序 IDE
  14. 磁珠法RNA pull down试剂盒、蛋白质-核酸相互作用
  15. 吴伯凡-认知方法论-给思维一个支点
  16. python微信抢红包神器_用Python实现微信自动化抢红包,再也不用担心抢不到红包了...
  17. js加ajax实现分页
  18. libssl-dev : 依赖: libssl1.0.0 (= 1.0.2g-1ubuntu4.13) 但是 1.0.2n-1ubuntu5.1 正要被安装
  19. python多核运行程序_python单进程能否利用多核cpu的测试结论
  20. 实时监控Mysql等数据库变化_进行数据同步_了解Debezium_--Debezium工作笔记001

热门文章

  1. ABP理论学习之多租户
  2. 常用工具之zabbix
  3. 为在innodb中什么主键用auto_increment效率会提高
  4. 一起来看流星雨剧情简介/剧情介绍/剧情分集介绍第三十五集
  5. 安全之美(英文影印版)
  6. 适用于Android的OpenSL ES指南-OpenSL ES的Android扩展
  7. php isset()与empty()详解
  8. 普通PC安装ESXI6.0无法识别网卡驱动问题
  9. ORACLE 计算时间相减间隔
  10. 记录git常用操作命令