2015年10月26日 星期一

解決 Android Studio 設定檔占用C磁碟之問題

Android Studio 的設定檔預設存放於 C 磁碟,包含 config 與 system 兩個資料夾,使用至今大約有230 MB,若你的 C 碟空間很保貴,可以考慮更改預設的儲存路徑。

這種問題多半在行時 Android Studio 會出現警告「Low disk space on a android studio system directory partition.」,若磁碟真的滿了,後續動作將無法正常執行。

依這篇文章「Android Studio使用问题小结」裡面提供了解決方法,但目前(2015/10)的版本似乎有些出入,但大致上是沒有問題的。

路徑設定步驟

  1. 找到 Android Studio 的安裝路徑,展開至 AndroidStudio\bin。
  2. 用文字編輯器開啟 idea.properties。
  3. 直接新增設定,包含 idea.config.path=D:/xxx/config 與 idea.system.path=D:/xxx/system。

請注意,原本的設定檔若放在 C 碟,可以直接把它搬到上面第3點指定的路徑,讓其能夠正常對應即可。

2015年10月18日 星期日

Cordova 安裝與開發流程

安裝Cordova

Cordova是個跨平台行動應用程式設計的解決方案,主要色是使用HTML, JavaScript, CSS等常見的Web技術來製作App。首先介紹如何安裝,這邊以官方提供的標準安裝方法來進行,依照以下步驟完成(適用Windows):
  1. 至Node.js官方 (https://nodejs.org/) 下載Node.js並安裝。
  2. 開啟「cmd」或「Node.js command prompt」,會出現命令列視窗。
  3. 輸入指令「npm install -g cordova」,將會自動完成Cordova的下載與安裝。

npm install -g cordova


開發前置準備


為使後續開發能順利進行,還需要進行以下設定,各平台可能不太一樣。這邊以Android為例,需先安裝Android SDK,並設定「環境變數」內的「系統變數」,包含:
  1. 新增ANDROID_HOME變數,值為Android SDK的安裝路徑,例如D:\Android\sdk,依你實際安裝路徑為主。
  2. 調整path變數,新增以下兩者,記得用分號「;」隔開:
%ANDROID_HOME%/tools
%ANDROID_HOME%/platform-tools


 建立Cordova專案

安裝好Cordova,即可利用指令的方式建立專案,其指令相當簡單,不需使用其他工具來完成。

  1. 開啟「cmd」或「Node.js command prompt」,利用「cd」指令移到你想建立專案的目錄下。
  2. 使用指令建立專案,參數ProjectName請自行代換為專案名稱,它會作為整個專案的資料夾,且建立在目前的位置上。
  3. cordova create PROJECT_DIR APP_ID APP_NAME
    
    這邊的 APP_ID 即對應到 Android 的 Package Name 與 iOS 的 Bundle Identifier。
  4. 使用指令移至剛才建立的專案目錄內。
  5. cd PROJECT_DIR
    
  6. 依你的需求,將專案加入平台,平台指的是你的App之後要執行在哪,以Android為例,使用指令完成。
  7. cordova platform add android 


開始撰寫程式

Cordova是個跨平台解決方案,還記得在前面我們用「cordova platform add」指令加入了Android平台嗎?你的App最終可能要執行在Android, iOS, WP8, BlackBerry等平台,既然是跨平台,當然希望「寫一次」程式就可以執行在各個平台上,為了實現這個需求,你可以編輯的資源僅限於「www」資料夾內的檔案。

那麼之前在platforms\android\assets\www中看到的檔案呢?若你直接異動它,再透過對應的IDE還是可以產出可執行的App,但無法兼顧其他平台,既然選擇Cordova,最好不要這樣處理。

另外有關App的基本資訊,Cordova為了兼顧多平台,統一將設定放在專案根目錄中的config.xml檔案,若欲調整App名稱與版本等資料請編輯該檔。


編譯與打包

在完成程式的新增與編輯之後(記得,僅存取\www內的資源),於Node.js command prompt執行以下指令即可,執行前請確認有完成「開發前置準備」裡面提到的環境變數設定。
cordova build

值得注意,這個build指令會自動把\www內的東西copy至個平台中的\assets\www,並且依各平台不同特性加入與修正必要檔案,為確保整個流程正確,這部分請不要手動完成。

但是!若你不想要使用這種命令方式來打包成apk檔案,可以借用其他IDE來完成,若你有這個打算,請不要直接執行build,而改用以下指令(不同平台請自行抽換參數):
cordova prepare android


prepare會把相關檔案copy至正確的地方,但不進行編譯與打包之動作。實際上執行前面說的build,它也是自動幫你在背後執行prepare與compile兩個指令。
 

使用Android Studio編譯與打包

基本上透過Cordova CLI可以完成整個開發流程,包括撰寫程式與編譯,但實際上,熟悉Android Studio者,或想以圖形操作介面包完成打包的人,可以將Cordova的Android專案以Android Studio來維護。

個人偏好以這樣的方式進行開發,可以直接執行到實機、觀察Log,而簽署apk時圖形化介面也比較友善。

若前面有將Cordova專案加入Android平台的話,在專案根目錄下,應會產生platforms\android,我們直接使用Android Studio開啟這個目錄,具體的操作方式:

開啟Android Studio,選擇「Import project (Eclipse ADT, Gradle, etc…)」把專案載入,請記得要載入的是Cordova專案中platforms\android目錄。


Δ 選擇「Import project (Eclipse ADT, Gradle, etc…)」把專案載入 

Δ 載入Cordova專案中platforms\android目錄

若Android Studio有提示Android Gradle plugin需要更新,請按下「Fix plugin version and sync project」讓它自動完成即可。

開啟後就依以往的方式把apk檔案打包出來,直接接上實機也可以執行,如同開發原生程式一般。


特別提醒!使用 Android Studio 可以方便的將程式執行到實機,但每次更改程式後,在透過 AS 執行前記得先執行 cordova prepare 指令,否則執行到裝置上的的 App 會是先前的版本


後記

Cordova版本持續更新,本文撰寫於2015/10,使用的Cordova版本為5.3.3。(要查版本可以下cordova -v指令)。未來新版本難保會有不同的處理流程,屆時請大家自行注意。

本文皆以個人經驗撰寫,部分資料來自官方文件,若讀者有更好的解決方案歡迎提供!

下期預告「安裝Cordova Plugin」。


延伸閱讀

  1. APACHE CORDOVA: The Command-Line Interface,
    http://cordova.apache.org/docs/en/5.1.1/guide/cli/index.html
  2. Tiger-Workshop Blog: PhoneGap 與 Cordova 的實際差異,
    http://blog.tiger-workshop.com/difference-between-phonegap-and-cordova/

2015年10月10日 星期六

用程式碼角度談河內塔(Hannoi)

河內塔一直是個經典範例,在資料結構與演算法的相關課程中幾乎是固定班底。本文從「程式碼」開始說起,有些人知道這種問題可以使用遞迴(Recursive)來解,隨手Google一下也都有多種程式語言所實踐的例子,今天直接由程式碼起步,說明原理,希望透過這種方式可幫助大家更易理解。

閱讀前最好要具備的知識:
  1. 河內塔是什麼,本文不再重述,請Google一下。
  2. 參數傳遞與存取,你必須能夠辨別目前存取的變數是在哪裡傳進去的。
  3. 遞回與推疊之間的關係。

河內塔關鍵演算


這邊以Java語言為例,變數宣告建議用小寫,只是本文會反覆提到ABC三個字母,為了閱讀方便以大寫標示。

public void move(int n, char A, char B, char C) {
    if (n > 0){
        move(n-1, A, C, B);
        System.out.println("將第" + n + "個盤子由" + A + " 移至 " + C );
        move(n-1, B, A, C);
    }
}

有什麼方法可以快速容易理解這段程式呢?其實不用想太多,觀察一下可以發現傳入的參數A B C進行了一些奇怪的置換,遞迴呼叫時一下是A C B,一下又是B A C。

其實這種交換只是為了迎合描述當初歸納的規則(後面再提),有看到System.out.println( )嗎?它抓取變數A與C,並套入其他字詞顯示盤子如何移動。因此,在A B C三者中,請先關注A與C位置 (即第一、第三個位置,中間先不理他),目的是要讓輸出的語句能夠符合規則。

不同個數的河內塔


程式碼看完了,接著要理解規則,先考慮三種情況:

1. 只有一個盤子:直接由A柱 → C柱。


2. 兩個盤子:A柱 → B柱,A柱 → C柱,B柱 → C柱。


3. 三個盤子:太長了,直接看圖。

若暫時不看最大的盤子(藍色),是否就相似「兩個盤子」的情況呢?我們針對「兩個盤子」的情況,用最白話的方式來描述盤子是如何移動的:
  1. 把A柱上的小盤子,移到B柱。 (A→B)
  2. 把A柱上的中盤子,移到C柱。 (A→C)
  3. 把B柱上的小盤子,移到C柱。 (B→C)

到這邊,再回頭看看程式碼,是否可以發現:

move(n-1, A, C, B);
System.out.println("將第" + n + "個盤子由" + A + " 移至 " + C );
move(n-1, B, A, C);
  1. 第一行:move呼叫傳入的參數是「A」、「C」、「B」。
  2. 第二行:直接print出第一個變數 → 第三個變數的語句。
  3. 第三行:move呼叫傳入的參數是「B」、「A」、「C」。


這時冷靜一下,想想第一次呼叫 (也就是在外面,例如在main裡面呼叫) move時,傳入的是按照順序的A B C。所以,第二行的print會抓到誰呢?第一個變數是A,第三個變數是C,於是印出「A → C」,但是這行不會馬上印出來,因為在print前還有一個move呼叫!現在回來看看第一行,第一個傳入A,第三個傳入B,可預期的它會印出「A → B」。同理,第三行,第一個傳入B,第三個傳入C,預期會印出「B → C」。看到這邊,你可以發現,這剛好滿足了前面分析的規則順序,即A→B,A→C,B→C。

再來談談「遞迴」,你可以發現move裡面有move,這種自己呼叫自己的行為就是遞迴了,但是一路呼叫沒完沒了,所以要加個條件讓它能有「停下來的機會」,於是有個 n > 0的判斷式,隨著每次呼叫move時傳入的 n – 1,可預期未來會碰上n = 0的情況,從而使遞迴呼叫結束。

最後我們要把這一切串起來!把頭腦當成電腦,開始執行程式吧,還是以「兩個盤子」為例:

  1. move被呼叫了,第一次傳進去的參數是A B C。
  2. 第一行又呼叫了一次move,傳入了A C B (就是把step 1傳入的順序交換一下再傳給下個move)、同時也把 n - 1後傳入。
  3. 注意,現在人在第2個move裡了,嗯?你說第1個move跑去哪了嗎?請暫且忽略它,記得你目前在遞迴,先不要去管第1個move,你只需要一直執行下去。檢查n是否 > 0,若是,再呼叫一次move (第3次),又傳入n – 1與交換過的順序的3個參數。
  4. 現在人在第3個move裡了……

以下請靠想像,再寫下去你看得更亂。你需要知道的重點是,在move裡面,只有System.out.println( )會輸出結果,因此無論傳入的參數怎麼換,它就只會印出第1個 →  第3個這種描述。

那前面被我們無視的「第1次move」呢?現在假設遞回呼叫結束了 (遇上 n = 0),將開始彈出(pop)堆疊,觸發各次呼叫move裡面的print,print完再呼叫第3行的move,又是一連串的遞迴。

而為何使用 n = 0作為遞回結束的條件呢?n在這邊表示盤子的總數,前面一直舉的例子「兩個盤子」即是n = 2。細心的你可能已經發現,第一次呼叫傳入的n是2,但河內塔不是要先移動最上面的盤子嗎?注意在此是以遞回的方式來求解,想想前面「無視第1次move」時,是不是馬上進入第2次的move呼叫了,第1次move還無法進行print,最後在彈出堆疊時,print的執行順序是反過來的,即n = 1印完,再印n = 2 (n=0被排除了,不會印出東西)。

你也可以用比較直觀的方式思考,假設有3個盤子,要移動大盤子(3),是不是要先移動中盤子(2),要移動中盤子(2),是不是要先移動小盤子(1),這就是 n – 1的概念。而一路減到最後,移動是最小、最上面的盤子,因為它沒有阻礙了,於是直接A → C,而因為小盤(1)移走了,所以中盤(2)也沒有阻礙了,於是直接A→B,這不就接回我們前面談的步驟了嗎?

其實在仔細想想,你還會發覺在n =2的情況下,第一步是 A → B。在n = 3的情況下,第一步卻是A → C,但演算法都沒有變,一樣都是第一步,為何會有兩種走法?這就是這個演算法的神奇之處,欲知詳細請見後記。


後記

  1. 以個人的經驗而言,最通盤的理解方法就是透過紙筆來模擬,把整個堆疊的push與pop動作跑一次,並注意每次呼叫move的傳入參數,了解他們是如何互換順序的。
  2. 如果你多試著解4、5、6…n個盤子的問題,可以發現單數盤子第一步是A→C,雙數盤子第一步是A→B,在遞迴呼叫配合ABC交換的情況下,也恰好滿足這種規律。
  3. 還是有障礙嗎?那麼該搬出這句名言了:「遞迴只應天上有,凡人應當用迴圈」。