之前在公司的项目中,需要用到的需求是这样的,当一个应用开启时先去检测是否有对应的资源包(也是个APK,但是没有界面也就是Activity存在,只是单纯的资源),如果有则加载资源包里面的资源,没有的话则加载本身的资源。这样的好处是什么呢?就是以后要修改资源布局的时候,只要改资源包里对应的东西,然后将新的资源包加载进系统就行了,而不用每次都要改本身的应用。大大方便了后续的开发和维护。今天趁着不用加班,有空的时间,整理了一下,不过一个多星期的东西了,凭记忆书写,不知道会不会漏了某些知识点,也在最后放上一个多星期前自己学习用的demo,到时用的时候可以先导入demo的应用apk,再导入皮肤包的apk,这样就能体会到差别了。
无图无真相,先来两张图作对比(第一张是用本应用的资源,第二张是导入了资源包调用资源包里的资源)
废话不多说,直接用代码说话:
1.放入这样的一个Java代码:
写一个SkinResource: 以实现资源的动态加载
package com.jrue.skintest;
import java.io.InputStream;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources.NotFoundException;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
public class SkinResource {
public static final String TAG = "SkinResource";
private static Context mSkinContext = null;
private static Context mLocalContext = null;
public static void initLocalContext(Context context) {
mLocalContext = context;
}
public static void initSkinContext(Context context) {
mSkinContext = context;
}
public static Context getSkinContext() {
return mSkinContext;
}
private static boolean existSkinContext() {
return mSkinContext != null;
}
public static InputStream getSkinRawInputStream(String name) {
int rawId = 0;
if (existSkinContext()) {
rawId = getIdentifier(name, "raw", mSkinContext);
if (rawId == 0) {
rawId = getIdentifier(name, "raw", mLocalContext);
return mLocalContext.getResources().openRawResource(rawId);
} else {
return mSkinContext.getResources().openRawResource(rawId);
}
} else {
rawId = getIdentifier(name, "raw", mLocalContext);
return mLocalContext.getResources().openRawResource(rawId);
}
}
public static View getSkinLayoutViewByName(String name) {
View view = null;
if (existSkinContext()) {// 存在皮肤资源包
view = loadSkinLayoutView(name, mSkinContext);
if (view == null) {
// 资源皮肤中找不到资源,则加载本地资源
view = loadSkinLayoutView(name, mLocalContext);
}
} else {
view = loadSkinLayoutView(name, mLocalContext);
}
return view;
}
public static int getSkinLayoutIdByName(String name, String type) {
return getSkinResourceId(name, type);
}
public static String getSkinStringByName(String name) {
String value = null;
if (existSkinContext()) {
value = loadSkinString(getIdentifier(name, "string", mSkinContext),
mSkinContext);
if (value == null) {
value = loadSkinString(
getIdentifier(name, "string", mLocalContext),
mLocalContext);
}
} else {
value = loadSkinString(
getIdentifier(name, "string", mLocalContext), mLocalContext);
}
return value;
}
public static Drawable getSkinDrawableByName(String name) {
Context context = mSkinContext;
int id = getIdentifier(name, "drawable", context);
if (id == 0 && mSkinContext != mLocalContext) {
context = mLocalContext;
id = getIdentifier(name, "drawable", context);
}
if (id == 0) {
return null;
}
return context.getResources().getDrawable(id);
}
public static Drawable getSkinDrawableByName(String name, String type) {
Drawable drawable = null;
if (existSkinContext()) {
drawable = loadSkinDrawable(
getIdentifier(name, type, mSkinContext), mSkinContext);
if (drawable == null) {
drawable = loadSkinDrawable(
getIdentifier(name, type, mLocalContext), mLocalContext);
}
} else {
drawable = loadSkinDrawable(
getIdentifier(name, type, mLocalContext), mLocalContext);
}
return drawable;
}
public static int getSkinResourceId(String name, String type) {
int layoutId = 0;
if (existSkinContext()) {
layoutId = getIdentifier(name, type, mSkinContext);
if (layoutId == 0) {
layoutId = getIdentifier(name, type, mLocalContext);
}
} else {
layoutId = getIdentifier(name, type, mLocalContext);
}
return layoutId;
}
public static ColorStateList getSkinColorStateList(String name) {
ColorStateList colorStateList = null;
if (existSkinContext()) {
colorStateList = loadSkinColorStateList(
getIdentifier(name, "drawable", mSkinContext), mSkinContext);
if (colorStateList == null) {
colorStateList = loadSkinColorStateList(
getIdentifier(name, "drawable", mLocalContext),
mLocalContext);
}
} else {
colorStateList = loadSkinColorStateList(
getIdentifier(name, "drawable", mLocalContext),
mLocalContext);
}
return colorStateList;
}
public static int getSkinColorByName(String name) {
int color = 0;
if (existSkinContext()) {
color = loadSkinColor(getIdentifier(name, "color", mSkinContext),
mSkinContext);
if (color == 0) {
color = loadSkinColor(
getIdentifier(name, "color", mLocalContext),
mLocalContext);
}
} else {
color = loadSkinColor(getIdentifier(name, "color", mLocalContext),
mLocalContext);
}
return color;
}
private static int loadSkinColor(int id, Context context) {
try {
return context.getResources().getColor(id);
} catch (NotFoundException e) {
e.printStackTrace();
return 0;
}
}
private static int getIdentifier(String name, String type, Context context) {
try {
return context.getResources().getIdentifier(name, type,
context.getPackageName());
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
private static String loadSkinString(int id, Context context) {
try {
return context.getResources().getString(id);
} catch (NotFoundException e) {
e.printStackTrace();
return null;
}
}
private static Drawable loadSkinDrawable(int id, Context context) {
try {
return context.getResources().getDrawable(id);
} catch (NotFoundException e) {
e.printStackTrace();
return null;
}
}
private static ColorStateList loadSkinColorStateList(int id, Context context) {
try {
return context.getResources().getColorStateList(id);
} catch (NotFoundException e) {
e.printStackTrace();
return null;
}
}
private static View loadSkinLayoutView(String name, Context context) {
LayoutInflater layoutInflater = LayoutInflater.from(context);
try {
return layoutInflater.inflate(
context.getResources().getLayout(
getIdentifier(name, "layout", context)), null);
} catch (NotFoundException e) {
e.printStackTrace();
return null;
}
}
public static String[] getSKinStringArraysByName(String name, String type) {
String[] array = null;
if (existSkinContext()) {
array = mSkinContext.getResources().getStringArray(
getIdentifier(name, type, mSkinContext));
if (array == null) {
array = mLocalContext.getResources().getStringArray(
getIdentifier(name, type, mLocalContext));
}
} else {
array = mLocalContext.getResources().getStringArray(
getIdentifier(name, type, mLocalContext));
}
return array;
}
}
2.因为本地资源和资源包虽然使用同个id号,但是使用的是不同的R文件,所以直接使用findViewById()的方式必然报空指针异常,所以这里用了另一种方式:设tag的方式:
这里的VTAG.java专门拿来放空间的tag:
public class VTAG {
public static final String BUTTON_BACK = "btn_back";
public static final String TEXTVIEW_TEST = "textView_test";
public static final String IMAGEVIEW_TEST = "imageView_test";
public static final String BUTTON_ONE = "btn_one";
public static final String BUTTON_TWO = "btn_two";
public static final String TEXTVIEW_DEMO = "tv_demo";
public static final String EDITTEXT_DEMO = "et_demo";
public static final String ERR_VIEW = "err_view";
}
当然id不起作用了,所以布局是这样写的(只截取一段):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/holo_blue_light"
android:orientation="vertical" >
<Button
android:id="@+id/back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/flybtn_back"
android:paddingTop="40px"
android:tag="btn_back"
android:text="返回"
android:textColor="#FFFFFF"
android:textSize="10sp" />
......................................................
</LinearLayout>
3.一个应用怎么跟皮肤资源包进行关联呢?这个当然少不了资源包的包名,所以将此块代码部分放在自定义的MyApplication里,具体如下:
public class MyApplication extends Application {
public Context mContext;
public Context mSkinContext;
@Override
public void onCreate() {
super.onCreate();
initSkinResource();
}
private void initSkinResource() {
try {
mSkinContext = createPackageContext("com.jrue.skin",
Context.CONTEXT_IGNORE_SECURITY);
} catch (NameNotFoundException e) {
e.printStackTrace();
mSkinContext = this;
}
SkinResource.initLocalContext(this);
SkinResource.initSkinContext(mSkinContext);
}
}
其中下面的就是我们资源包的应用包名了。
com.jrue.skin
---------------------------------------------------------------------------分隔线补上补上---------------------------------------------------------------------------------------------------------------------------
突然发现有更好的方式写SkinResource方法,差点忘了,之前的也不删了,同样有用,但是觉得下面的会更有效,用法基本一样,不讲解,直接上代码:
SkinResoure另一种写法:
public class Skinresource {
//tang 换皮肤
public static Context skinContext =null;
public static Context mContext=null;
public static void SetContext(Context context) {
mContext = context;
}
public static void setSkinContext(Context context) {
mContext = context;
}
/**
* tang 换皮肤 获取各种资源
* @param skinPackageContext
* @param resourceType
* @param resourceName
* @param packgeName
* @return
*/
private static int getgetResourcesFromSkin(Context skinPackageContext,String resourceType,
String resourceName,String packgeName)
{
int id=0;
try
{
id=skinPackageContext.getResources().getIdentifier(resourceName,
resourceType, packgeName);
}
catch(Exception e)
{
id=0;
}
return id;
}
/**
* tang 取得皮肤包中的字符串
* @param skinPackageContext
* @param resourceName
* @return
*/
public static String getStringFromSkin(Context skinPackageContext,String resourceName)
{
int id=getgetResourcesFromSkin(skinPackageContext,"string",
resourceName,"com.flyaudio.systemui_skin");
if(id==0)
{
id=getgetResourcesFromSkin(mContext,"string",resourceName,"com.android.systemui");
return mContext.getResources().getString(id);
}
return skinPackageContext.getResources().getString(id);
}
/**
* tang 取得皮肤包中整型参数
* @param skinPackageContext
* @param resourceName
* @return
*/
public static Integer getIntegerFromSkin(Context skinPackageContext,String resourceName)
{
int id=getgetResourcesFromSkin(skinPackageContext,"integer",
resourceName,"com.flyaudio.systemui_skin");
if(id==0)
{
id=getgetResourcesFromSkin(mContext,"integer",resourceName,"com.android.systemui");
return mContext.getResources().getInteger(id);
}
return skinPackageContext.getResources().getInteger(id);
}
/**
* tang 取得皮肤包中Drawable资源
* @param skinPackageContext
* @param resourceName
* @return
*/
public static Drawable getDrawableFromSkin(Context skinPackageContext,String resourceName)
{
int id =getgetResourcesFromSkin(skinPackageContext,"drawable",
resourceName,"com.flyaudio.systemui_skin");
if(id==0)
{
id=getgetResourcesFromSkin(mContext,"drawable",resourceName,"com.android.systemui");
return mContext.getResources().getDrawable(id);
}
return skinPackageContext.getResources().getDrawable(id);
}
public static ColorStateList getColorStateListFromSkin(Context skinPackageContext,String resourceName)
{
int id =getgetResourcesFromSkin(skinPackageContext,"drawable",
resourceName,"com.flyaudio.systemui_skin");
if(id==0)
{
id=getgetResourcesFromSkin(mContext,"drawable",resourceName,"com.android.systemui");
return mContext.getResources().getColorStateList(id);
}
return skinPackageContext.getResources().getColorStateList(id);
}
/**
* tang 取得皮肤包中color资源
* @param skinPackageContext
* @param resourceName
* @return
*/
public static int getColorFromSkin(Context skinPackageContext,String resourceName)
{
int id =getgetResourcesFromSkin(skinPackageContext,"color",
resourceName,"com.flyaudio.systemui_skin");
if(id==0)
{
id=getgetResourcesFromSkin(mContext,"color",resourceName,"com.android.systemui");
return mContext.getResources().getColor(id);
}
return skinPackageContext.getResources().getColor(id);
}
/**
* tang 取得皮肤包中layout资源
* @param skinPackageContext
* @param resourceName
* @return
*/
public static View getLayoutFromSkin(Context skinPackageContext,String resourceName)
{
int viewId=getgetResourcesFromSkin(skinPackageContext,"layout",
resourceName,"com.flyaudio.systemui_skin");
LayoutInflater inflater=null;
View view=null;
Log.d("recy","getLayoutFromSkin "+viewId+"");
if(viewId !=0)
{
inflater = LayoutInflater.from(skinPackageContext);
view =inflater.inflate(skinPackageContext.getResources().getLayout(viewId), null);
}
else
{
viewId=getgetResourcesFromSkin(mContext,"layout",resourceName,"com.android.systemui");
inflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view =inflater.inflate(mContext.getResources().getLayout(viewId), null);
}
return view;
}
/**
* 取得皮肤包中ID
* @param skinPackageContext
* @param resourceName
* @return
*/
public static int getIdFromSkin(Context skinPackageContext,String resourceName,String type)
{
int id=0;
id=getgetResourcesFromSkin(skinPackageContext,type,
resourceName,"com.flyaudio.systemui_skin");
Log.d("recy","getIdFromSkin "+id+"");
if(id==0)
{
id=getgetResourcesFromSkin(mContext,type,resourceName,"com.android.systemui");
}
return id;
}
}
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
然后大体代码的实现就这样了,资源包里的内容和布局也差不多,具体需要看最后的demo吧。