插件换肤
来源:互联网 发布:数据库表结设计例子 编辑:程序博客网 时间:2024/06/05 02:35
插件换肤的重点在于如何加载插件包的资源。
插件包其实就是一个apk的压缩包,加载插件包的资源,其实就是加载apk的资源。
如何才能加载apk中的资源呢?
首先android中的各种资源都对应一个唯一id,比如获取一个view,通过findViewById(int id)方法,就可以得到布局的唯一view。
同样,
设置图片
setBackground(getResources().getDrawable(id))
设置颜色
setTextColor(getResources().getColor(id))
唯一的id值怎么获得呢?
id可以通过Resources下的getIdentifier方法根据icon的名字、view设置的id名、color的名字等得到:
public int getIdentifier(String name, String defType, String defPackage) { return mResourcesImpl.getIdentifier(name, defType, defPackage); }
所以获取插件包的资源的核心就在:Resources,如果可以获取插件包的Resources,就可以根据名字,获取插件包的资源了。
如何获取插件包的Resources?
/** * Create a new Resources object on top of an existing set of assets in an * AssetManager. * * @deprecated Resources should not be constructed by apps. * See {@link android.content.Context#createConfigurationContext(Configuration)}. * * @param assets Previously created AssetManager. * @param metrics Current display metrics to consider when * selecting/computing resource values. * @param config Desired device configuration to consider when * selecting/computing resource values (optional). */ @Deprecated public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) { this(null); mResourcesImpl = new ResourcesImpl(assets, metrics, config, new DisplayAdjustments()); }
而创建Resources的关键在于
Create a new Resources object on top of an existing set of assets in an AssetManager.
通过AssetManager最新的设置创建一个新的Resouces对象
AssetManager的最新设置是什么呢?
/** * 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 final int addAssetPath(String path) { return addAssetPathInternal(path, false); }
这个设置可以是一个文件或者压缩包路径,即我们的插件包。
通过上面的分析,接下来实现插件换肤
/** * 加载皮肤 */ public void loadSkin(){ boolean grant = ClientUtils.addPermission(READ_EXTERNAL_STORAGE, context); if(!grant){ Looklog.i(TAG, "loadSkin error: 无sd卡读取权限"); //如果是外部目录,需要判断权限,否则crash return; } //加载皮肤 new Thread(new Runnable() { @Override public void run() { //本地存储的路径 String skinPkgPath = Local.getDVStringData(SKINPKGPATH); //插件名 String skinName = "skin"; //缓存path String cachePath = context.getCacheDir() + "/" + skinName; boolean needCopy = true; if(!TextUtils.isEmpty(skinPkgPath)){ if(skinPkgPath.equals(cachePath)){ File file = new File(skinPkgPath); if(file != null){ if(file.exists()){ needCopy = false; } } } } //如果缓存为空,copy if(needCopy){ Looklog.i(TAG,"无skin缓存,需要拷贝 " + skinPkgPath + " cachePath:" + cachePath); skinPkgPath = copySkinToCache(skinName); Looklog.i(TAG,"无skin缓存,需要拷贝 拷贝成功>>>>:" + skinPkgPath); }else { Looklog.i(TAG, "有skin缓存,直接使用 " + skinPkgPath); } //判断是否copy成功 if(TextUtils.isEmpty(skinPkgPath)){ return; } //判断路径合法性 File file = new File(skinPkgPath); if ((file == null) || !file.exists()) { return; } //读取 PackageManager mPm = context.getPackageManager(); PackageInfo mInfo = mPm.getPackageArchiveInfo(skinPkgPath, PackageManager.GET_ACTIVITIES); if(mInfo == null)return; skinPackageName = mInfo.packageName; try { AssetManager assetManager = AssetManager.class.newInstance(); Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class); addAssetPath.invoke(assetManager, skinPkgPath); Resources superRes = context.getResources(); Resources skinResource = new Resources(assetManager, superRes.getDisplayMetrics(), superRes.getConfiguration()); if(skinResource != null){ isDefaultSkin = false; skinResources = skinResource; clz = skinResources.getClass(); skinVersionCode = mInfo.versionCode; skinVersionName = mInfo.versionName; skinLoaded = true; Looklog.i(TAG, "Skin versionCode:" + skinVersionCode + " versionName:" + skinVersionName + " clz:" + clz + " packageName:" + skinPackageName + " path:" + skinPkgPath); saveSkinData(skinVersionName, skinVersionCode, skinPkgPath); } } catch (Exception e) { e.printStackTrace(); Looklog.i(TAG, "Skin load error " + e.getMessage()); } } }).start(); }
上面的skin路径,是由于将skin的插件包放在了assets目录下,如果是sd卡目录下,修改对应路径即可。
加载assets文件的话,需要先将assets路径下的skin插件包拷贝到缓存目录。
private String copySkinToCache(String fileName) { File cacheFile = new File(context.getCacheDir(), fileName); InputStream inputStream = null; FileOutputStream outputStream = null; try { inputStream = context.getAssets().open(fileName); outputStream = new FileOutputStream(cacheFile); byte[] buf = new byte[1024]; int len; while ((len = inputStream.read(buf)) > 0) { outputStream.write(buf, 0, len); } } catch (IOException e) { cacheFile = null; e.printStackTrace(); }finally { if(outputStream != null){ try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } outputStream = null; } if(inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } inputStream = null; } } if(cacheFile == null){ return ""; } return cacheFile.getAbsolutePath(); }
定义获取color或drawable的方法:
private int getIdentifier(String name, String defType) { int id = skinResources.getIdentifier(name, defType, skinPackageName); if(id <= 0){ id = appResources.getIdentifier(name, defType, appPackageName); } return id; } private int getColorId(String name){ return getIdentifier(name, "color"); } private int getDrawableId(String name){ return getIdentifier(name, "drawable"); } public int getColor(String name){ int id = getColorId(name); int color = getColor(id, skinResources); if(color == -1){ color = getColor(id, appResources); } if(color == -1){ color = Color.WHITE; } return color; } public Drawable getDrawable(String name){ int id = getDrawableId(name); Drawable drawable = getDrawble(id, skinResources); if(drawable == null){ drawable = getDrawble(id, appResources); } if(drawable == null){ drawable = new Drawable() { @Override public void draw(@NonNull Canvas canvas) { } @Override public void setAlpha(int alpha) { } @Override public void setColorFilter(@Nullable ColorFilter colorFilter) { } @Override public int getOpacity() { return PixelFormat.TRANSPARENT; } }; } return drawable; } private Drawable getDrawble(int id, Resources resources){ try{ return resources.getDrawable(id); } catch (Exception e){} return null; } private int getColor(int id, Resources resources){ try { return resources.getColor(id); }catch (Exception e){} return -1; }
使用方式:
在values下新建theme_colors.xml
<?xml version="1.0" encoding="utf-8"?><resources> <color name="background_color_default">#ffffff</color></resources>
代码使用:
public int getBackgroundColor() { return getColor("background_color_default"); }
只需要在插件包中添加一样的background_color_default,改成其他颜色
以上步骤即可实现插件换肤。
- Eclipse换肤插件
- 插件换肤
- Android换肤之——插件换肤
- 如何给插件实现自动换肤
- jQuery之换肤与cookie插件
- Android插件换肤功能实战
- Android 插件换肤原理解析
- android插件化开发---换肤
- 网页换肤,模块换肤,jQuery的Cookie插件使用
- VC 常用插件和界面库,换肤
- jQuery实现换肤功能(使用cookie.js插件)
- Android插件开发之-换肤功能前篇
- Android插件开发之-换肤功能后篇
- 动态加载插件开发换肤等技术文章
- Android插件化开发实现动态换肤
- android 换肤(1)——插件式无缝换肤(解析鸿洋大神的换肤流程)
- android 换肤(2)——插件式无缝换肤(解析鸿洋大神的换肤流程)
- 换肤
- 递推
- 链表的归并排序
- Python使用PyQt5库 一、Designer界面的使用——终于出界面了。****************
- 项目1-5
- C语言中控制printf的打印颜色实例及vt100的控制符
- 插件换肤
- CodeForces
- JAVA设计模式之【代理模式】一(静态代理)
- Linux硬链接与软链接
- HDU-6000-Wash
- 内置的常用层:LayerColor、LayerGradient
- 前端优化策略列举(一)
- 阶乘因式分解(1)
- 华山论剑:微服务框架-SpringCloud、Dubbo or Istio