Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android開發者上手寶典(三)

Android開發者上手寶典(三)

編輯:關於Android編程

19.怎麼使用SourceInsight?

19.1用途

我們主要使用SourceInsight進行源碼分析和查找,主要是查找我們所需要的文件/類的位置。對於一套源碼,擁有幾十萬甚至更多個文件,我們可以將這套源碼導入到SourceInsight的工程裡,然後通過它的搜索功能,便能快速給出我們搜索結果:是否有這個文件,同時可以直接打開進行代碼閱讀和修改同步等操作。什麼時候需要這麼做呢?舉一個例子幫助理解:

當我們需要解決一個PR或驗證一個問題時,難免會涉及到一些並不熟悉的文件(布局、資源等xml文件等)/類,這時候,僅僅通過Eclipse或者直接去文件夾下面一個一個尋找的話,無異於於大海撈針費事費力還不一定能找到。這時候,通過SourceInsight便可以在幾秒鐘之內完成尋找任務,何其方便省事!

它的原理是對源碼(你所選取的目錄)下的所有文件建立索引,當你輸入文件名進行搜索時,它便可以快速定位並顯示出來。

19.2安裝

因為我們是在Ubuntu下開發,而SourceInsight這個工具是Windows平台下的,因此涉及到安裝問題。在這裡特別說一下如何進行安裝:使用wine進行安裝。方法如下:

先下載SourceInsight的安裝文件,一般均為後綴為.exe的執行文件,比如sourceinsight.exe,拷貝到一個存儲目錄,例如這裡使用/local目錄;

打開終端,輸入安裝命令:

$wine install /local/sourceinsight.exe

安裝好以後打開,將SN碼復制進注冊框即可。

也就是說我們使用wine進行安裝,以後要使用的時候,在Ubuntu系統的狀態欄下的Application中,會看到Wine菜單,點擊它會彈出Programs文件夾,在其中便可找到安裝好的SourceInsight文件夾,點擊它的logo即可運行。

19.3使用

最後講一下使用SourceInsight的方法:

1.在最上面的菜單欄中,點擊Project→New Project;
2.在彈出的對話框中,點擊Browse,選擇所需要導入的工程目錄。

這裡特別說明一下:導入整個工程或者導入一個模塊均可,例如導入yarism-v1.0-dint或者下面的一個模塊Settings。區別是導入的工程越大,它的初次導入時間越久(文件越多越花時間,可以理解)。但從使用經驗來看,直接導入一整個項目後,在搜索的時候也不會有特別明顯的卡頓。因此,作者個人一般是一整個工程全部導入的。

3.然後,起一個工程名(這個名字是用來在SourceInsight中標記的,並不影響實際源碼,因此請放心隨意起名),為了便於記憶區分,一般即使用源碼工程名,例如使用eyelike-v1.0-dint。

然後點擊OK,彈出一個確認的窗口,繼續點擊OK。這時彈出下面窗口:
SourceInsight導入源碼示意圖vc+zpMqxvOSjrNDo0qrEzdDEtci0/aOpoaM8L3A+DQo8cD40LrW8yOvN6siruvO147v3Q2xvc2Who8i7uvOjrNTaz8LD5srkyOu/8tbQyuTI68jOus7P69KqsunV0rXEzsS8/qOsvLS/yb+0tb3OxLz+wre+trXI0MXPoqOstaW798v50qqy6b+0tcTOxLz+o6y8tL/J1NrX87LgtPK/qrjDzsS8/qGjPGJyIC8+DQo8aW1nIGFsdD0="SourceInsight搜索文件示意圖" src="/uploadfile/Collfiles/20160517/20160517090150360.png" title="\" />
圖x SourceInsight搜索文件示意圖

以上搜索操作即可滿足我們平日裡的需求,是不是非常方便簡單!當你關閉該工程後,可以再次點擊菜單欄最上方的Project,選擇Open Project,然後選擇所要打開的工程即可。

20.如何單編一個模塊?

前面講了代碼的全編譯,但往往耗時較長(例如作者目前使用的i7處理器+8G內存,全編一次Android4.4 Kitkat源碼需要5小時多)。實際開發中,我們一般只是對模塊進行單獨編譯(單編之前必須先進行過全編譯)。例如我只對設置模塊做了修改,那麼就只是單編設置模塊,然後將該模塊單獨刷進手機裡進行驗證即可。

全編譯分MTK平台代碼和Google源碼,單編也是一樣的。

先講在MTK平台下單編一個模塊的方法:

1.進入源碼目錄,例如eyelike-v1.0-dint,輸入如下命令(編譯MTK所提供的基線代碼為例):

$cd /local/eyelike-v1.0-dint/

2.輸入編譯命令:

$./makeMtk –t mm packages/apps/Settings/

說明:上面命令中packages/apps/Settings/為模塊路徑。

將單編後的模塊刷進手機的方法如下:

$adb push out/target/……

省略號表示模塊在系統中的路徑,具體查看方法是:在單編完成後,終端會返回一些信息,其中包含了兩個輸出文件,均是全路徑的格式進行顯示,其中後綴為.APK的全路徑是編譯後的apk在out目錄的全路徑,其中的項目名稱後面的部分即為該模塊在手機系統中的存儲路徑。首先將out目錄中的全路徑復制到push命令之後,然後再將手機的存儲路徑復制到最後,中間用空格區分即可。

特別提示:有時候會報出權限不夠,adb remount一下即可。

然後講Google源碼的單模塊編譯方法:

1.進入源碼目錄,例如kitkat-v1.0-dint,輸入如下命令:

$cd /local/kitkat-v1.0-dint

2.輸入命令:

$source build/envsetup.sh

說明:加載所有所需的系統環境變量。

3.輸入編譯命令:

$mmm packages/apps/Settings/

說明:上面命令mmm後面的部分為模塊路徑。

4.輸入命令:

$make snod

說明:對於Google的源碼驗證只能在模擬器中進行。因為Google源碼中是不包含硬件驅動等內容的,因此,不能向單編MTK平台代碼直接將該模塊push進手機進行驗證測試。要使得編譯後的單個模塊在模擬器中生效,就必須了解加載模擬器的機制。簡單講,模擬器在開啟的時候,會加載下面路徑:

/local/kitkat-v1.0-dint/out/target/product/generic

中的system.img文件,而各模塊的內容均包括在其中,如下圖所示。因此,如果我們編譯了一個模塊後,只要保證將編譯所做的修改更新到該system.img中,然後重新打開模擬器即可看到修改的效果。而上面命令的作用,就是使單編後的修改在system.img中更新生效。
system.img文件示意圖
圖x system.img文件示意圖

5.最後,重新啟動模擬器即可,命令如下:

$./out/host/linux-x86/bin/emulator

特別說明:輸入上面命令後即可啟動模擬器。要關閉該模擬器,直接點擊模擬器右上角的X按鈕即可;也可以在當前終端中按下Ctrl+C組合鍵。另外,第2、3條命令,在一個終端中只需要輸入一次即可,以後只需要鍵入第4條命令即可。但是,如果開啟了新的終端,則需要重新輸入以上所有命令,這點需要特別留意。

21.具備實際項目開發水平的必備技能?

至此,再停下來做一個小結:

我們已有了一個較為熟悉的模塊,能夠進行源碼的下載、更新、全編、單編,能夠查看PR,能夠根據PR需求進行代碼修改。好有成就感和踏實感是不是?此時,只要在閱讀學習代碼和演練PR的時候沒有自我欺騙,應該已能初步負責一些簡單實際項目任務了!恭喜你!

但是,還有一個重要的部分我們還沒有涉及。是什麼呢?——各種提交相關的操作。是的,包括代碼提交、字符串提交、圖片提交等等。難道不是嗎?

22.如何提交字符串和圖片?

我們使用MSGM網站來進行管理項目中的字符串和圖片資源,網址為:aspx">http://eyelike.com/msgm/login.aspx。賬號的申請,首先要在網站登錄界面進行注冊。如下圖所示:
MSGM網站注冊示意圖
圖x MSGM網站注冊示意圖

賬號信息自己按提示填寫即可,沒有特殊規定。然後需要發郵件向集成組組長進行申請Approved。Approved通過後,登陸後進行嘗試即可,其具體使用比較簡單(不過還是推薦向資深同事請教,5分鐘的時間將節省幾小時的嘗試,並能有效習得如何避免犯錯)。

這時,大家肯定會產生疑惑:為什麼要提交字符串和圖片?請看下面內容。

23.為什麼要提交字符串和圖片?

23.1資源分離的原理

要解釋這個問題,這就必須講一下資源分離的機制了!

系統定制是我們公司作為國際性公司的特色(例如華為手機,明明是使用Android系統的手機,打開手機為什麼會看到huawei?為什麼會有各種huawei的應用和元素在裡面?當然是因為我們做了文章和工作,這就是我們做了系統定制),而系統定制的一個重要目的是資源分離。資源分離的主要內容是將代碼與資源(如圖片、字符串、聲音、相關定制值等)分離開。

如何分離開呢?首先講未進行資源分離時的情形,比如Google Android源碼,我們進行編譯使用的是make命令,而make命令的運行機制即是通過多個.mk文件,將源碼中分布在各個文件夾下面的內容一個個按照一定的邏輯順序找到並轉換為機器認識的形式。那麼,我們將原來和代碼在一起(離得比較近)的資源分離出來(統統抽出來放到一個特殊的文件夾/目錄下面)。對於這些多個.mk文件造成的影響就是,它們找不到這些被移走的資源文件了。那麼,我們便想辦法對這些文件的內容進行修改,使得它們重新知道那些被移走的文件到哪裡去了,進而在編譯的時候能夠找到它並生成完整的輸出文件。

概括地講,就是通過對編譯系統的編譯文件的修改,從而改變它的編譯機制。我們因此最終實現創建了一個新的分區(partition)cuspack,將資源分離,並有了一套自己的解析定制資源的機制。

直觀地講,我們最終做到的效果是將一個代碼和資源在一起的APK,分成只有代碼的APK和只有資源的APK兩部分。例如,本來Google源碼中Settings編譯後生成一個Settings.APK的文件;而在經過系統定制後,將編譯生成Settings.APK(只有代碼)和Settings_res.APK(只有資源)兩個文件,其中Settings_res.APK將存放在cuspack分區當中。

上面的兩種闡述,大概講清了系統定制的核心內容。想要深入理解,最好請教集成組framework的同事。當你能非常熟稔地掌握各個編譯控制文件的邏輯時,便完全可以在兩個Team之間任意遨游了(要花很多時間學習熟悉,而且對C語言和腳本要求較多,因為大部分.mk文件是用C語言編寫,而且牽扯較多腳本工具的使用;這個已經和我們的Android系統上層開發維護跑題甚遠了,就此打住)。

23.2資源分離的優點:

最後說一下資源分離的優點:通過資源分離,我們將世界各個不同地區、不同運營商的不同要求所產生的各種修改問題,縮小到只需要修改定制的資源上來。如此一來,核心代碼基本不需要進行修改,所有工作由Perso組代替完成,大大降低了修改不同需求所帶來的人力消耗和維護成本。

23.3原因綜述

正是因為有了這樣的機制,誕生了一個組:Perso組,專門負責這些定制資源的管理。為了提高效率,他們使用一個叫做MSGM的網站。通過它,可以方便地與UE(美工/設計)、開發工程師進行資源的交流。因為不同地區的語言、風格等等差異,手機系統的上層應用會出現各種適配需求(翻譯、圖片等等),這些問題均由開發工程師在工程代碼中進行驗證、確認或修改。所以,提交字符串和圖片便成了一項十分普遍和重要的工作了。

24.代碼的目錄結構?

作為上層開發者,在主代碼根目錄有四個文件夾操作比較頻繁:packages(各模塊代碼主要位於此處)、frameworks(系統框架代碼主要位於此處)、mediatek(MTK代碼主要位於此處),而以“項目名_wimdata_ng”命名的文件夾,則是各定制資源所在。其下,又分若干文件夾:wcustores(主要存放圖片、聲音等資源)、wlanguage(主要存放字符串資源)、wprocedures(主要存放各plf定制值)。如下圖標注。
代碼主要操作目錄示意圖
圖x 代碼主要操作目錄示意圖

25.如何提交代碼?

作為開發人員,解決的很大一部分問題是以PR進行記錄的。而大部分PR的解決又是以修改代碼為主要方式的。既然修改了代碼,怎樣才能提交到服務器?這部分特別重要,因此下面將花費較大篇幅進行詳細講解。

提交代碼的步驟:

25.1提交前的確認工作:

首先我們要確保已經有代碼被修改,其次確保修改後的代碼可以編譯通過,第三要確保所修改的代碼著實可以滿足PR需求。達到這三個要求,即可安心提交。否則,千萬不能提交,一定要保持嚴謹的態度使得三個要求具備,缺一不可。

下面詳細闡述這三個要求的具體內容:

一、很明顯,如果代碼沒有被修改,提交是沒有意義的,這點不多說了;

二、修改後的代碼編譯可以通過,可以保證不會影響整個源碼的編譯工作。即使你所修改的功能不正常,但一般不會影響別人的模塊和功能。這對於團隊協作的開發模式,尤其又是代碼量巨大的工程來說是非常重要的。因為一旦你的提交導致源碼編譯報錯,其他人的工作都會受到影響,從而降低整個團隊的開發效率。

三、我們的修改是為了解決問題,如果所作代碼的修改不能有效解決問題,那麼提交上去只是多此一舉。而且會面臨被測試人員打回的風險(PR往往要送到測試部門的測試工程師那裡去進行驗證,既然沒有滿足修改需求,當然會被打回重新修改),而這是非常嚴重的質量問題。對於一個軟件開發工程師來說,這無疑說明你的能力水平的低下,將嚴重影響你的績效(和工資獎金掛鉤的評比工具,大部分是以打分的形式進行);對於測試工程師來說,使得他增加測試工作量,浪費人力;對於整個項目來說,加長了PR生命周期,拖慢了整個項目進度。由此可以看出,真是有百害而無一利!

然而,怎麼避免出現嚴重的質量問題呢?答案是仔細嚴謹地修改代碼,並一定做好本地驗證工作。

25.2提交代碼的方法:

1.打開終端,進入存儲目錄(本例中進入/local目錄),敲入下面命令:

$cd /local

2.新建代碼提交目錄,例如我們的本地源碼目錄為:kitkat-v1.0-dint,在其中進行了修改,那麼可以建立一個目錄名叫做kitkat-v1.0-dint-temp(名字隨便起,便於標識區分是哪個項目的提交目錄即可)的文件夾(不使用命令直接手動建立當然也是可以的):

$mkdir kitkat-v1.0-dint-temp

3.進入該代碼提交目錄:

$cd kitkat-v1.0-dint-temp

4.從服務器同步項目manifest文件,即代碼下載命令的前面部分(本例的代碼下載命令為:repo init -u [email protected]:aosp/manifest -m kitkat-v1.0-dint.xml && repo sync):
$repo init -u [email protected]:aosp/manifest -m kitkat-v1.0-dint.xml

說明:此時,在這個代碼提交目錄即有了我們的下載配置文件,與我們的源碼目錄kitkat-v1.0-dint中的一致,只是現在我們還未下載任何代碼進來。下面是關鍵的一步,即下載我們需要提交的庫。這裡涉及到庫的概念,即我們的一套源碼,在服務器中是以庫為單位進行存儲的(類似於模塊的概念,只是劃分的維度可能會有所不同)。因此,我們的提交也是對應於庫進行提交的,最直觀地說明就是,我們必須在一個文件目錄下面進行代碼的提交,而這個文件目錄,就是一個“庫”。

我們上層開發主要涉及到的幾個庫為:frameworks/base(在源碼目錄/frameworks文件夾下的修改提交到該庫)、packages/apps(在源碼目錄/packages文件夾下的修改提交到該庫)、xxx(項目名)_wimdata_ng/wprocedures(在源碼目錄/ xxx(項目名)_wimdata_ng下修改了plf文件後提交到該庫)。

本例中以修改SettingsProvider.java類後的提交為例進行說明,該類在源碼目錄/frameworks下面,因此,

5.我們鍵入下面命令,從服務器同步該庫的代碼:

$repo sync frameworks/base

說明:此時,我們的kitkat-v1.0-dint-temp目錄即是服務器中該庫的最新代碼,我們可以想到,與我們本地的kitkat-v1.0-dint目錄中的同樣的庫代碼中,有一個類SettingsProvider.java的代碼是不同的。我們的提交所希望達到的目的便是讓服務器中的同樣的庫同樣的類的代碼與我們本地kitkat-v1.0-dint目錄中的代碼一致。下面便需要借助一個叫做Meld Diff Viewer的對比工具了(後面有教如何安裝)。

6.鍵入命令:

$meld

說明:此時可以打開Meld工具的窗口界面。

6.1點擊最上面菜單欄的File,點擊New,出現如下圖所示界面:
Meld代碼導入示意圖
圖x Meld代碼導入示意圖

6.2點擊圖中Original後面的Browse按鈕,導入未修改的源碼,這裡即下載下來的kitkat-v1.0-dint-temp目錄中的SettingsProvider.java類;

6.3點擊圖中Mine後面的Browse按鈕,導入修改後的源碼,這裡即我們的本地源碼kitkat-v1.0-dint目錄中的SettingsProvider.java類。

6.4然後點擊OK,即可看到兩套代碼中該類的對比,如下圖所示:
Meld代碼對比示意圖
圖x Meld代碼對比示意圖

說明:上圖中右側即為本地修改的代碼,而左側即為服務器下載下來的未修改的代碼,綠色標識出來的即為代碼有差異的部分。中間有個黑色箭頭,點擊它即可將右邊的修改插入到左邊去。

6.5點擊黑色箭頭,將修改導入左側代碼中;

6.6點擊最上面的Save按鈕保存該修改。

說明:此時,kitkat-v1.0-dint-temp目錄中的代碼庫便與kitkat-v1.0-dint中的對應的代碼庫相同了(本例中是frameworks/base庫)。
至此,大家心中應該慢慢有所明了。我們接下來所需做的,便是將kitkat-v1.0-dint-temp中的代碼同步到服務器上。

7.進入kitkat-v1.0-dint-temp目錄下的frameworks/base/:

$cd frameworks/base/

8.查看確認所做修改:

$git status

說明:上面命令可以查看當前目錄是否有修改,是否有提交更新到服務器,如果有修改會將修改的文件顯示出來。

9.接著輸入:

$git diff

說明:這個命令可以將修改的代碼顯示出來,同前面小節所講在Gerrit網站查看修改記錄的效果一致。

10.輸入提交代碼命令:

$ /automount/tools/scm_tools/tools/patch_delivery_cli.php -p ff

說明:至此,所有確認工作OK。

上面命令表示使用patch_delivery_cli.php腳本工具來提交代碼。還記得前面講如何查看別人的PR修改記錄嗎?當時提到我們提交代碼成功後腳本工具會自動在Bugzilla上面的該PR的Comments中插入修改記錄的鏈接,那個腳本工具就是這裡的patch_delivery_cli.php。這下前後連貫起來了,是不是有中恍然覺悟豁然開朗的感覺?又該恭喜你了!

11.接著根據終端出現的提示,輸入對應的信息:

11.1第一個是項目選擇,它會提供所有項目的名稱編號,根據我們的PR屬於哪個項目,輸入對應數字編號按Enter即可。
patch_delivery界面示意圖
圖x patch_delivery界面示意圖

11.2接下來是輸出Bug Number和patch comments等信息,如上圖所示。這裡特別注明:PR號一定要填寫正確,Comments從Bugzilla網站上復制過來即可(我們在提交代碼的時候,一般都同時開著Bugzilla,以復制這些必要信息)。其余根據提示填寫即可,沒有強制規定,但提倡使用嚴謹的語言風格。另外,在patch comments中填寫完畢後,按Enter鍵,然後再出入一個“.”,然後再按Enter鍵才可以進入下一步。其他選填項如果不想填寫,也均使用“.”表示結束,這點需要特別知會。

11.3最後,確認command輸入yes。

說明:此時,代碼提交的任務便提交到了Gerrit網站。又得回顧一下之前所講,Gerrit網站是用來做代碼審核的。

12.登陸Gerrit網站,此時可以看到我們剛才提交的代碼已經對應生成了提交任務,點擊該任務,設置代碼reviewer,如下圖所示:
這裡寫圖片描述
圖x Gerrit添加Reviewer示意圖

在Add Reviewer按鈕左側的輸入框輸入reviewer的郵箱,然後點擊該按鈕即可完成添加。添加成功後可以在下圖中紅色方框標識的地方看到reviewer的信息。
Gerrit添加Reviewer成功示意圖
圖x Gerrit添加Reviewer成功示意圖

這樣Gerrit網站就會自動發郵件到你所設置的reviewer的郵箱,當他登陸Gerrit網站後就可以看到你的修改審核任務。

13.等待審核通過,通過後,重新登錄Gerrit網站。便可以在Gerrit網站上發現一個Submit的按鈕,如下圖所示:
這裡寫圖片描述
圖x Gerrit審核通過示意圖

14.點擊Submit按鈕,當該patch顯示如下圖紅色方框信息後,表示大功告成!
這裡寫圖片描述
圖x Patch提交成功示意圖

特別說明:

一、如果沒有審核通過,你將會受到Gerrit網站自動發給你的郵件通知,你需要做的是重新查看並修改代碼,然後再重新提交。這個操作就不用多贅述了吧!

二、有時候,我們提交代碼比較著急,希望能盡早被審核通過,那麼,提交後直接去代碼reviewer座位上告訴他比較緊急請他盡快review,是最好的辦法。

26.怎麼安裝Meld Diff Viewer?

Meld Diff Viewer是Linux平台下的一款對比工具,可以進行文件、目錄的對比。當然,也有很多人使用另一款對比工具Beyond Compare,其為Windows平台下的一款強大的對比工具,但是收費需要破解。既然我們本身就是在Ubuntu下面工作,那麼使用Meld便可以了。它十分簡潔,而且免費,對於我們提交代碼的對比工作,已經足夠使用。

如果系統中還未安裝,使用下面方式可以進行安裝:

1.打開終端,輸入下載命令:

$sudo apt-get install meld

2.提示輸入密碼:

$eyelike(本機的Ubuntu系統登錄密碼)

如果出現

“Sorry, user user is not allowed to execute ‘/usr/bin/apt-get install meld’ as root on aclgcl-ubnt22”

的錯誤時,說明sudo權限設置還不OK。進行如下設置(因為一般公司中出於安全考慮,管理員權限都沒有下放到開發工程師個人,所以去請集成組同事幫忙設置一下,需要root權限):

1.先輸入命令:

$su

2.然後輸入密碼:

$xxxxx(這個集成組管理系統配置的同事知道)

3.然後進入root賬戶,輸入命令:

$vim /etc/sudoers

4.在其中添加添加user賬戶代碼,如下:

“(復制root賬戶代碼後粘貼,將root字段修改為user即可)”

5.然後保存退出,完成設置,即可正常安裝軟件。

27.怎麼接手實際項目?

至此,已經可以獨立提交代碼了!這也預示著具備接手實際項目的能力了,心中難免激動又忐忑不安,這都是正常的。

其實,比較好的節奏是開始的時候接手一些預研任務。基本任何一個完整的項目,開始都有一段時間的預研,用來將參考項目(一般是之前已經開發的過的項目,很多問題類似,很多代碼可以參考共用)的一些功能需求預先熟悉,導入到我們自己將要開發的項目代碼中來(此時你是可以使用參考的代碼修改來直接解決任務的)。預研任務的特點是難度系數較小,但是任務繁多,再適合熟悉代碼和練手不過了!所以,不要太擔心,你已經一步一步進入實際項目中開始有自己的產出了。

寄語

至此,一名合格的初級開發人員已然成型,假以時日熟悉各種操作和加深對模塊代碼的理解和熟悉,便可達到“海闊憑魚躍,天高任鳥飛”的層次。本文只是將作者從初學到最終能夠接手實際項目的學習過程中所遇到的問題、所認為必須了解掌握的內容整理而成。萬事從無到有難,在茫茫不知所措時曾經極度渴望有人、有文章來指點江山;也曾遇到因為不了解一個小小的知識點而花費大量時間的時候。好在受到非常多的同事、負責的導師等人的幫助指點,最終完成了項目前的學習。這篇文章便是對他們的感謝,也是為像曾經的我一樣懷著對Android開發的熱愛和激情的後來者所寫,希望其中的某些知識能實實在在幫助到他們,給予他們學習的動力。文中難免有勘誤,希望自己沒有犯出誤導大家的根本性錯誤,這樣便滿足了。俗話說知識無止盡,還有非常多的東西沒有抒寫出來,也還有非常多的東西沒有學習。但是,相信只要我們有了足夠的基礎,有足夠多的耐心去學習摸索,那未講的未知的終將變為自己熟悉的、自己能力的一部分,並產生出更多更大的價值。末尾,贈一句:“我們都在路上,加油,與君共勉!”

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved