好用高擴(kuò)展性的Android平臺(tái)日志框架Slog

Slog

GitHub項(xiàng)目地址:https://github.com/shenbibo/Slog

概述

Slog是一個(gè)輕量級(jí)的Android平臺(tái)的日志庫(kù)笆檀,其是基于對(duì)當(dāng)前開(kāi)源的日志框架LoggerTimber的一個(gè)組合與擴(kuò)展忠怖。具有極大的可擴(kuò)展性预愤,相比于原生Android Log褥影,有以下新特性宝当。

  • 支持對(duì)日志的格式化排版輸出预伺,顯示效果更清晰,更方便查看盖灸。
  • 支持輸出打印日志方法的棧和當(dāng)前線程信息。
  • 支持打印對(duì)象磺芭,支持自定義對(duì)象解析器赁炎,默認(rèn)提供對(duì)數(shù)組,集合等解析钾腺。
  • 支持使用多個(gè)自定義日志適配器徙垫,以決定日志的不同處理方式,默認(rèn)提供LogcatTree適配器放棒。
  • 支持每次打印日志之前自定義日志輸出配置姻报,從而達(dá)到不同的日志輸出效果。
  • 支持自定義日志組裝器间螟,從而顯示不同效果的格式化字符串吴旋。

引用方法

compile 'com.sky.slog:slog:0.4.0'

用法示例

初始化Slog

一般地在應(yīng)用的Application類的onCreate()方法中調(diào)用如下類似代碼。

Slog.init(new LogcatTree());

初始化時(shí)厢破,至少需要傳入一個(gè)日志適配器荣瑟,當(dāng)然我們也可以添加多個(gè)適配器,這個(gè)后面詳解摩泪。

以上是最簡(jiǎn)單的初始化方式笆焰,我們還可以在初始化的時(shí)候?qū)θ罩据敵鲎鋈峙渲茫缦隆?/p>

Slog.init(new LogcatTree())     // 初始化见坑,設(shè)置適配器
    .showThreadInfo(true)       // 設(shè)置是否打印日志的線程的信息
    .prefixTag("test")          // 設(shè)置全局日志的前綴
    .logPriority(Slog.FULL)     // 設(shè)置日志輸出級(jí)別
    .methodCount(2)             // 顯示棧中方法的個(gè)數(shù)嚷掠,默認(rèn)從調(diào)用日志接口的方法往stack下計(jì)算
    .methodOffset(1)            // 顯示從調(diào)用日志打印接口的方法往stack下計(jì)算的偏移數(shù)
    .simpleMode(false);         // 設(shè)置簡(jiǎn)單模式,無(wú)任何格式荞驴,等同于調(diào)用logcat不皆,默認(rèn)值為false.

以上方法的作用與默認(rèn)值。

方法 默認(rèn)值 作用
prefixTag "Android" 設(shè)置全局日志前綴熊楼。
logPriority Slog.FULL 日志的輸出級(jí)別粟焊,F(xiàn)ULL表示可以輸出任何級(jí)別的日志, NONE孙蒙,表示不輸出任何日志。
methodCount 1 設(shè)置顯示棧中方法到最終組裝的日志中的個(gè)數(shù)悲雳,默認(rèn)從調(diào)用日志接口的方法往stack下計(jì)算挎峦。
methodOffset 0 設(shè)置從調(diào)用日志打印接口的方法往stack下的偏移數(shù)。
showThreadInfo false 設(shè)置是否打印日志的線程的信息合瓢。
simpleMode false 設(shè)置簡(jiǎn)單模式坦胶,無(wú)任何格式,不顯示線程信息,方法調(diào)用顿苇,等同于調(diào)用logcat。

注意,上表中合溺,如果simpleModetrue昭躺,則methodCount, methodOffset, showThreadInfo將無(wú)效

另外我們還可以通過(guò)Slog.getSetting()獲取Setting對(duì)象之后,在任何時(shí)候?qū)θ諰og輸出配置項(xiàng)進(jìn)行修改幔翰。

基本使用

使用以下方式初始化Slog漩氨。

Slog.init(LogcatTree()).perfixTag("TestSlog").showThreadInfo(true);

打印普通日志

// 打印普通日志
Slog.d("sky debug");
Slog.i("sky info");

// 打印格式化字符串
Slog.d("this is a format string log, str1 = %s, int value2 = %d, boolean3 = %b", "string1", 2, true);

normal_log

打印錯(cuò)誤日志

// 打印throwable
Slog.e(new Throwable());
Slog.w(new RuntimeException(), "test log with warn priority = %d", Slog.WARN);
error_warn_log

打印jsonxml

jsonxml字符串采用的日志級(jí)別都是Debug的。

打印json字符串

String jsonEmpty = "";
String jsonEmpty2 = "{}";
String jsonNull = null;
Slog.json(jsonEmpty);
Slog.json(jsonEmpty2);
Slog.json(jsonNull);

String json = "{'xyy1':[{'test1':'test1'},{'test2':'test2'}],'xyy2':{'test3':'test3','test4':'test4'}}";

Slog.json(json);

String jsonArray =
        "{ 'employees': [ {'firstName':'John', 'lastName':'Doe'}, {'firstName':'Anna', 'lastName':'Smith'}, "
                + "{'firstName':'Peter', 'lastName':'Jones'}]}";
Slog.json(jsonArray);
json1

json2

打印xml字符串

String androidXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
        "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
        "    package=\"com.sky.tools\" >\n" +
        "\n" +
        "    <application\n" +
        "        android:name=\".application.MainApplication\"\n" +
        "        android:allowBackup=\"true\"\n" +
        "        android:icon=\"@mipmap/ic_launcher\"\n" +
        "        android:label=\"@string/app_name\"\n" +
        "        android:roundIcon=\"@mipmap/ic_launcher_round\"\n" +
        "        android:supportsRtl=\"true\"\n" +
        "        android:theme=\"@style/AppTheme\" >\n" +
        "        <activity android:name=\".main.MainActivity\" >\n" +
        "            <intent-filter>\n" +
        "                <action android:name=\"android.intent.action.MAIN\" />\n" +
        "\n" +
        "                <category android:name=\"android.intent.category.LAUNCHER\" />\n" +
        "            </intent-filter>\n" +
        "        </activity>\n" +
        "    </application>\n" +
        "\n" +
        "</manifest>";

Slog.xml(androidXml);
xml_log

打印對(duì)象

Slog 支持對(duì)對(duì)象的打印遗增,其原理是給每個(gè)不同的對(duì)象類型添加對(duì)應(yīng)的對(duì)象解析器叫惊,默認(rèn)提供對(duì)數(shù)組,集合等解析做修,支持自定義對(duì)象解析器霍狰。

打印null對(duì)象

Slog.i(null);
Slog.i("");
null_object

打印數(shù)組對(duì)象

// 全局多維對(duì)象數(shù)組
private static Object[] objectsArray = new Object[]{
        new boolean[]{false, true, true, false},
        new String[][]{
                new String[]{"22", "23", "24"},
                new String[]{"123", "456", "789"}},
        new int[][][]{new int[][]{
                new int[]{666, 555, 444},
                new int[]{111, 222, 333, 444}},
                new int[][]{
                        new int[]{1, 2, 3, 4, 5, 6},
                        new int[]{7878, 6565, 84155, 7542, 0}}}};


// 打印對(duì)象數(shù)組
Object[] objectArray = new Object[1024];
for (int i = 0; i < objectArray.length; i++) {
        objectArray[i] = i;
}

Slog.i(objectArray);

// 打印String
String[] stringArray = new String[1024];
for (int i = 1024; i < stringArray.length + 1024; i++) {
        stringArray[i - 1024] = "is " + i;
}
Slog.i(stringArray);

// 打印int數(shù)組
int[] intArray = new int[1024];
for (int i = 2048; i < intArray.length + 2048; i++) {
        intArray[i - 2048] = i;
}
Slog.i(intArray);

// 打印多維數(shù)組
Slog.i(objectsArray);
array_log

打印自定義對(duì)象解析器的對(duì)象

有如下一個(gè)Student類。

public class Student {
    private int number;
    private int age;
    private String name;
    private boolean isBoy;

    public Student(int number, int age, String name, boolean isBoy){
        this.number = number;
        this.age = age;
        this.name = name;
        this.isBoy = isBoy;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public boolean isBoy() {
        return isBoy;
    }

    public int getNumber() {
        return number;
    }
}

自定義一個(gè)Student對(duì)象解析器饰及,所有的對(duì)象解析器都必須要實(shí)現(xiàn)Parser接口蔗坯。

public class StudentParser implements Parser<Student> {
    @Override
    public Class<Student> getParseType() {
        return Student.class;
    }

    @Override
    public String parseToString(Student student) {
        return student.getName() + " is a " + student.getAge() + " years old " + (student.isBoy() ? "boy" : "girl");
    }
}

上面的parseToString將在解析對(duì)象時(shí)調(diào)用,由它返回被解析的對(duì)象最終要表示的字符串內(nèi)容旋炒。

// 沒(méi)有添加解析器之前
Student s = new Student(12345, 54, "sky", true);
Slog.d(s);

// 添加解析器之后
Slog.addObjectParser(new StudentParser());
Slog.d(s);
object_parser

打印Collection對(duì)象

這里以Map舉例步悠。

// empty map
Map<Integer, Student> map = new HashMap<>();
Slog.d(map);

// int map
Map<Integer, Integer> intMap = new ConcurrentHashMap<>();
intMap.put(1, 2);
intMap.put(1543, 2745867);
intMap.put(17687, 27678);
intMap.put(76781, 27678);
intMap.put(1786768, 26786);
Slog.d(intMap);

// Object Map
Map<Object, String> objectStringMap = new LinkedHashMap<>();
objectStringMap.put(new Object(), "11223786");
objectStringMap.put(new Object(), "475775486");
objectStringMap.put(new Object(), "7856874757");
Slog.d(objectStringMap);

// student Map
map.put(12345, new Student(12345, 54, "sky", true));
map.put(123456, new Student(123456, 56, "sky2", true));
map.put(1234567, new Student(1234567, 15, "sky3", true));
map.put(12345678, new Student(12345678, 25, "sky4", true));
map.put(1234555, new Student(1234555, 35, "sky5", true));
map.put(12345444, new Student(12345444, 45, "sky6", true));
Slog.d(map);

// map itself
Map map1 = new Hashtable<>();
//noinspection CollectionAddedToSelf,unchecked
map1.put(map1, map1);
Slog.d(map1);
map_log

指定臨時(shí)的配置項(xiàng)打印日志

前面的示例都是不修改輸出配置項(xiàng)時(shí)打印的日志,但是在很多時(shí)候我們可能根據(jù)不同的場(chǎng)景瘫镇,需要采用不同的日志輸出配置鼎兽。

除了前面說(shuō)的使用Slog.getSetting()方法獲取Setting對(duì)象之后,修改全局輸出配置外铣除,Slog框架還支持指定臨時(shí)輸出配置谚咬,只在下次當(dāng)前線程打印日志時(shí)生效一次的方式更改日志輸出效果。

具體包括以下幾個(gè)方法尚粘。

Slog.t()        // 指定下一次當(dāng)前線程打印日志的tag择卦,最終輸出的日志的Tag組合為: prefixTag-tag
Slog.th()       // 指定下一次當(dāng)前線程打印日志是否顯示線程信息
Slog.m()        // 指定下一次當(dāng)前線程打印日志顯示的調(diào)用stack中方法的數(shù)目
Slog.o()        // 指定下一次當(dāng)前線程打印日志顯示stack方法時(shí)的偏移值
Slog.s()        // 指定下一次當(dāng)前線程打印日志是否采用簡(jiǎn)單模式輸出

上面的配置方法可以單個(gè)使用也可以組合使用。

單個(gè)使用

Slog.t("custom22").i("set tag to custom");
Slog.th(false).i("hide the threadInfo");
Slog.m(0).i("test 0 method count print, so hide track");
Slog.m(3).i("test three method count println");
Slog.o(1).i("method offset 1");
Slog.s(true).i("set to simple mode");
temp_setting_log

聯(lián)合使用

Slog.s(false).t("fiveSetting").th(true).m(5).o(2).i("this time set five temp setting for test");
five_temp_setting_log

添加日志適配器

Slog框架目前只提供一個(gè)實(shí)現(xiàn)的日志適配器LogcatTree郎嫁,本框架支持自定義日志適配器秉继,所有的日志適配器都必須要繼承Tree抽象類或者其子類,為了保證足夠的擴(kuò)展性泽铛,我們?cè)?code>Tree的接口中除了可以接收到封裝處理好的日志之外尚辑,也可以對(duì)原始的日志數(shù)據(jù)進(jìn)行處理。

自定義一個(gè)FileTree盔腔。

public class FileTree extends Tree {

    // ... 還有其他的方法也可以根據(jù)需要復(fù)寫(xiě)

    // 處理對(duì)象類型的日志杠茬,注意該接口方法月褥,也可以根據(jù)原始的`originalObject`參數(shù)進(jìn)行自定義處理
    @Override
    protected void prepareObjectLog(int priority, String tag, String[] compoundMessages, @Nullable Object originalObject) {
        super.prepareObjectLog(priority, tag, compoundMessages, originalObject);
    }

    // 處理String類型的日志,注意該接口方法瓢喉,也可以根據(jù)原始的`originalMessage`參數(shù)進(jìn)行自定義處理
    @Override
    protected void prepareStringLog(int priority, String tag, Throwable t, String[] compoundMessages, @Nullable String originalMessages, @Nullable Object... args) {
        super.prepareStringLog(priority, tag, t, compoundMessages, originalMessages, args);
    }

    // 該方法為必須要實(shí)現(xiàn)的父類抽象方法
    @Override
    protected void log(int priority, String tag, String message) {
        // ... 省略代碼將日志保存到文件中
    }
}

將其添加到日志適配器列表中宁赤,以后就可以正常使用了。

Slog.plantTree(new FileTree());

注意: 在每個(gè)日志適配器中栓票,我們可以根據(jù)需要最終自己確定將組裝之后的日志或者原始日志如何處理决左。

自定義日志組裝器

通過(guò)繼承LogAssembler抽象類,我們可以實(shí)現(xiàn)自己定義的日志組裝器逗载。

public class SimpleLogAssembler extends LogAssembler {

    @Override
    protected void onFormatModeLogMethodStackTrace(List<String> compoundMessagesList, int methodCount, int stackOffset,
            StackTraceElement[] trace) {
        for (int i = methodCount; i > 0; i--) {
            int stackIndex = i + stackOffset;
            if (stackIndex >= trace.length) {
                continue;
            }

            //noinspection StringBufferReplaceableByString
            StringBuilder builder = new StringBuilder();
            builder.append(getSimpleClassName(trace[stackIndex].getClassName()))
                   .append(".")
                   .append(trace[stackIndex].getMethodName())
                   .append("(")
                   .append(trace[stackIndex].getFileName())
                   .append(":")
                   .append(trace[stackIndex].getLineNumber())
                   .append(")");

            compoundMessagesList.add(builder.toString());
        }
    }

    @Override
    protected void onFormatModeLogThreadInfo(List<String> compoundMessagesList, Thread curThread) {
        compoundMessagesList.add(Helper.createThreadInfo(curThread));
    }

    @Override
    protected void onFormatModeLogContent(List<String> compoundMessagesList, Throwable t, Object originalObject, Object[] args) {
        String[] compoundMessages = compoundMessage(t, originalObject, args);
        for (String compoundMessage : compoundMessages) {
            String[] splitMessages = compoundMessage.split(LINE_SEPARATOR);
            Collections.addAll(compoundMessagesList, splitMessages);
        }
    }
}

以上三個(gè)方法是子類必須要實(shí)現(xiàn)的哆窿,還有其他的方法子類可以選擇性的復(fù)寫(xiě)。

以下是調(diào)用實(shí)例厉斟。

Slog.setLogAssembler(new SimpleLogAssembler());
Slog.i("set log assembler to simple");
Slog.m(10).i("simple log assembler set methodCount to 10");

// 設(shè)置為null挚躯,將使用默認(rèn)的日志組裝器
Slog.setLogAssembler(null);
Slog.i("Slog.setLogAssembler(null), so turn to default log assembler");
set_log_assembler

另外,我們也可以在初始化時(shí)調(diào)用Slog.init(Tree, LogAssembler)方法時(shí)進(jìn)行指定日志組裝器擦秽。

SlogTest測(cè)試用例集

更多的用法可以參考slog/src/androidTest/java/com.sky.slog/SlogTest.java码荔。

結(jié)構(gòu)概述

Slog打印日志的基本流程可以歸納為以下幾個(gè)步驟。

  • 打印日志感挥,調(diào)用對(duì)應(yīng)的Slog接口缩搅。
  • 根據(jù)當(dāng)前日志全局配置,判斷是否對(duì)需要輸出日志(當(dāng)前是只判斷允許輸出的日志級(jí)別Priority)触幼。
  • 結(jié)合全局日志配置和單次指定的日志配置(單次優(yōu)先級(jí)高于全局)硼瓣,對(duì)原始日志進(jìn)行組裝。
  • 將組裝好的日志和原始日志數(shù)據(jù)通過(guò)日志分發(fā)器分發(fā)到各個(gè)日志適配器置谦。
  • 每個(gè)日志適配器最終根據(jù)自身實(shí)現(xiàn)對(duì)日志進(jìn)行處理堂鲤。

簡(jiǎn)單的流程圖。

slog_流程圖
slog_流程圖

簡(jiǎn)單的類圖媒峡。

Slog結(jié)構(gòu)類圖
Slog結(jié)構(gòu)類圖
  • LogAssembler瘟栖,日志組裝器的抽象類,負(fù)責(zé)對(duì)日志進(jìn)行組裝谅阿,調(diào)用分發(fā)器將組裝好的日志進(jìn)行分發(fā)半哟。
  • LogDispatcher,日志分發(fā)器接口签餐。
  • LogController寓涨,分別實(shí)現(xiàn)了TreeMangerLogDispatcher接口氯檐,通過(guò)其分發(fā)日志功能缅茉,將日志分發(fā)到其管理的日志適配器中。

致謝

本庫(kù)最終形成男摧,分別參考了以下三個(gè)庫(kù)蔬墩,本庫(kù)的設(shè)計(jì)借鑒了它們的設(shè)計(jì)思想與代碼實(shí)現(xiàn),十分感謝耗拓。

Logger : https://github.com/orhanobut/logger

Timber : https://github.com/JakeWharton/timber

ViseLog : https://github.com/xiaoyaoyou1212/ViseLog

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末拇颅,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子乔询,更是在濱河造成了極大的恐慌樟插,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件竿刁,死亡現(xiàn)場(chǎng)離奇詭異黄锤,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)食拜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門鸵熟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人负甸,你說(shuō)我怎么就攤上這事流强。” “怎么了呻待?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵打月,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我蚕捉,道長(zhǎng)奏篙,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任迫淹,我火速辦了婚禮秘通,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘千绪。我一直安慰自己充易,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布荸型。 她就那樣靜靜地躺著盹靴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瑞妇。 梳的紋絲不亂的頭發(fā)上稿静,一...
    開(kāi)封第一講書(shū)人閱讀 49,111評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音辕狰,去河邊找鬼改备。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蔓倍,可吹牛的內(nèi)容都是我干的悬钳。 我是一名探鬼主播盐捷,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼默勾!你這毒婦竟也來(lái)了碉渡?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤母剥,失蹤者是張志新(化名)和其女友劉穎滞诺,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體环疼,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡习霹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了炫隶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片淋叶。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖等限,靈堂內(nèi)的尸體忽然破棺而出爸吮,到底是詐尸還是另有隱情,我是刑警寧澤望门,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布形娇,位于F島的核電站,受9級(jí)特大地震影響筹误,放射性物質(zhì)發(fā)生泄漏桐早。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一厨剪、第九天 我趴在偏房一處隱蔽的房頂上張望哄酝。 院中可真熱鬧,春花似錦祷膳、人聲如沸陶衅。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)搀军。三九已至,卻和暖如春勇皇,著一層夾襖步出監(jiān)牢的瞬間罩句,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工敛摘, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留门烂,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像屯远,于是被迫代替她去往敵國(guó)和親蔓姚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理慨丐,服務(wù)發(fā)現(xiàn)赂乐,斷路器,智...
    卡卡羅2017閱讀 134,600評(píng)論 18 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,518評(píng)論 25 707
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,748評(píng)論 6 342
  • 曉風(fēng)拂柳絮咖气,化聲蘆葦中。旭日當(dāng)空照挖滤,留影松柏下崩溪。汪月今將現(xiàn),此刻祝中秋斩松×嫖ǎ——by Aman正義 招財(cái)進(jìn)寶,不負(fù)年華...
    Lii閱讀 500評(píng)論 0 0
  • 悟在藍(lán)蓮花下 忘記了憂傷帶來(lái)的疼痛惧盹,遺忘了痛苦帶來(lái)的清晰的傷疤乳幸,丟掉了沉重包袱這個(gè)累贅,把卑微放在孤寂的門口,孤單...
    孫子曰閱讀 452評(píng)論 4 5