highlight.js

顯示具有 程式設計 標籤的文章。 顯示所有文章
顯示具有 程式設計 標籤的文章。 顯示所有文章

星期二, 3月 18, 2014

讓 Sublime Text 開啟 Big5 編碼的文字檔


之前嘗試使用 Sumline Text 的時候, 發現無法開啟 Big5 編碼的檔案後就做罷, 今日心血來潮找了一下, 原來早就有人寫好 package 了, 只要參考以下這邊文章安裝 Convert2UTF8 即可:

如何解決 Sublime Text 的中文亂碼? - 海芋小站

 安裝之後, 就可以正常開啟 Big5、GB、JIS 編碼的檔案了。

星期三, 12月 04, 2013

Webkit 要命的修改--支援 DOM4 的 remove()

Webkit 在 2012 年 9 月做了一項變動, 支援 DOM4 的 remove(), 會在執行此方法的元素有父元素時, 刪除掉自己。如果你用 Opera 18 測試以下的 HTML 檔:

<!DOCTYPE html>
<html>
 <head>
  <meta charset="UTF-8">
  <script type="text/javascript">
   function remove() {
    alert("remove is called.");
   }
  </script>
 </head>
 <body>
  <button onclick="remove()">刪除</button>
 </body>
</html>
按一下『刪除』鈕, 你可能預期會執行程式中的 remove(), 顯示訊息窗, 但實際的結果卻是『刪除』鈕不見了, 這是因為按下『刪除』後執行的是內建的 remove(), 而不是程式中所撰寫的 remove(), 而內建的 remove() 就把『刪除』鈕的 button 元素刪除了。

要解決這個問題很容易, 就是不要將 function 取名為 "remove", 不過我想應該有許多舊的網頁上都有以 remove 為名的 function, 如果剛好又是用在類似以上案例的情境下, 就會產生悲劇了!

星期二, 12月 03, 2013

Google Play Service 版本更新

今天收到一封信詢問 Google Map API V2 的問題,由於 API 改版頻繁,一個月前寫的程式在另外一台機器上竟然無法執行, 一跑就當掉。經過一番搜尋之後, 發現 Google Map API V2是屬於 Google Play Service,而 Google Play Service 之前改版到 13, 在這一版中必須在專案的 AndroidManifset.xml 中為 application 元素加上以下的 meta 屬性:
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
google-play-services_lib 程式庫才能正常運作, 否則就會當掉, Android 程式設計之路真是步步驚心啊!

星期六, 9月 14, 2013

Linux 下 Eclipse 的 Java 原始碼編碼設定

由於 Eclipse 的 Java 原始碼預設採用 OS 的編碼, 這在中文 Windows 上是 big-5, 但是在 Linux 上卻是 UTF-8, 所以如果在 Linux 上匯入一個原本是在 Windows 上開發的專案, 就可能會遇到 Java 原始碼中的中文顯示亂碼的情況, 這時可以在 Linux 的 Eclipse 上選取『Window/Preferences』開啟 Preferences 交談窗, 接著切換到『General/Appearance/Content Types』後, 在右側點開『Text/Java Source File』, 並在下方的『Default encoding』填入『BIG5』即可, 詳細畫面如下圖:

星期三, 8月 28, 2013

超簡短的行動裝置瀏覽器 JavaScript 偵測技巧

剛剛看到 stackoverflow 上一篇超讚的回覆, 使用以下的技巧偵測是否行動裝置的瀏覽器:
if(typeof window.orientation !== 'undefined'){...}
由於一般來說, PC 上的瀏覽器都沒有提供 window.orientation 屬性, 因此可以用來快速判別是否為行動裝置的瀏覽器。

當然, 隨著往後 PC 與平版、手機界線的混淆, 也許這個方法會失效, 不過目前應該還堪用, 先學起來!

星期六, 8月 24, 2013

使用 JavaScript 縮放網頁內容

同事開出了一個需求, 希望專為手機製作的網頁若是在桌機上的瀏覽器觀看時, 能夠自動縮小尺寸,不然以現在手機至少 800X400 點數以上的設計, 在手機上看起來大小適中的圖片, 到了桌機上的瀏覽器都會過大。

為了解決這個問題, 第一步是先能判別是手機還是桌機, 這在 detect mobile browser 網站已經提供有現成的 JavaScript 碼可用。接著就是希望能夠縮放網頁內容, 查了各種解法, 看起來要想透過 JavaScript 直接控制瀏覽器的縮放比例是不可行的, 只能透過 CSS 直接縮放網頁內容, 根據 stackoverflow 上這篇問答, 根據瀏覽器的種類, 可分別處理:
  • Firefox 提供有 MozTransform 屬性可以用 scale(1.0) 的格式設定元素的縮放比例, 1,0 就是原尺寸不縮放。
  • Chrome 或是 IE 則可用 zoom 屬性, 以 100% 的格式設定縮放比例。
只要將上述屬性套用在body 元素的 CSS 上, 就可以將整個網頁內容縮放成指定的比例。

不過對於 Firefox, 縮放後網頁的上下左右都會留下大塊的空白區域, 使得縮放後的內容不識顯示在瀏覽器的中央上方處, 要解決這個問題, 必須再使用 MozTransformOrigin 屬性設定為 "center top" 才行。

利用上述方式寫成的 JavaScript 碼如下:

window.onload = function(){
    var a = navigator.userAgent||navigator.vendor||window.opera;
    var level = 60;
    if (!(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))) {
     if (navigator.userAgent.indexOf('Firefox') != -1 && parseFloat(navigator.userAgent.substring(navigator.userAgent.indexOf('Firefox') + 8)) >= 3.6){//Firefox)
         document.body.style.MozTransform = "scale(" + level/100 + ")";
         document.body.style.MozTransformOrigin = "center top";
     }
     else {
      document.body.style.zoom = "" + level + "%";
      document.body.style.msTransformOrigin = "center top";
     }
 }   
};

這個解法在 IE 上也有和 Firefox 類似的問題, 就是網頁內容會偏向瀏覽器視窗的左邊, 而不是在中間上方, 目前還沒有找到解決的方法, 很可惜。

星期日, 3月 24, 2013

JavaScript 的 var

今天有同事問我 JavaScript 變數有加 var 宣告跟沒有有什麼差?我聽了也是一愣, 後來去查了文件才發現, 原來 var 不 var 可有差了, 主要大概可以歸納為這兩點:
  1. JavaScript 是以 function 來建立新的變數 scope, 只要是在 function 之外宣告的變數都是全域變數, 也就是全域物件的屬性, 而只有全域變數可以不用加 var 宣告, 就可以直接使用。
  2. 有加 var 宣告的全域變數是全域物件 (在瀏覽器中就是 window) 的 non-configurable 屬性, 比如說你就無法使用 delete 刪除以 var 宣告的全域變數。
舉例來說, 以這個 html 檔為例:
<!DOCTYPE html>
<html>
<head>
    <script src="http://code.jquery.com/jquery-1.9.1.js"></script>
</head>
<body>
  <div id="da"></div>
  <div id="db"></div>
  <div id="dc"></div>
  <div id="dd"></div>
<script>
i = 10;
var j = 20; 
this.i = 100;
this.j = 200;

$("#da").text(i);
$("#db").text(j);
$("#dc").text(this.i);
$("#dd").text(window.j);
</script>
 
</body>
</html>
實際輸出的結果就是:
100
200
100
200
你可以看到不論是用 i 或是 this.i 都是同一份資料, 這是因為 this 指向全域物件, 所以也可以用 window.j 以存取 j, 因為在瀏覽器中, window 就是全域物件。

如果你在剛剛的 JavaScript 程式中插入兩航程式, 嘗試用 delete 刪除 i 與 j:
i = 10;
var j = 20; 
this.i = 100;
this.j = 200;

delete this.i;
delete this.j;

$("#da").text(i);
$("#db").text(j);
$("#dc").text(this.i);
$("#dd").text(window.j);
在瀏覽器的 JavaScript console 中就會看到以下的錯誤訊息:
Uncaught ReferenceError: i is not defined
這是因為 i 並沒有使用 var 宣告, 是全域物件的 configurable 屬性, 因此可以用 delete 刪除, 所以當執行到底下存取變數 i 的值時, i 變數就已經不存在了。

事情還沒完, 如果你是使用 node.js, 那麼又複雜了一點, 使用 var 宣告的全域變數實際上不是真的全域, 而只能在模組 (可簡單看成是檔案) 內存取, 出了模組, 就無法存取了。以底下的程式為例:
i = 10;
var j =20;

console.log(global.i);
console.log(global.j);
console.log(i);
console.log(j);
執行結果如下:
10
undefined
10
20
透過 node.js 的全域物件 global 可存取到沒有使用 var 宣告的 i 變數, 這是真正全域的變數。可是透過 global 物件嘗試存取 j 變數時, 就會看到 global.j 是未定義的屬性, 這表示 j 並不是真正全域的變數。

如果另外寫個程式把剛剛的測試程式當成模組載入:
var tv = require("./testvar.js");

console.log("global==============");
console.log(i);
//console.log(j);
輸出結果如下:
10
undefined
10
20
global==============
10
可以看到在程式中可存取到在另一個檔案中宣告的變數 i, 的確是全域變數無誤。若是把程式中最後一行的註解拿掉, 嘗試存取 j, 就會看到:
10

D:\mee\My Box Files\practice\jswebapp\testvar2.js:5
console.log(j);
^
ReferenceError: j is not defined
at Object. (D:\mee\My Box Files\practice\jswebapp\testvar2.js:5:13)
可以看到 j 並未定義, 這是因為 j 是用 var 在其他檔案中宣告的變數, 不是全域變數, 所以無法存取。

星期四, 1月 03, 2013

讓 Android 模擬器顯示虛擬按鈕

Android 的模擬器在小尺寸的設定時, 預設都是假設裝置是有 home、menu、back 這些硬體按鈕, 如果你要測試一些 Android 3.0 之後的功能, 像是在 action bar 顯示功能選單, 就會因為預設的設定而不會出現在 action bar 中, 仍然是從螢幕下方滑出來。如果要設定成沒有這些硬體按鈕的裝置, 就必須手動更改模擬器的設定檔。

首先啟動 Android Virtual Device Manager, 會在上方看到模擬器的資料存放的資料夾:


在該資料夾中, 每個模擬器都會以模擬器的名字建立專屬的資料夾。在個別模擬器的資料夾中, 有個 config.ini 檔, 就是有關該模擬器的基本設定:


開啟 config.ini 檔, 找到以下這行:
hw.mainKeys=yes
把設定值改為 no, 存檔後再重新啟動模擬器, 就可以看到模擬器顯示虛擬的按鈕了:




星期五, 12月 07, 2012

.NET SortedList 存放同樣 key 的物件

今天遇到使用 SortedList 時產生例外, 抱怨 key 相同, 這時我才注意到, 原來 SortedList 不能存放相同 key 的物件。不過其實嚴格來說, 並不是 key 相同就不能存放, 而是預設的比較器是很正規的比較, 當兩個比較對象相同時, 就會傳回 0, 而 SortedList 就會抱怨 key 相同, 產生例外。

根據上述, 解決方案其實很簡單, 就是自己實作一個只會傳回 1 與 -1 的比較器, 在建構 SortedList 時傳入, 這樣即使 key 相同也可以存入。比較器的實作非常簡單, 可參考這一篇討論串中一樓的解答


class MyComparer : IComparer
{

  public int Compare(int x, int y)
  {
    if (x < y)
      return -1;
    else return 1;
  }
}
非常簡單。

星期三, 12月 05, 2012

修改 Visual Studio 專案檔的儲存資料夾

我因為常常製作一些功能相近的小程式, 所以都會拿現有的專案複製之後修改, 不過這樣一來, 會遺留許多就專案的痕跡, 自己看了也很不舒服。其中, 有許多設定, 像是專案名稱、組件名稱、命名空間等等都可以在 Visual Studio 裡頭直接修改, 只有儲存的資料夾必須自己手動修改。

對於專案最外層的資料夾, 也就是儲存有 .sln 檔的資料夾, 可以隨意更改名稱, 但是裡層的資料夾 (預設與外層同名), 就必須在修改名稱之後, 再以文字編輯器開啟 .sln 檔, 將其中的資料夾對應到新的名稱才行。例如我有一個叫做 WinTCPTest 的專案:


若想更改紅色框的資料夾名稱, 就要使用文字編輯器修改 WinTcpTest.sln 檔:

只要將 Project 段落中的資料夾名稱改為新的資料夾即可。

星期六, 12月 01, 2012

Xcode 4.5 中 UIDatePicker 在重新開啟專案後寬度莫名其妙變成 480

自從 Xcode 4.5 預設啟用 autolayout 功能後, 許多地方若是沒注意, 就會出現靈異現象。今天我自己遇到的狀況就是在準備送印一本日文翻譯書之前, 整理要附贈的範例光碟, 發現有個介紹 UIDatePicker 的範例開啟後, UIDatePicker 的寬度就莫名其妙變成 480, 超出了 iPhone 預設的 320。

於是我做了個簡單的實驗, 建立一個 Single Page 樣板的專案, 在 Storyboard 中放置一個 UIDatePicker, 如下:
這時即使甚麼事情都不做, 立刻關閉專案, 之後再重新開啟專案, 就會看到 storyboard 的內容變成這樣:
你可以看到 UIDatePicker 突然變寬了, 如果從尺寸檢視面板查看, 會發現寬度變成了 480。不過如果你執行這個程式, 看起來又很正常:
如果一開始建好專案時, 就先把 autolayout 功能取消, 就不會有這樣的問題。目前我也還不知道到底是哪裡出錯?即使啟用 autolayout, 我看了 UIDatePicker 的 constrain 也都沒有甚麼問題, 使用 Xcode 4.5.1、4.5.2 (以及朋友在 4.6) 上都會有一樣的情況, 若您知道問題的癥結, 也請告訴我, 謝謝。

PS:之前我也遇到過 UIView 動畫在 autolayout 啟用時, 使用 center 屬性變更畫面上元件的位置會跑到錯的位置上, 顯然 autolayout 真是值得大家好好研究一番啊!

星期二, 11月 27, 2012

Android 模擬器 Skin 設成 WXGA720 就跑不起來?

Android 模擬器一直是大家詬病的工具, 除了跑得很慢以外, 還回到一些奇奇怪怪的問題, 像是網路上許多人都發生過, 只要把 Android 模擬器設定為 Skin 使用 WXGA720, 像是這樣:

結果一起動模擬器就會出現配置記憶體錯誤, 終止執行。看了各路人馬的補救方案後, 我自己最後要這樣才能跑來, 一是改為自訂解析度 720X1280, 另外則是要很無俚頭的把 Hardware 中 Device ram size 的 1024 加上 mb 字尾, 像是這樣:
就可以執行了。至於原因嘛, 我真的不懂, 但至少這樣可以測試程式了。

星期三, 11月 14, 2012

在 Windows Forms 程式中取得組建檔的版本編號

剛剛想要在視窗的標題列顯示程式的版本號碼 (設定在組建檔的版本編號), 找了許久, 最簡單的應該就是從這裡看到的解答:
this.GetType().Assembly.GetName().Version.ToString ();
當然, 從 GetName() 傳回的物件還可以取得其他與組件檔案相關的資訊可供使用, 需要的可以自己看一下文件囉。

星期四, 10月 18, 2012

callback 到底應該怎麼翻?

由於現在越來越多程式語言或是框架 (framework) 強調非同步技術, 使得 callback 躍登熱門詞彙, 不過這個詞倒底要怎麼翻成中文, 可有點傷腦筋。過去有的人不翻, 有的翻為「回呼函數」, 這我個人認為無法達意;我也看過有作者翻成「回撥函數」, 這取材自回撥電話的意思 , 意思是到了, 但是在程式設計的語句中唸起來就是怪怪的。前幾天讀何孟翰先生寫的《超強圖解 前進 App Store!iOS6 SDK 實戰演練》一書, 他譯為「回應函數」, 我覺得真不錯, 既能達意, 夾在文句中唸起來也不會繞口, 趕緊記下來, 往後就用這個說法。

星期五, 10月 12, 2012

IBOutlet 與 IBAction 到底是什麼?

在學習 iOS 開發的時候, 一定會遇到的就是 IBOutlet 與 IBAction, 這兩個其實是定義在 UIKit 的 UINibDeclarations.h 中的 macro, 定義如下:
#ifndef IBOutlet
#define IBOutlet
#endif 
#ifndef IBAction
#define IBAction void
#endif
從定義可以看出來, IBOutlet 與 IBAction 對於程式碼沒有實質的意義, 存在的作用只是像是標籤一樣, 標示了程式碼中的某個屬性可以用來對應到介面上的某個同樣類別的元件, 或是某個方法可以用來回應規格相符的事件。

星期四, 10月 11, 2012

Xcode 4.5 自動產生 IBOutlet 屬性的改變

前天想說編輯的書最後還是應該用 Xcode 4.5 校稿才對, 結果一升級之後今天測試了一下, 發現了一個討厭的問題, 就是在自動產生 IBOutlet 的屬性時, 在對應的成員變數的命名上不一樣了, 這樣一來, 不就得要改書中的內文以及程式了?

以前如果在 Interface Builder 上從一個 UILabel 產生 IBOutlet 屬性, 假設取名為 myLabel, Xcode 會在 ViewController.h 檔中產生以下這行 @property 指令:
@property (weak, nonatomic) IBOutlet UILabel *myLabel;
同時在 ViewController.m 檔中產生對應的 @synthesize 指令:
@synthesize myLabel;
這樣在 ViewController.m 中就可以直接以 myLabel 操作對應的元件。但是在 Xcode 4.5 中, 已經不會產生 @synthesize 指令, 這會導致編譯時由編譯器自動以如下的 @synthesize 敘述幫你合成 getter 與 setter 方法:
@synthesize myLabel = _myLabel;
也就是將對應的成員變數以你指定的屬性名稱加上 "_" 為字首命名, 使得屬性名稱與對應的成員變數名稱變成不一樣了, 因此無法以 myLabel 操作元件, 而必須加上 self  以 self.myLabel 才能操作對應的元件。當然, 也可以直接使用變數, 但這樣除了違背封裝的意圖, 也會使用到程式中沒有出現過得變數。這下子, 書中原本的程式以及解說的內容都得一併修改, 真是麻煩了。

當然, 這樣的變更主要是為了符合良好的程式撰寫習慣, 讓屬性與成員變數能夠明確地區分開來, 不過能不能有個選項讓我可以選擇要不要接受這樣的改變啊?

PS:如果需要, 還是可以自行把 @synthesize myLabel; 加回去, 只是多一道工, 而且對我來說, 變成還要額外解是為什麼要這樣做, 更是麻煩!

星期六, 10月 06, 2012

Objective-C 的協定 (Protocol)

前幾天在看 iOS 開發的翻譯書稿件, 注意到一件奇怪的事。在使用 UIAlertView 的時候, 有些書都沒有強調擔任 UIAlertView 的委派物件必須遵守 (conform) UIAlertViewDelegate 協定。因此, 如果是由 controller 擔負委派物件時, controller 的類別大概會是這樣:
@interface ViewController : UIViewController
    ....
- (void)alertView:(UIAlertView *)alertView
    clickedButtonAtIndex:(NSInteger)buttonIndex {
    .....
}
@end
事實證明, 這樣的確是可以運作, 連個編譯的錯誤訊息都沒有。當使用者點選了 UIAlertView 上的按鈕時, 的確會引發 clickedButtonAtIndex。

但若是使用 UIActionSheet 時, 書中卻又強調委派物件必須遵守 UIActionSheetDelegate 協定。因此, 如果一樣由 controller 擔任委派物件時, controller 類別大概會長這樣:
@interface ViewController :
        UIViewController<UIActionSheetDelegate>
.....
- (void)actionSheet:(UIActionSheet *)actionSheet
        clickedButtonAtIndex:(NSInteger)buttonIndex {
.....
}
@end
實在覺得很奇怪, 兩個元件的 pattern 其實是一樣的, 但為甚麼一個需要明確標示遵守協定, 另一個卻不用?經過 google 找到這一篇 Why do I not need to declare UIAlertViewDelegate in the header?, 看起來原因有兩個:
  1. 在建立 UIAlertView 的  initXXX 方法中, delegate: 的型態是 delegate:(id), 並沒有要求委派物件必須遵守任何協定。但是在建立 UIActionSheet 的 initXXX 方法中, delegate: 的型態卻是 delegate:(id < UIActionSheetDelegate >), 表示委派物件應該要遵守 UIActionSheetDelegate 協定。
  2. 在 Objective-C 中, 協定的角色似乎沒有其他種類物件導向語言中的界面 (Interface) 那樣嚴謹。事實上, 如果擔任 UIActionSheet 的委派物件並沒有遵守 UIActionSheetDelegate 協定,  只要實作有正確的 clickedButtonAtIndex: 方法, 程式一樣可以動, 只是編譯時會有警告訊息而已。而在 framework 的實作中, 看來也都是以透過 respondsToSelector:@selector(delegatedMethod:) 檢查委派物件是否具有指定的方法, 才會實際叫用該方法, 而不是依靠是否遵循特定的協定來判斷。
換句話說, 協定就只是給大家參考的規格書, 而不是像是其他語言中的界面那樣嚴格。 

星期二, 9月 25, 2012

Eclipse 中文化後變回英文介面

大部分的人都知道可以到 Eclipse 的 Babel 專案頁面中下載中文化的語言包, 讓 Eclipse 變成中文介面。不過 Eclipse 預設會根據作業系統目前的語系設定, 使用對應的語言包。也就是說, 一旦你安裝了繁體中文的語言包, 那麼預設就是中文的介面, 而這在 Eclipse 中並設定畫面可以更改。

如果想將 Eclipse 改回英文介面, 網路上大部分人的作法都是建議在執行 Eclipse 時, 加上參數指定語系為英文, 例如:
eclipse.exe -vmargs   -Duser.language=en” 
為了方便起見, 你可以建立不同的捷徑, 在不同語系之間轉換。不過實際上會想換回英文, 大概也都不需要在不同語系間切換了, 這時可以把上述的參數加到在 Eclipse 資料夾下的 eclipse.ini 檔案中, 例如:
-startup
plugins/org.eclipse.equinox.launcher_1.3.0.v20120522-1813.jar

...............................
-vmargs
-Dosgi.requiredJavaVersion=1.5
-Dhelp.lucene.tokenizer=standard
-Xms40m
-Xmx384m
-Duser.language=en”
這樣執行 eclipse 時就會強制改用英文語系了。

星期六, 9月 22, 2012

錯誤訊息:Missing styles. Is the correct theme chosen for this layout?

Android 開發採用 Eclipse 作為整合開發環境, 不過這 Eclipse 真的是有許多狀況, 今天同事給我一個很簡單的專案檔案, 說怎麼跑都會出錯, 程式當掉。我看了之後, 雖然發現了程式撰寫上的問題, 但還看到一個怪怪的畫面, 我打開 layout 檔案後看到的是這樣:


首先注意到的是怎麼不管是 TextView 或是 Button 的樣子都很怪, 有些字還疊在一起。然後看到下方顯示了 "Missing styles. Is the correct theme chosen for this layout?" 的錯誤訊息, 但明明使用的就是建立專案後預設的 AppTheme 啊?檢查了 styles.xml、AndroidManifest.xml 的內容, 都沒有改過, AppTheme 的定義都沒有錯誤。如果從上方選取 theme 的功能表拉下來看, 會發現原來根本就誤以為專案中沒有定義 AppTheme 這個主題:


顯然一定是資源的相關資料亂掉了, 只好死馬當活馬醫, 先隨便換個現在系統認得的主題:


果然改個主題之後, 畫面看起來就正常多了:


但是下方還有個錯誤訊息, 這次變成找不到 @string/app_name 這個字串資源了, 所以畫面的標題無法顯示 App 的名稱。明明剛剛都沒問題, 也沒去動過 strings.xml 檔, 根據經驗, 當 Eclipse 頭腦不清時, 最有用的作法就是重新啟動 Eclipse, 重新啟動之後果然一切正常, 而且也認得專案中有定義 AppTheme 主題, 就算再選回 AppTheme 也沒有問題:


之後專案就完全正常了, 接著將之前提到有問題的程式碼改正後, 執行起來也都正確無誤。Eclipse, 我真是被你打敗了! (可以來個 Visual Studio for Android 嗎?)

Android Virtual Device 模擬器的儲存位置

我自己的習慣都是把資料單獨儲存在一個分割區中, 與作業系統分開, 不過因為 Windows 預設的使用者資料夾就是在 C, 所以在建立 Android 模擬器時, 預設也都會儲存到 C 下, 經過 Google 一下, 只要設定一個環境變數 ANDROID_SDK_HOME, 指定希望儲存的目的資料夾, 就可以讓 Android Virtual Device Manager 把新建立的模擬器儲存到指定位置了。


這同時也可以解決當使用者名稱有中文時, 無法從包含名稱有中文的資料夾啟動模擬器的問題。