Android使用BuildConfig類製作Logger工具類

    套用微信的廣告語:再小的知識點也體現自己的態度                     -------開場語

簡述:

       在Android開發中,我們使用android.util.Log來打印日誌,一般我們會設置一個全局變量,標記軟件是否顯示日誌,打包發佈之前只要改下DEBUG=false就行了,但是每次在發佈之前都要手動去改這個變量,是不是很不方便?對,那麼有沒有可以不用手動處理而又在發佈時不打印日誌的方法呢?,那麼今天就來研究一個這個問題。

技術預研:

    ADT(r17)發佈以後,Google爲我們提供了一種新的調試機制,即BuildConfig.DEBUG。即:新增了一個特性,允許開發者只在Debug模式下運行部分代碼。Builds會生成一個叫做BuildConfig的類,該類包含一個名爲DEBUG的常量,其常量值會依據開發者的Build類型自動設定。如此,便可以利用BuildConfig.DEBUG來實現只在Debug模式下運行的代碼。
    我們先來看一下BuildConfig這個類在什麼位置,我以新建的一個Demo爲例:現將項目的形式改爲Project,然後依次app—>build—>generated—>source—>BuildConfig,如下GIF動態圖所示:
           

    我們找到BuildConfig類以後可以發現該類的路徑爲:包名.BuildConfig.java.如下:

           

    通過技術預研現得出兩個結論:
        ① Android Studio中BuildConfig.java在app—>build—>generated—>source—>BuildConfig下;
        ② BuildConfig.java的包路徑爲:包名.BuildConfig。

方案設計:

    方案一:BuildConfig類中DEBUG屬性

        根據預研結論二我們在AS中找到BuildConfig類的包路徑爲:包名.BuildConfig,然後直接使用DEBUG屬性或者爲了程序的靈活性利用反射獲取DEBUG屬性值。

    方案二:自定義BuildConfig類

        根據預研結論一我們打開BuildConfig類,然後自定義一個屬性,利用該其作爲Logger的開關的屬性。

 方案實現:

     方案一實現:

       ① 我們直接使用BuildConfig的DEBUG屬性:
/**
 * @author:lizhenya
 * @Time: 2016/11/6
 * @email: [email protected]
 */

public class Logger {
    private static final String TAG = "Logger";

    /**
     * The override method of Logger.
     *
     * The default level of any tag is set to LOGLEVEL 5. This means that any
     * level log will be logged. if your set the LOGLEVEL to 0 , no log will be
     * print out.
     */
    public static int LOGLEVEL = BuildConfig.DEBUG? 5 : 0;
    public static boolean VERBOSE = LOGLEVEL > 4;
    public static boolean DEBUG = LOGLEVEL > 3;
    public static boolean INFO = LOGLEVEL > 2;
    public static boolean WARN = LOGLEVEL > 1;
    public static boolean ERROR = LOGLEVEL > 0;

    public static void setDebugMode(boolean debugMode) {
        LOGLEVEL = debugMode ? 5 : 0;
        VERBOSE = LOGLEVEL > 4;
        DEBUG = LOGLEVEL > 3;
        INFO = LOGLEVEL > 2;
        WARN = LOGLEVEL > 1;
        ERROR = LOGLEVEL > 0;
    }

    public static void v(String tag, String msg) {
        if (DEBUG)
            Log.v(tag, msg == null ? "" : msg);
    }

    public static void v(String tag, String msg, Throwable tr) {
        if (DEBUG)
            Log.v(tag, msg == null ? "" : msg, tr);
    }

    public static void v(String msg) {
        if (DEBUG)
            Log.v(TAG, msg == null ? "" : msg);
    }

    public static void v(String msg, Throwable tr) {
        if (DEBUG)
            Log.v(TAG, msg == null ? "" : msg, tr);
    }

    public static void d(String tag, String msg) {
        if (DEBUG)
            Log.d(tag, msg == null ? "" : msg);
    }

    public static void d(String tag, String msg, Throwable tr) {
        if (DEBUG)
            Log.d(tag, msg == null ? "" : msg, tr);
    }

    public static void d(String msg) {
        if (DEBUG)
            Log.d(TAG, msg == null ? "" : msg);
    }

    public static void d(String msg, Throwable tr) {
        if (DEBUG)
            Log.d(TAG, msg == null ? "" : msg, tr);
    }

    public static void e(String tag, String msg) {
        if (ERROR)
            Log.e(tag, msg == null ? "" : msg);
    }

    public static void e(String tag, String msg, Throwable tr) {
        if (ERROR)
            Log.e(tag, msg == null ? "" : msg, tr);
    }

    public static void e(String msg) {
        if (ERROR)
            Log.e(TAG, msg == null ? "" : msg);
    }

    public static void e(String msg, Throwable tr) {
        if (ERROR)
            Log.e(TAG, msg == null ? "" : msg, tr);
    }

}
        ②使用反射獲取DEBUG屬性值以提高程序的靈活性:
            首先我們寫一個獲取DEBUG屬性值的工具類
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author:lizhenya
 * @Time: 2016/11/6
 * @email: [email protected]
 */

public class BuildConfigHelper {


    public static Boolean isDebug = null;

    public static boolean isDebugBuild() {
        if (isDebug == null) {
            try {
                final Class<?> activityThread = Class.forName("android.app.ActivityThread");
                final Method currentPackage = activityThread.getMethod("currentPackageName");
                final String packageName = (String) currentPackage.invoke(null, (Object[]) null);
                final Class<?> buildConfig = Class.forName(packageName + ".BuildConfig");
                final Field DEBUG = buildConfig.getField("DEBUG");
                DEBUG.setAccessible(true);
                isDebug = DEBUG.getBoolean(null);
            } catch (final Throwable t) {
                final String message = t.getMessage();
                if (message != null && message.contains("BuildConfig")) {
                    isDebug = false;
                } else {
                    isDebug = BuildConfig.DEBUG;
                }
            }
        }
        return isDebug;
    }
}
         其次再在修改Logger類中修改獲取BuildConfig的DEBUG屬性的方式:
public static int LOGLEVEL = BuildConfigHelper.isDebug ? 5 : 0;

    方案二實現:

        我們首先在BuildConfig類中定義一個Logger開關的屬性值:LOG_TOGGLE,完整的BuildConfig類如下:
/**
 * Automatically generated file. DO NOT MODIFY
 */
package com.lzy.buildconfigdemo;

public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String APPLICATION_ID = "com.lzy.buildconfigdemo";
  public static final String BUILD_TYPE = "debug";
  public static final String FLAVOR = "";
  public static final int VERSION_CODE = 1;
  public static final String VERSION_NAME = "1.0";
  // Fields from build type: debug()我們自定義的一個控制Log開關的屬性值
  public static final boolean LOG_TOGGLE = true;
}

   我們知道BuildConfig類是Gradle編譯過程中自動生成的,所以我們得把剛纔自定義的屬性配置到build.gradle中,如下:
    buildTypes {
        release {
            buildConfigField "boolean", "LOG_TOGGLE", "false"
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        debug{
            buildConfigField "boolean", "LOG_TOGGLE", "true"
        }
    }
      在上面我們定義了一個:
 buildConfigField "boolean", "LOG_TOGGLE", "false"
      這個語法規則表示:我們定義了一個boolean變量,變量名爲LOG_TOGGLE,並給變量賦值爲false。
    我們使用如下:
        findViewById(R.id.btn_buildConfig).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (BuildConfig.LOG_TOGGLE) {
                    Toast.makeText(MainActivity.this, "Debug", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(MainActivity.this, "Release", Toast.LENGTH_SHORT).show();
                }
            }
        });
    OK,方案二流程已經熟悉了,那麼我們現在在封裝Logger類如下:
public class Logger {
    private static final String TAG = "Logger";

    /**
     * The override method of Logger.
     * <p>
     * The default level of any tag is set to LOGLEVEL 5. This means that any
     * level log will be logged. if your set the LOGLEVEL to 0 , no log will be
     * print out.
     */
    public static int LOGLEVEL = BuildConfig.LOG_TOGGLE ? 5 : 0;
    public static boolean VERBOSE = LOGLEVEL > 4;
    public static boolean DEBUG = LOGLEVEL > 3;
    public static boolean INFO = LOGLEVEL > 2;
    public static boolean WARN = LOGLEVEL > 1;
    public static boolean ERROR = LOGLEVEL > 0;

    public static void setDebugMode(boolean debugMode) {
        LOGLEVEL = debugMode ? 5 : 0;
        VERBOSE = LOGLEVEL > 4;
        DEBUG = LOGLEVEL > 3;
        INFO = LOGLEVEL > 2;
        WARN = LOGLEVEL > 1;
        ERROR = LOGLEVEL > 0;
    }

    public static void v(String tag, String msg) {
        if (DEBUG)
            Log.v(tag, msg == null ? "" : msg);
    }

    public static void v(String tag, String msg, Throwable tr) {
        if (DEBUG)
            Log.v(tag, msg == null ? "" : msg, tr);
    }

    public static void v(String msg) {
        if (DEBUG)
            Log.v(TAG, msg == null ? "" : msg);
    }

    public static void v(String msg, Throwable tr) {
        if (DEBUG)
            Log.v(TAG, msg == null ? "" : msg, tr);
    }

    public static void d(String tag, String msg) {
        if (DEBUG)
            Log.d(tag, msg == null ? "" : msg);
    }

    public static void d(String tag, String msg, Throwable tr) {
        if (DEBUG)
            Log.d(tag, msg == null ? "" : msg, tr);
    }

    public static void d(String msg) {
        if (DEBUG)
            Log.d(TAG, msg == null ? "" : msg);
    }

    public static void d(String msg, Throwable tr) {
        if (DEBUG)
            Log.d(TAG, msg == null ? "" : msg, tr);
    }

    public static void e(String tag, String msg) {
        if (ERROR)
            Log.e(tag, msg == null ? "" : msg);
    }

    public static void e(String tag, String msg, Throwable tr) {
        if (ERROR)
            Log.e(tag, msg == null ? "" : msg, tr);
    }

    public static void e(String msg) {
        if (ERROR)
            Log.e(TAG, msg == null ? "" : msg);
    }

    public static void e(String msg, Throwable tr) {
        if (ERROR)
            Log.e(TAG, msg == null ? "" : msg, tr);
    }

}

方案比較:

    兩種方案比較,第一種方案直接利用BuildConfig類的DEBUG屬性,這種情況適用於API開發環境較爲簡單的情況,比如就一個測試環境和一個正式環境。第二種方案我們自定義的一個專門的日誌開關屬性,這樣可以適用於多種api開發環境。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章