星期日, 7月 29, 2012

Android 程式中的 Activity.this 是甚麼?

在撰寫 Android 程式時, 許多地方都需要傳遞一個 Context 類別的物件, 這時常常會看到傳入的是 XXXActivity.this, 其中 XXXActivity 就是你的 Activity 類別的名稱, 如果對於 Java 不熟悉, 可能會覺得很奇怪, this 我知道, 但是 Activity.this 是甚麼?

其實這主要是因為在 Android 程式中, 大多數的程式可能都是在事件處理時執行, 而大多數的事件處理都是寫在匿名的內部類別 (Inner Class) 中, 也就是說, 當事件處理執行時, 所屬的物件是內部類別所產生的物件, 因此若是只寫 this, 那麼所指的其實是這個內部類別的物件, 但我們需要傳遞的是外部 Activity 類別的物件 (Activity 是 Context 的衍生類別), 這時就必須在 this 前冠上外部類別的名稱, 而這也就是你會看到 XXXActivity.this 的原因。

如果你還是不大了解, 請看以下這段程式:
public class MyOutterClass {
  String name = "Outter Class";
  MyInnerClass inner = null;

 void callout()  {
  System.out.println("(Outter)this.name=" + this.name);
  System.out.println("(Outter)MyOutterClass.this.name=" +
   MyOutterClass.this.name);
 } 

 public MyOutterClass() {
  inner = new MyInnerClass();
 }
 
 public static void main(String[] argv) {
  MyOutterClass outter = new MyOutterClass();
  outter.inner.callme();
 }
 
 class MyInnerClass {
  String name = "Inner Class";
  void callme() {
   System.out.println("(Inner)this.name=" + this.name);
   System.out.println("(Inner)MyOutterClass.this.name=" +
    MyOutterClass.this.name);
   callout();
  } 
 }
}
執行後的結果如下:
(Inner)this.name=Inner Class
(Inner)MyOutterClass.this.name=Outter Class
(Outter)this.name=Outter Class
(Outter)MyOutterClass.this.name=Outter Class
當內部類別的 callme() 執行時, 可以看到 this 與 MyOutterClass.this 指的分別是內部以及外部的物件, 但是當執行到外部類別的 callout() 時, 這兩種寫法指的都是外部的物件。

補充說明:內部類別是指非 static 的巢狀類別 (Nested Class), 所以每個內部類別的物件一定都有一個版隨的外部類別的物件。

星期二, 7月 17, 2012

詞辨:constant 與 literal

閱讀原文書時, 常會被 literal 這個詞搞混, 其實 literal 的意思很簡單, 就是將某個值使用文字直接表示出來, 這段文字就稱為 literal。舉例來說, 如果有這一行程式:
int a = 20;
這個 "20" 就稱為是一個 literal, 也就是在程式中直接用文字描述 20 這個值, 因為如此, 我會建議將 literal 譯為「字面值」, 取其從字面就可以得知資料值之意。

有些中文書會把 literal 稱為「常數」, 這基本上就誤會了兩個詞彙的意思。constant 指的是某個東西具有不變的值, 例如圓週率, 大家都知道的它的值是固定不變的, 這時候我們會說「圓週率是一個常數, 它的值是 3.14159.......」。在程式語言中, 常數 (constant) 就是指一個具名但內容不會變動的資料, 例如:
const int pi = 3.1415976;
這時我們說 pi 是個常數, 它的值為 3.1415976, 而非 3.1415976 是個常數。這就像是以下這段程式:
int a = 30;
你會說 a 是一個變數, 而不是 30 是個變數。

詞辨:parameter 與 argument

閱讀程式設計的文章時, 常會看到 parameter 與 argument 兩個詞, 在中文中可能都會被翻譯為「參數」或是「引數」, 不過這兩個詞嚴格來說, 是有不同的意義的。追本溯源, 這兩個詞來源自數學中的函數, parameter 指的是在定義函數時給定的變數, 而 argument 指的是使用該函數時實際傳遞給函數的資料。轉換到程式設計中也是一樣, 假設有個 foo 函數, 定義如下:
void foo(int n)
{
    .....
}
那麼 n 就是 parameter, 而在呼叫此函數時, 可能是這樣:

foo(20)
或是
foo(x)
此時 20 或是 x 就是 argument。

在某些程式語言中, 也會把 parameter 稱為 formal parameter, 而將 argument 稱為 actual parameter, 前者表示只是形式上的參數, 告訴程式呼叫此函數時, 需要傳入的資料個數與型別, 而後者表示實際上傳給函數的資料。如果要中文化, 這還真是難倒我了, 但若是 formal parameter 譯為「形式參數 」、actual parameter 譯為「實際參數」, 倒還可以, 但要想兩個詞彙分辨 parameter 與 argument , 還真是有點難啊!目前較通用的翻譯是 parameter 為「參數」、argument 為「引數」, 姑且可以看成「參考格式」、「實際引用」的意思吧。

星期六, 7月 07, 2012

裝完 Ubuntu 後 Grub 開機選單中的 Fedora 不見了!

原本因為工作的關係, 裝了 Fedora 17 測試, 想說乾脆試用看看, 不過使用了一段時間後, 還是不習慣, 所以又裝了 Ubuntu 12.04 版, 沒想到安裝完後怎麼原本 Grub2 開機選單中的 Fedora 不見了?即使在 Ubuntu 中利用 update-grub 重新產生了 /boot/grub/grub.cfg, 仍然就是沒有看到 Fedora 出現。

為了一探究竟, 把安裝 Fedora 的分割區掛載起來看了一下, 奇怪, 怎麼 /boot/grub 下沒有 grub.cfg 檔?又注意到了 /boot 下有另一個 grub2 目錄, 裡頭有 grub.cfg 檔, 難不成就是這個原因?沒辦法, 死馬當活馬醫, 既然這裡有 grub.cfg 檔, 我就在 Ubuntu 下幫 Grub2 新增一個項目, 從這個 grub.cfg 檔複製 Fedora 開機內容試看看囉。

以下是 Fedora 下 /boot/grub2/grub.cfg 中有關第一個選項 (預設就是啟動 Fedora) 的內容:
### BEGIN /etc/grub.d/10_linux ###
menuentry 'Fedora Linux' --class fedora --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-33f4c026-0cb9-4b61-bf8d-17b4b8779488' {
    load_video
    set gfxpayload=keep
    insmod gzio
    insmod part_msdos
    insmod ext2
    set root='hd0,msdos8'
    if [ x$feature_platform_search_hint = xy ]; then
      search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos8 --hint-efi=hd0,msdos8 --hint-baremetal=ahci0,msdos8 --hint='hd0,msdos8'  33f4c026-0cb9-4b61-bf8d-17b4b8779488
    else
      search --no-floppy --fs-uuid --set=root 33f4c026-0cb9-4b61-bf8d-17b4b8779488
    fi
    echo    'Loading Linux 3.3.4-5.fc17.x86_64 ...'
    linux    /boot/vmlinuz-3.3.4-5.fc17.x86_64 root=UUID=33f4c026-0cb9-4b61-bf8d-17b4b8779488 ro rd.md=0 rd.lvm=0 rd.dm=0 SYSFONT=True  KEYTABLE=us rd.luks=0 LANG=en_US.UTF-8 rhgb quiet
    echo    'Loading initial ramdisk ...'
    initrd    /boot/initramfs-3.3.4-5.fc17.x86_64.img
}
只要把這一段複製下來, 貼到 /etc/grub.d/ 下預設提供給我們當範本的 40_custom 檔案中即可 (用貼的最方便, 不然還得研究 Grub2 的指令, 也容易出錯):
#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.
menuentry 'Fedora Linux' --class fedora --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-33f4c026-0cb9-4b61-bf8d-17b4b8779488' {
    load_video
    set gfxpayload=keep
    insmod gzio
    insmod part_msdos
    insmod ext2
    set root='hd0,msdos8'
    if [ x$feature_platform_search_hint = xy ]; then
      search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos8 --hint-efi=hd0,msdos8 --hint-baremetal=ahci0,msdos8 --hint='hd0,msdos8'  33f4c026-0cb9-4b61-bf8d-17b4b8779488
    else
      search --no-floppy --fs-uuid --set=root 33f4c026-0cb9-4b61-bf8d-17b4b8779488
    fi
    echo    'Loading Linux 3.3.4-5.fc17.x86_64 ...'
    linux    /boot/vmlinuz-3.3.4-5.fc17.x86_64 root=UUID=33f4c026-0cb9-4b61-bf8d-17b4b8779488 ro rd.md=0 rd.lvm=0 rd.dm=0 SYSFONT=True  KEYTABLE=us rd.luks=0 LANG=en_US.UTF-8 rhgb quiet
    echo    'Loading initial ramdisk ...'
    initrd    /boot/initramfs-3.3.4-5.fc17.x86_64.img
}
要特別注意前兩行不能改, 只要把剛剛複製的內容貼到 # 開頭的註解行之後即可, 接著再使用 update-grub 指令, 就可以看到這次居然自動找到 Fedora 了:
meebox@meeboxU:~$ sudo update-grub
Generating grub.cfg ...
Found linux image: /boot/vmlinuz-3.2.0-26-generic
Found initrd image: /boot/initrd.img-3.2.0-26-generic
Found linux image: /boot/vmlinuz-3.2.0-23-generic
Found initrd image: /boot/initrd.img-3.2.0-23-generic
Found memtest86+ image: /boot/memtest86+.bin
Found Windows 8 (loader) on /dev/sda1
Found Fedora release 17 (Beefy Miracle) on /dev/sda8
done
接著只要重新開機, 就可以看到開機選單上反而出現了兩個 Fedora 17 的選項, 一個是剛剛我自己加上去, 由 40_custom 自訂的選項, 另一個就是剛剛經由 update-grub 指令, 透過 OS-Prober 自動找到的。雖然兩個選項都可以啟動 Fedora, 不過過程的顯示內容不大一樣, OS-Prober 自動找到的選項啟動過程多是文字, 最後才進入繪圖模式, 從原本 Fedora 的設定檔複製過來的選項開機過程很早就進入繪圖模式, 比較美觀。

後來發現, 其實只要把安裝 Fedora 17 的分割區掛載起來, OS-Prober 的動作就可以自動找到 Fedora 了。另外, 我不知道為甚麼 Fedora 要改將 grub.cfg 放到 /boot/grub2 下, 但根據 Fedora 的文件, 的確是特意如此。

星期日, 7月 01, 2012

Linux Mint 下讓 Firefox 擺脫 DuckDuckGo 搜尋的方法

Linux Mint  預設安裝了 Firefox, 可是在 Firefox 裡預設的搜尋引擎居然變成鴨鴨狗 Duckduckgo, 不但右上角搜尋方塊如此, 連我最常用, 直接在網址攔輸入關鍵值查詢時也都變成鴨鴨狗, 我完全不想研究原因, 只想趕快把預設的搜尋引擎換成 Google, 這一篇文章幫了我大忙:

10 things to do after installing Linux Mint 13 ~ Linux and Life

要將搜尋方塊變回 Google 很簡單, 只要透過方塊左側下拉選單就可以管理搜尋引擎, 第一次使用管理功能會先進入 Linux Mint 對於預設搜尋引擎為甚麼不是 Google 的說明網頁, 接著再選取管理功能就會看到加入 Google 的選項, 只要把 Google 變成搜尋選項的首位, 往後在搜尋方塊就會改用 Google 搜尋了。

網址列的關鍵字搜尋就沒有直接的功能表設定項目可用了, 要進入 about:config, 找到 keyword.URL 項目, 將其內容改為使用 Google 搜尋的 "http://www.google.com/search?q=" 就了, 往後在網址列直接鍵入關鍵字就可以改用 Google 搜尋了。

我對鴨鴨狗實在沒什麼意見, 也相信 Linux Mint 一定有其充分的理由改用鴨鴨狗, 可是我實在不習慣啊!