1. 程式人生 > >Android在debug和release模式自動載入不同的配置檔案

Android在debug和release模式自動載入不同的配置檔案

思路:
1. 判斷當前執行在何種模式下
2. 載入配置檔案

1. 判斷當前執行在何種模式下

當直接在eclipse中執行程式和android tools工具打包時候,會自動修改gen/**/BuildConfig.java中的欄位DEBUG欄位的值

if (BuildConfig.DEBUG) {
    // debug模式
} else {
    // release模式
}

2. 載入配置檔案

使用PULL解析器解析asset中的不同配置檔案,每個配置檔案配置了需要反射的類名稱資訊以及欄位資訊

xml檔案格式:

<?xml version="1.0" encoding="UTF-8"?>
<root> <description></description> <className>com.yanjun.testpowerful.Config</className> <a>1</a> <b>2</b> </root>

解析類:

package com.yanjun.testpowerful.util;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import
java.lang.reflect.Modifier; import java.util.HashMap; import java.util.Map; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import android.content.Context; import android.text.TextUtils; import android.util.Xml; public class LoadConfigUtil { // 解析對應到類 private
static final String TAG_CLASSNAME = "className"; // xml中根節點tag名稱 private static final String TAG_ROOTNAME = "root"; // xml編碼 private static final String XML_ENCODING = "utf-8"; /** * 載入配置 * @param ctx * @param fileName * @throws IOException * @throws XmlPullParserException */ public static void load(Context ctx, String fileName) throws IOException, XmlPullParserException { // 將xml解析為map Map<String, String> content = parser(ctx, fileName); // 檢查類配置 String className = content.get(TAG_CLASSNAME); if (TextUtils.isEmpty(className)) { throw new IllegalStateException("missing configuration: missing " + TAG_CLASSNAME); } Class<?> clazz; try { clazz = Class.forName(className); } catch (ClassNotFoundException e) { e.printStackTrace(); return ; } // 通過反射設定值 Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { try { // 只反射靜態欄位 if ((field.getModifiers() & Modifier.STATIC) != Modifier.STATIC) { continue ; } String fieldName = field.getName(); if (!content.containsKey(fieldName)) { continue; } field.setAccessible(true); field.set(null, content.get(fieldName)); } catch (Exception e) { e.printStackTrace(); } } } /* * 將xml解析為map */ private static Map<String, String> parser(Context ctx, String fileName) throws IOException, XmlPullParserException { Map<String, String> content = new HashMap<String, String>(); InputStream in = ctx.getAssets().open(fileName); try { XmlPullParser parser = Xml.newPullParser(); parser.setInput(in, XML_ENCODING); String lastTagName = null; int eventType = parser.getEventType(); while (eventType != XmlPullParser.END_DOCUMENT) { switch (eventType) { case XmlPullParser.START_DOCUMENT: break; case XmlPullParser.START_TAG: if (parser.getName().equals(TAG_ROOTNAME)) { break; } lastTagName = parser.getName(); break; case XmlPullParser.TEXT: if (lastTagName == null) { break; } String value = parser.getText(); if (value != null) { content.put(lastTagName, value.trim()); } case XmlPullParser.END_TAG: lastTagName = null; break; } eventType = parser.next(); } } finally { if (in != null) { in.close(); } } return content; } }

在Application建立的時候反射具體的配置到類中:

package com.yanjun.testpowerful;

import android.app.Application;

import com.yanjun.testpowerful.util.LoadConfigUtil;

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        // 載入配置檔案
        loadConfig();
    }

    /*
     * 載入配置檔案
     */
    private void loadConfig() {
        try {
            if (BuildConfig.DEBUG) {
                LoadConfigUtil.load(this, "config-debug.xml");
            } else {
                LoadConfigUtil.load(this, "config-release.xml");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
後續:

優點

-可以對生產環境和測試環境使用兩套不同的配置,並動態切換,不用修改程式碼和配置

缺點
-在app啟動的時候使用到了解析xml、反射等技術,可能會額外增加app啟動時間,尤其在配置較多的時候
提示
-減少不必要的配置
-將必須的配置定義到同一個類中,其它常量定義其他類中
-如果使用了混淆,記得去掉混淆xml中配置的類
-如果需要動態載入多個類的配置,可使用多個配置檔案

補充:

當引用Library專案時,使用了Library專案中的BuildConfig類,該類中的DEBUG不會在打包的時候被修改,可以Application啟動的時候通過程式碼獲取程式的模式,並做相應的設定

// 判斷是否是以debug模式執行
if ((getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) == ApplicationInfo.FLAG_DEBUGGABLE) {
    // 設定日誌輸出級別:輸出所有日誌
    LOG_LEVEL = LOG_LEVEL_DEBUG|LOG_LEVEL_INFO|LOG_LEVEL_WARN|LOG_LEVEL_ERROR|LOG_LEVEL_ASSERT;
} else {
    // 設定日誌輸出級別:不輸出
    LOG_LEVEL = 0;
}