换肤框架的资源
换肤需要对应的资源,那么资源有哪些来源呢?
1.apk打包的时候,有几个默认的资源被打包进APK中。
2.从网络下载,放到指定的路径。
根据上一章的SkinManager的内容:
@Override protected Resources doInBackground(String... params) { try { if (params.length == 1) { String skinPkgPath = params[0]; Log.e("loadSkin", skinPkgPath);///storage/emulated/0/Android/data/ren.solid.materialdesigndemo/cache/skin/skin_brown.skin File file = new File(skinPkgPath); if (file == null || !file.exists()) { return null; } PackageManager mPm = context.getPackageManager(); PackageInfo mInfo = mPm.getPackageArchiveInfo(skinPkgPath, PackageManager.GET_ACTIVITIES); skinPackageName = mInfo.packageName; 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()); SkinConfig.saveSkinPath(context, skinPkgPath); skinPath = skinPkgPath; isDefaultSkin = false; return skinResource; } return null; } catch (Exception e) { e.printStackTrace(); return null; } }他做了三件事
第一步:他获取指定路径的包名:
PackageManager mPm = context.getPackageManager(); PackageInfo mInfo = mPm.getPackageArchiveInfo(skinPkgPath, PackageManager.GET_ACTIVITIES); skinPackageName = mInfo.packageName;
第二步:使用asset加载器加载对应的asset资源:
AssetManager assetManager = AssetManager.class.newInstance(); Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class); addAssetPath.invoke(assetManager, skinPkgPath);第三步:根据加载器生成Resources对象:
Resources superRes = context.getResources(); Resources skinResource = new Resources(assetManager, superRes.getDisplayMetrics(), superRes.getConfiguration());
完成这三步之后就可以获取对应资源的Resources对象了,我们就可以使用Resource中的资源了,对应换肤就可以实现了。
这上面的三步,本质都是找到资源的路径然后生成对应的Resources对象。
1.apk打包的时候,有几个默认的资源被打包进APK中。
Myapplication.apk(主应用程序)
skin.apk(只包含资源的apk文件,皮肤apk,apk本质是压缩文件)
它们在Android studio中的结构是这样的:
Skin的结构里面什么都没有,除了需要替换的资源文件:结构如下:
怎么创建assets文件夹网上有就不说了。然后将应用打包,安卓到手机之后,assets文件夹下面的文件就被保存在系统统一管理assets文件的路径下了,这个区域我在百度上找了很久,也试了很多最终不能以路径的形式找出来,而只能调用assetsManager的open方法打开对应文件名的inputstream数据流。
只能这样的话,就只有一个思路了,那就是采用异步的形式将inputstream数据流copy到应用的cache文件夹(这个路径获取网上也有,不说了),具体代码如下:
public class Copyutil { public static boolean copyApkFromAssets(Context context, String fileName ) { boolean copyIsFinish = false; String path= context.getExternalCacheDir() + File.separator + "skin.apk"; try { InputStream is = context.getAssets().open(fileName); //关键的代码 File file = new File(path); file.createNewFile(); FileOutputStream fos = new FileOutputStream(file); byte[] temp = new byte[1024]; int i = 0; while ((i = is.read(temp)) > 0) { fos.write(temp, 0, i); } fos.close(); is.close(); copyIsFinish = true; } catch (IOException e) { e.printStackTrace(); } return copyIsFinish; } public static boolean isExistFile(String path){ File f=new File(path); return f.exists(); } }通过上面的代码,我们就可以将skin.apk复制到如下路径
//storage/emulated/0/Android/data/com.example.myapplication/cache/skin.apk
接着调用SkinManager的load函数异步加载assets资源得到Resources对象。
2.从网络下载,放到指定的路径。
原理同1,只不过通过网络把skin.apk下载到下面这个路径
//storage/emulated/0/Android/data/com.example.myapplication/cache/skin.apk