2013年12月29日 星期日

如何檢查你目前Ubuntu 桌面是使用 Unity-2d 或 Unity-3d 與確定目前系統是否有支援 Unity-3d

       檢查 Ubuntu 桌面是使用 Unity-2d 或 Unity-3d 你可以透過 "echo $DESKTOP_SESSION" 命令來檢查,執行畫面如下:

      如果目前使用 Unity-2d 會顯示 Ubuntu-2d,Unity-3d 則只會顯示 Ubuntu。

      另外如果你要確定系統是否有支援 Unity-3d,你可以透過 "/usr/lib/nux/unity_support_test -p" 來檢查,執行畫面如下:


[參考連結]

解決使用 Intel G840 啟動 VirtualBox 3D 加速 VirtualBox 會當機的問題

     在VirtualBox中安裝 Ubuntu 12.04 LTS後,如果你沒有啟動 VitualBox 3D 加速,進入 Ubuntu 後使用的是 Unity-2d,如果你想要使用 Unity-3d 你必須要啟動 VitualBox 的 3D 加速。設定的方式如下圖:

    但當啟動 3D 加速時,重新啟動虛擬時你也許會遇到 VirtualBox 會莫名的當機,無法正常開啟你的虛擬機,最後更新 Intel G840 HD Graphic 驅動程式後,就解決啟動虛擬機會當機的問題了,如果你有遇到類似的問題,或許可以嘗試更新你的顯示卡驅動程式來解決問題。
 


如何在 Windows XP 下透過 VirtualBox 安裝 64 bits Ubuntu 12.04 LTS

    如果你想要在 Windows XP 下安裝 64 bits Ubuntu 12.04 LTS,你必須確定下列項目你都已經設定好了,才可正常安裝:
  1. 啟動 VirtualBox VT-x / AMD-V ( VirtualBOx 4.3.12 如果 BISO 沒有先開啟支援虛擬化技術,加速的頁面是無法點選。), 如下圖:

  2. 啟動 BIOS 中 CPU 的虛擬化技術(Virtualization technology)。 
    如果你沒有在 BIOS 中啟動虛擬化技術時,當你啟動你的 VirtualBox 中的 Ubuntu 時,會看到如下的警告視窗:

 
    即便你點選繼續最後會停在開機畫面無法正常進入 ;其實從上面的訊息中 "請確認在您主機電腦的 BIOS 中已正確啟用 VT-x/AMD-V",就已經告訴你如何解決問題了。只要從新開起進入到 BIOS 中啟動虛擬技術就可以正常的啟動安裝 64 bits Ubuntu 12.04 LTS。

    下圖為 ASUS 主機板設定的方式:

後記:
       重新安裝電腦後,BIOS 也已經啟動虛擬技術,但 VirtualBox 依然無法正常偵測到 VT-x,找了老半天,還以為是 Windows 7 跟 VirtualBox 哪邊不和需要設定,最後發現是因為安裝了avast free antivirus 的防毒軟體,移除後就可以正常偵測到且可以正常起動Guest OS。之前無法執行 Windows 的磁碟掃描也是因為它。似乎要考慮別的免費防毒軟體了。 XD


[參考資料]
     
    

2013年12月5日 星期四

LINE: 發生錯誤,請重撥(101),伺服器無法使用請檢查網路連線

     最近在家用 LINE 透過 WIFI 打免費電話時,發生一些問題,撥打時沒有 ringtone 而且人家打電話進來也沒有 ringtone 且無法接起電話,最後 LINE 就顯示 "發生錯誤,請重撥(101),伺服器無法使用請檢查網路連線",一度還以為是我的手機問題,氣到想要把它摔掉。後來發現兇手是 WIFI 基地台,今天突然想起,之前我有重新設定 WIFI 基地台,有重新設定防火牆,死馬當活馬醫,我把 "Enable SPI and Anti-DoS firewall protection" 選項給取消後,LINE 終於可以正常撥接了。

2013年12月2日 星期一

修改 Android Emulator 的 Abstracted LCD density

      如果你用 ADT 來編輯目前 AVD 的 Abstracted LCD density 值時,你會發現在 Hardware 欄位那邊你只能下拉選擇數值而不能填入你想要的值,如下圖所示:
    注意:因為這個 AVD 我是用舊版的 ADT 所產生的,所以還看的到Hardware 的屬性設定。新版的,你可以在 Device Definitions 頁面,按 【New Device...】在新增裝置時設定,但我找不到可以設定 LCD density的數值,它似乎會根據你所設定螢幕解析度的是屬於 ldpi 或者 mdpi 來填入預設的數值。不過修改 LCD density 的方式是一樣的。

     從上圖你可以看到只有 120 、160、240...等數值可以選擇,而且你無法修改。修改的方式是到你的 .android 目錄下找到 AVD 資料夾,然後開啟 config.ini 檔案,修改 【hw.lcd.density】的數值即可。如下圖所示:


列印例外訊息 printStackTrace()、toString()、 getMessage()

     當我們處理 Java 例外時,通常會在例外捕獲時列印例外的訊息,一般在輸出訊息通常使用 printStackTrace()、toString()、 getMessage() 這三種方法列印出例外訊息。
     而輸出訊息的格式請參考下面圖示:

  • printStackTrace ()方法 輸出如下
  • java.io.FileNotFoundException: abc.txt (系統找不到指定的檔案。)
     at java.io.FileInputStream.open(Native Method)
     at java.io.FileInputStream.<init>(Unknown Source)
     at java.io.FileInputStream.<init>(Unknown Source)
     at ExceptionExample.someMethod(ExceptionExample.java:7)
     at ExceptionExample.main(ExceptionExample.java:19)
    
  • toString()方法 輸出如下
  • java.io.FileNotFoundException: abc.txt (系統找不到指定的檔案。)
    
  • getMessage()方法 輸出如下
  • abc.txt (系統找不到指定的檔案。)
    
    另外我們故意讓程式丟出 NullPointerException,透過上面三種方法輸出例外訊息,其範例與輸出結果如下:
  • 範例
  •     String str = null;
        try {
             str.length();
        } catch (Exception e) {
             e.printStackTrace();
        }
    
  • printStackTrace()
  • java.lang.NullPointerException
     at ExceptionExample.main(ExceptionExample.java:30)
    
  • toString()
  • java.lang.NullPointerException
    
  • getMessage()
  • null
    
     在上面的 NullPointerException 例子,toString() 與 getMessage() 幾乎沒有任何幫助,基本上,除非是自訂的例外或者可以明顯知道例外的輸出的解果發生在哪個地方,例如,我們只在某個地方開啟特殊的檔案,則我們可以考慮使用  toString() 與 getMessage() 來減少除錯訊息的輸出,否則建議還是直接 printStackTrace() 方法輸出詳細的例外訊息。

[參考資料]




2013年12月1日 星期日

String equals( ) 與 compareTo( ) 方法的不同

     Java 中要比對字串是否相等,我們可以使用 equals 或者 compareTo 方法來實現,但是它們之間有甚麼不同呢 ? equals 與 compareTo 之間主要的不同有下面兩點:

  1. 如果傳入的參數是 null 時, equals  總是回傳 false,而 compareTo 則是丟出 java.lang.NullPointerException。
    範例如下:
     "foo".equals((String)null)  // 回傳 false
     "foo".compareTo((String)null) == 0 // 丟出 NullPointerException
    

  2. compareTo 除了可以比對字串是否相等外,還可以得知哪一個字串比較大或者小,equals 只能比對是否相等。
     另外好奇的是,為何將 null 傳入 equals 裡面會沒事,看了一下原始碼你會發現類似下面的程式碼:
   if (anObject instanceof String) {
      ...  
   }
    而 null 是物件的參考常數值,它可以被任何物件所參考,但它不屬於任何物件。也就是說 null instanceof object 總是回傳 false,故在將它傳入 equals method 並不會丟出任何例外。

    下面是從 Oracle 上查詢到的資料,解釋有關 null type。有興趣的人可以連結過去查看。
4.1. The Kinds of Types and Values
There is also a special null type, the type of the expression null (§3.10.7, §15.8.1), which has no name.
Because the null type has no name, it is impossible to declare a variable of the null type or to cast to the null type.
The null reference is the only possible value of an expression of null type.
The null reference can always undergo a widening reference conversion to any reference type.
In practice, the programmer can ignore the null type and just pretend that null is merely a special literal that can be of any reference type.   

2013年11月24日 星期日

Eclipse 設定編碼方法

      當你載入其他人開發的專案或檔案時,有時會發現奇怪的字元時,就表示你的 Eclipse 預設的編碼方式與專案不同。 Eclipse IDE 提供三種設定編碼的方式:

  1. 設定單一檔案的編碼:只有該檔案被設定此編碼。
  2. 設定單一專案的編碼:只有所選的專案設定為此編碼。
  3. 預設所有專案的編碼:所有你新開的專案都以此設定為主,在 Windows 平台建議選擇 UTF-8 (繁體 Windows上 Eclipse 預設使用 MS-950 編碼 ),這樣切換到 Linux 上才不會要再設定一次。
      這三種設定的方式請參考下面的圖示:

  • 設定單一檔案的編碼


    • 設定專案的編碼
    • 預設所有專案的編碼

    [延伸閱讀]
         

    2013年11月17日 星期日

    解決 HTC One SV 更新後 "開發者選項" 不見的問題

        昨天更新我的 HTC One SV 後,今天發現開發者選項竟然不見了,上網查到的解決方式如下:
              設定>關於>軟體資訊>更多>狂按 建置號碼


    參考資料:

    旋轉 Windows 畫面

        今天電腦讓小朋友亂按,結果開始列跑到右邊去,上網查了一下如何旋轉畫面,終於把畫面給轉回來了~: )

        如果你想要旋轉 Windows 畫面可以透過下面的 Shortcut Key:
    1. Ctrl + Alt + Up Arrow  (這是我們一般操作的畫面 開始列在下方)
    2. Ctrl + Alt + Down Arrow (開始列在上面,畫面上下顛倒)
    3. Ctrl + Alt + Right Arrow (開始列在右邊)
    4. Ctrl + Alt + Left Arrow (開始列在左邊)
    參考資料:

    透過 getenv 與 getProperties 取得系統環境變數與JVM屬性設定

          在 Java 中我們可以透過 System.getProperties() 取得 JVM 參數設定System.getenv() 來取得作業系統的環境變數設定。你可以在 The Java Tutorials 裡面參考 System Properties 與 Environment Variables 教學文章看到其他用法。

         如果你使用 Eclipse 你可以透過 -D<Key>=<Value> 的方式在 Run > Run Configurations... > (x)= Arguments > VM Arguments 來設定額外的 JVM 屬性設定。例如你可以填入 -DColor=blue 來設定 Color 屬性為 blue。如下圖所示:


    簡易的範例程式如下:
        // 列出目前所有的 JVM 屬性設定
        System.getProperties().list(System.out); 
        
        // 透過 getProperty 單獨取出特定的某個屬性設定值    
        System.out.println("Color = " + System.getProperty("file.separator"));    
    
        // 取出我們設定的屬性值,注意屬性名稱是 case sensitive
        // 如果你寫成 color 得到的會是 null
        System.out.println("Color = " + System.getProperty("Color"));
    
        // 你也可以使用下列方式,當所指定的屬性沒有鍵值時,回傳你所設定的預設值
        // 下面的範例當沒有設定 Color 屬性鍵值時會回傳預設的 Pink 值
        System.out.println("Color = " + System.getProperty("Color", "Pink")); 
    
        // 列出目前作業系統所有的環境變數設定
        Set<Map.Entry<String, String>> envSet = System.getenv().entrySet();
        for (Map.Entry<String, String> set: envSet) {
            System.out.println(set.getKey() + " = " + set.getValue());
        }
        // 透過 System.getenv(key) 的方式單獨取出你想要的屬性設定
        System.out.println("SystemDrive = " + System.getenv("SystemDrive"));
        System.out.println("TEMP = " + System.getenv("TEMP"));
    


    參考文章:



    2013年11月13日 星期三

    保護回傳參考型態的物件

          今天在 "最新 Java 7 程式語言 施威銘" 這本書中看到了一篇內容,大概的內容是講述當我有一個類別 Circle, 該類別裡面包含了另一個類別 Point 物件紀錄 Circle 的中心點,為了保護 Point 物件,所以在 Circle 裡面使用 private 來修飾 Point 物件;但當外部需要取得中心點資料時,便在 Circle 類別寫了一個傳回 Point 的參考物件 method,此時因為外部可以取得 Point 的物件參考,所以外部就可透過 所得到的 Point 物件參考來設定修改資料,這樣就違背了當初我們不想讓外部的使用者來隨便設定 Circle 的中心點的用意,也失去了把 Point 設成 private 作用。
         所以為了避免這種情況發生,可以使用下列方式:
    1. new 一個新的 Point 物件,拷貝目前 Circle 物件內的 Point 物件資料。
    2. 將 Point 變成 immutable 的類別,也就是不提供設定(setXX ) method。
    3. Point 類別 implements Cloneable 類別,然後回傳 clone 物件。
        書本使用第一個方式,在回傳 Point 物件參考的 method 中,可以先用 new 的方式將目前在 Circle 類別內的 Point 物件拷貝一份,然後傳回去。這樣外部修改 Point 物件時就不會影響原本的 Circle 物件裡 Point 物件資料了。

    範例程式:

    class Point implements Cloneable {
        private int x;
        private int y;
        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
        // 2. 把 setPoint 移除,讓 Point 變成 immutable 的類別
        public void setPoint(int x, int y) {
            this.x = x;
            this.y = y;
        }
        public int getX() {
            return x;
        }
        public int getY() {
            return y;
        }
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    class Circle {
        private Point point;
        private int radius;
        public Circle(int x, int y, int r) {
            point = new Point(x, y);
            radius = r;
        }
        public Point getPoint() {
            return point;
        }
        public Point getReadOnlyPoint() {
            try {
                // 3. 讓 Point 類別實作 Cloneable,然後回傳 clone 物件 
                return (Point)point.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return null;
        }
        public Point getReadOnlyPoint2() {
            //1. 使用 new 的方式,將目前的Point 資料拷貝一份
            return new Point(point.getX(), point.getY());
        }
        
        @Override
        public String toString() {
            return String.format("(%d, %d) ,radius = %d", point.getX(), point.getY(), radius);
        }
    }
    
    public class ProtectReferenceObj {
        public static void main(String[] args) {
            Circle circle = new Circle(1,1,2);
            Point pt = circle.getPoint();
            System.out.println("Before: " + circle);
            pt.setPoint(10, 20);
            System.out.println("After: " + circle);
            System.out.println("================================");
            System.out.println("Before: " + circle);
            Point pt2 = circle.getReadOnlyPoint();
            pt2.setPoint(11, 22);
            System.out.println("After: " + circle);
            System.out.println("pt2.x =  " + pt2.getX() + " pt2.y = " + pt2.getY());
            System.out.println("================================");
            System.out.println("Before: " + circle);
            Point pt3 = circle.getReadOnlyPoint2();
            pt3.setPoint(55, 99);
            System.out.println("After: " + circle);
            System.out.println("pt3.x =  " + pt3.getX() + " pt3.y = " + pt3.getY());
        }
    }
    


    輸出結果:
    Before: (1, 1) ,radius = 2
    After: (10, 20) ,radius = 2
    ================================
    Before: (10, 20) ,radius = 2
    After: (10, 20) ,radius = 2
    pt2.x =  11 pt2.y = 22
    ================================
    Before: (10, 20) ,radius = 2
    After: (10, 20) ,radius = 2
    pt3.x =  55 pt3.y = 99
    


    2013年11月5日 星期二

    ArrayList 使用 toarray 轉換成物件陣列

         在某些情況下,我們希望能夠將 ArrayList 物件所存的內容轉換成陣列的形式,在 ArrayList 中提供了 toarray 方法來達到我們的需求。下面是 Java 所提供的 toarray 方法的原始碼:

        public Object[] toArray() {
            return Arrays.copyOf(elementData, size);
        }
    
        public T[] toArray(T[] a) {
            if (a.length < size)
                // Make a new array of a's runtime type, but my contents:
                return (T[]) Arrays.copyOf(elementData, size, a.getClass());
            System.arraycopy(elementData, 0, a, 0, size);
            if (a.length > size)
                a[size] = null;
            return a;
        }
    
    
         有上面可知,我們有兩個方式可以使用 toarray 方法,一個是不帶任何參數 toarray 方法回傳 Object 陣列,另外一個是回傳你所傳入的型態陣列。
         我們先來看 public T[] toArray(T[] a) 的方法,從原始碼中,我們發現此方法會使用參數的 length 的屬性,代表該參數必須要先配置過記憶體才行,如果直接傳 null 給它會引發 "java.lang.NullPointerException" 的例外事件。再回頭看一下原始碼,會發現當你所配置的陣列元素小於目前 ArrayList 所儲存的元素時,toarray 方法會幫你配置足夠的元素來儲存目前 ArrayList 物件中所含的所有元素。而當你的所配置的陣列元素個數大於目前會將你所配置的第 size 元素設定為null。基本上你可以想成超出的元素都會被設置成 null 就可以。(PS: 要使用 ArrayList 其型態一定是參考型態,如果使用基本型態會出現編譯失敗 ,而物件陣列的預設值為 null)。

        另外一個 toArray法是回傳 Object 陣列,由於兩個陣列基底型別不同時,不能互相參照,所以你無法直接將回傳的 Object 陣列轉成你要的型態陣列。但是你可以針對每個 Object 元素做轉型。

    範例程式如下:

         static void toArrayDemo() {
            
            ArrayList<integer> list = new ArrayList<integer>(){{
                add(1);
                add(2);
                add(3);
                add(4);
            }};
    
            //"main" java.lang.NullPointerException
            //Integer[] test = null; 
            //test = list.toArray(test); 
            // or Integer[] test = list.toArray(null);
            
            // 配置的元素小於 ArrayList 所存的元素各數少時,
            // toArray 會幫你重新配置足夠的陣列個數來儲存。
            Integer[] test = list.toArray(new Integer[0]);
            System.out.print("<1>[ ");
            for (Integer val : test) {
                System.out.print(val + " ");
            }
            System.out.println("]");
            // 配置大於 ArrayList 所存的 元素個數,多餘的陣列元素都是 null
            Integer[] test2 = list.toArray(new Integer[10]);
            System.out.print("<2>[ ");
            for (Integer val : test2) {
                System.out.print(val + " ");
            }
            
            System.out.println("]");
            
            // 配置符合目前 ArrayList 所含的元素個數
            Integer[] test3 = list.toArray(new Integer[list.size()]);
            System.out.print("<3>[ ");
            for (Integer val : test3) {
                System.out.print(val + " ");
            }
            System.out.println("]");
            
            //無法將 Object 陣列轉成其他型態的陣列
            //[Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
            //Integer[] test4 = (Integer[] )list.toArray();
            
            Object [] obj = list.toArray();
            
            System.out.print("<4>[ ");
            for (Object val : obj) {
                // 你可以對每一個 Object 中的元素轉型成 Integer 型態的物件
                // 因為我們宣告的 ArrayList 是儲存 Integer 物件,所以每一個
                // Object 物件都是參考到  Integer 物件
                
                System.out.print( ((Integer)val).intValue() + " ");
                // 下面方式與上面轉型所列印出來的結果相同,因為每一個 Object 元素
                // 都是參考到 Integer 物件,而 Integer 的 toString method 就是列印其值。
                //System.out.print( val + " ");
            }
            System.out.println("]");
        }
    

    輸出結果:
    <1>[ 1 2 3 4 ]
    <2>[ 1 2 3 4 null null null null null null ]
    <3>[ 1 2 3 4 ]
    <4>[ 1 2 3 4 ]

    補充:
        Object[] obj = new Object[size] 與 Object[] intObj = new Integer[2]  的不同是,obj 陣列可以指定
    任何型態的物件參考,每一個元素值不一定要儲存相同的物件。而 intObj 是參考到 Integer 陣列所以其元素只能儲存 Integer 物件,儲存其他型態物件會引發 "java.lang.ArrayStoreException" 例外事件。另外 intObj 是參考到 Integer 陣列,所以你可以將 intObj 指定給其他 Integer 陣列來參考。

    範例程式如下:

        static void arrayDemo() {
            Object [] intobj = new Integer[2];
            System.out.println("obj instance Integer[] = " + (intobj instanceof Integer[]));
            obj[0] = new Integer(10);
            //Exception in thread "main" java.lang.ArrayStoreException: java.lang.Float
            //obj[1] = new Float(10.f);
            
            Object [] obj2 = new Object[2];
            System.out.println("obj2 instance Integer[] = " + (obj2 instanceof Integer[]));
            obj2[0] = new Integer(10);
            obj2[1] = new Float(10.f);
            System.out.println("obj2[0] = " + obj2[0] + " , obj2[1] = " + obj2[1]);
        }
    

    2013年10月31日 星期四

    ArrayList 移除 element 的問題

        今天查了 ArrayList 用法的時候,發現在 Javaworld 有人發了一篇 arraylist的移除問題,下面是他的 Sample Code
     
       ArrayList<integer> list = new ArrayList<integer>();
       list.add(2);
       list.add(2);
       list.add(3);
       list.add(1);
       list.add(2);
       System.out.println(list);
    
       for (int i=0; i<list.size(); i++){
          if(list.get(i)<3) {
             list.remove(i);
          }
       }
       System.out.println(list);
    

         原發問者想要將小於 3 的值全部移掉只剩下 3 這個元素,但是卻印出 [1 , 2],上面的的Sample Code 我有修改過,所以顯示為 [2,3,2] ,因為原程式在判斷條件小於3 的 if 後面多了分號 Orz。
         Anyway, 回到原來的問題,當你刪除一個元素時 size 也會跟著縮小,但是 i 的值卻會遞增,在 for 迴圈最後面加入除錯訊息,就可以知道為何印出 [2, 3, 2]。下面是我在 for 迴圈中加入除錯訊息所印出的資料:
    i = 0 : [2, 3, 1, 2] size:4
    i = 1 : [2, 3, 1, 2] size:4
    i = 2 : [2, 3, 2] size:3

        要解決這個問題有下面三種方式

    1. 透過 Iterator 
    2. 透過 for 迴圈反向檢查,可以在 ConcurrentModificationException for ArrayList 中查到方式。
    3. 透過 CopyOnWriteArrayList

    透過 Iterator 方式如下:
            
            Iterator<Integer> Allelement = list.iterator();
            while (Allelement.hasNext()) {
                if (Allelement.next() < 3) {
                    Allelement.remove(); // 刪除最後 Iterator 所回傳的值,也就是目前所指到值
                }
            }
    
    透過 for 迴圈反向檢查:
            
           for (int i = list.size() - 1; i >= 0; i--) {
                if(list.get(i) < 3){
                    list.remove(i);
                }
            }
    

    透過 CopyOnWriteArrayList:
            CopyOnWriteArrayList <Integer> list = 
                         new CopyOnWriteArrayList <Integer>();
            list.add(2);
            list.add(2);
            list.add(3);
            list.add(1);
            list.add(2);
            for (Integer val : list) {
                if (val  < 3) {
                    list.remove(val);
                }
            }
    
    請注意,使用 foreach 去詢訪 ArrayList 時,你不可以在 foreach 中 執行 remove,如果執行了應該會出現 java.util.ConcurrentModificationException 的例外訊息。


    2013年10月23日 星期三

    Scanner(System.in) 無法取的輸入的問題

        當你的只使用一個 Scanner(System.in) 在你的程式中並沒有甚麼問題,但是如果你有兩個類別都使用 Scanner(System.in) 來取得輸入時,最後使用 Scanner(System.in) 來取得輸入的類別是無法取得輸入,除非第一個使用的那個類別沒有呼叫close來關閉 Scanner。

        範例程式如下:
    // InputDemo.java
    import java.io.IOException;
    import java.util.Scanner;
    
    public class InputDemo {
        public static void main(String[] args) throws IOException {
            OtherInput otherInput = new OtherInput();
    
            int number = -1;
            Scanner scanner = new Scanner(System.in);
            
            // 嘗試執行下列敘述會得到IO例外訊息
            //System.out.println("System.in.available()" + System.in.available());
            
            System.out.print("Input a number:");
            if (scanner.hasNextInt()) {
                number = scanner.nextInt();
            }
            scanner.close();
            // 因為 scanner.nextInt() 沒有執行,所以 number 為 -1
            System.out.println("You input a number " + number);
        }
    }
    
    
    // OtherInput.java 
    import java.util.Scanner;
    public class OtherInput {
        public OtherInput() {
            Scanner scanner = new Scanner(System.in);
            
            int age = 0;
            String name = null;
            
            System.out.print("Please input your name:");
            if (scanner.hasNextLine()) {
                name = scanner.nextLine();
            }
            
            System.out.print("Please input your age:");
            if (scanner.hasNextInt()) {
                age = scanner.nextInt();
            }
            scanner.close();
            System.out.println("Your name: " + name + " and age: " + age);
        }
    }
    

        在 Eclipse 下如果你沒有關閉 Scanner 會有一個警告訊息:"Resource leak: 'scanner' is never closed"。所以不建議不關閉 Scanner 物件。為什麼關閉 Scanner 物件會有問題呢? 因為當你執行 scanner.close() 時也會把 System.in 標準輸入也關閉掉,所以最後使用Scanner 物件的 calss 無法正常的取得輸入。
       你可以試著把上面的範例 InputDemo.java 中的 System.in.available() 註解符號拿掉,你會得到下列的例外訊息:
       Exception in thread "main" java.io.IOException: Stream closed
     at java.io.BufferedInputStream.getInIfOpen(Unknown Source)
     at java.io.BufferedInputStream.available(Unknown Source)
     at InputDemo.main(InputDemo.java:10)
    

       所以當你有多個類別要使用 Scanner(System.in) 取得輸入時,最好可以在主類別建立一個 Scanner 物件,然後將該物件傳遞給需要的類別,然後在主類別呼叫 Scanner 的 close 方法。

    [其他參考]
    java.util.NoSuchElementException - Scanner reading user input

    Eclipse Console 視窗取得輸入的問題

         剛剛在嘗試了一下,發現是輸入法的問題,如果發現無法輸入可以將輸入切換到一般英文的模式,不要切換到有任何中文的輸入法。 : )

         在 Java 中要取得 Console 視窗輸入的文字可以透過 Scanner 物件來達到,今天如果你使用Eclipse 來開發時,當你的程式在取得輸入文字前,如果有先列印出一段提示文字時,你會發現 Eclipse 的 Console 視窗的游標會在最前面 (請參考下圖),並不會接在你所列印的提示文字後面,此時,如果你直接輸入任何文字嘗試取得輸入,會發現 Eclipse Console 視窗並不會顯示任何文字,且即便你按 Enter 想要結束輸入,Eclipse Console 視窗也不會有任何反應,此時你只能按停止執行或者重新執行程式來逃離這個狀況。

         要解決無法取得輸入的情況,當你執行程式時,必須先將游標移到正確的位置,然後再輸入,此時 Eclipse Console 視窗就可以正確的取得輸入的文字,注意,如果你的提示文字使用 println 來顯示,你必須移到下一行的開頭,如果使用 print 來顯示,則必須將游標移到提示文字的最後面才可開始輸入文字。

         範例程式如下:
    import java.util.Scanner;
    
    public class InputDemo {
        public static void main(String[] args) {
            int number = -1;
            Scanner scanner = new Scanner(System.in);
            System.out.print("Input a number:");
            
            if (scanner.hasNextInt()) {
                number = scanner.nextInt();
            }
            scanner.close();
            System.out.println("You input a number " + number);
        }
    }
    
    

    2013年9月25日 星期三

    Java 查詢可用時區參數與設定時區

        Java 中可以透過 TimeZone 物件來查詢、設定 有關時區資訊。

    查詢目前使用的時區:
    TimeZone.getDefault().getID(); // Asia/Taipei
    TimeZone.getDefault().getDisplayName(); // friendly name ex: 台灣標準時間
    

    設定時區:
    TimeZone tx = TimeZone.getTimeZone("Indian/Cocos"); // "Indian/Cocos" 就是 TimeZone ID
    TimeZone.setDefault(tx);
    

    列出可用時區:
    String [] ids = TimeZone.getAvailableIDs();
    for (String timezone : ids) {
        System.out.println(timezone + " " + 
              TimeZone.getTimeZone(timezone).getDisplayName());
    }
    

       如果要取得目前日期時間可以透過 Calendar 物件取的相關訊息:
    Calendar now = Calendar.getInstance();
    int hour = now.get(Calendar.HOUR_OF_DAY);
    int minute = now.get(Calendar.MINUTE);
    int second = now.get(Calendar.SECOND);
    int month = now.get(Calendar.MONTH);
    int day = now.get(Calendar.DAY_OF_MONTH);
    int year = now.get(Calendar.YEAR);
    System.out.printf("現在是 %d/%d/%d %02d:%02d:%02d", 
        year, (month+1), day, hour, minute, second);
    

        要注意的是,Calendar 物件類別中的 MONTH 是用 0 到 11 來到表 1 月到 12 月,所以取得的數值要加 1 才會顯示正確。
     
        當你發現上面顯示的日期時間與你的電腦不符時,有可能是 Java 解譯器用錯時區設定;當 Java 解譯器不曉得目前的預設時區的話,會直接使用格林威治時間。

    [相關資料]
    [Java] 日期方法 (Date method)

    懸置物件(dangling object)、懸置指標(dangling pointer)、懸置引用(dangling reference)

    下面解釋來源: 程式語言結構 1

    (1)懸置物件(dangling object):一個仍然存放資訊的記憶體空間,可是已沒有辦法可存取這個空間,則此空間便被稱為懸置物件。

    (2)懸置指標(dangling pointer):懸置指標意謂指標指到一個不存在任何有意義資訊的記憶體空間。

    (3)懸置引用(dangling reference):懸置引用意謂指標變數指到一個已經不存在的記憶體空間。如Pascal語言中,x是一個指標變數,當執行了dispose(x)後,(即將x所佔用的記憶體空間歸還給系統),若想引用x,則將造成懸置引用現象。

    根據 Object-Oriented Programming in C++ 的解釋如下:

    Dangling pointer
       Pointer point to a heap-dynamic variable that has been de-allocated.

    Dangling reference
       Pointers that refer to something that no longer there and also occurs when a function return a pointer point to local variable.


    [關鍵字]
    dangling object dangling pointer dangling reference

    [相關參考網站]

    網路資源搜尋

    Filesonic Hotfile Search - 可以找尋 影音及應用程式的搜尋引擎,但是中文沒有支援,所以你要搜尋的影片必須知道它的英文翻譯才行,該search engine 主要搜尋 hotfile.com 與 filesonic.com 檔案伺服器。

    ShareDigger - File Search Engine - 可以搜尋 4filehosting.com、 Badongo.com、Depositfiles.com、Filefront.com、iFolder.ru、Megashares.com、Megaupload.com、Multiply.com、Rapidshare.com、Rapidshare.de、Rapidsharing.com、Rapidupload.com、Sendspace.com、TurboUpload.com、zshare.net網站上面所分享的檔案。

    FileCrop - Search and Download Rapidshare Megaupload and Hotfile Files

    Global FTP Search Engine: Global File Search Engine

    YunFile- 網路檔案上傳伺服器,只能上傳檔案分享給其他人,沒有搜尋的功能,但是還是可以透過 Google來搜尋該伺服器目前有哪些分享的檔案。

    http://hotfile.com/

    4shared.com - 免費文件分享及儲存 有自己的資源搜尋引擎。讚!!

    [Keyword]
    File search engine

    [相關文章]
    多個免費檔案分流服務,讓你上傳一次就能儲存到一堆免費空間!
    免費網路硬碟比一比
    網路硬碟 | ㊣軟體玩家
    【下載】: 免費網路硬碟空間50g【分享】 - yam天空部落
    雲端大戰,6大免費網路硬碟誰最好用(上) | T客邦 - 我只推薦好東西
    雲端大戰,6大免費網路硬碟誰最好用(下) | T客邦 - 我只推薦好東西

    網路開放課程鏈結


    麻省理工學院「開放式課程網頁」首頁

    http://www.myoops.org/twocw/mit/index.htm

    國立交通大學OpenCourseWare開放式課程
    http://ocw.nctu.edu.tw/index.php 

    哈佛進修學院遠距教育計劃
    http://www.myoops.org/twocw/harvard/welcome/index.htm 

    約翰霍普金斯大學彭博公共衛生學院開放式課程
    http://www.myoops.org/twocw/jhsph/index.htm

    日本開放式課程網頁聯盟
    http://www.myoops.org/twocw/jocw/index.htm

    台灣開放式課程網頁聯盟
    http://www.tocwc.org.tw/

    TBSCTS [專科]程式語言Youtube影片
    http://www.youtube.com/view_play_list?p=06810CD71A86FACC

    C 入門教學Youtube影片
    http://www.youtube.com/view_play_list?p=0B6BF05869177563

    中小企業網路大學校-數位學習
    http://www.smelearning.org.tw/

    我要自学网
    http://www.51zxw.net/

    MyOOPS開放式課程
    http://www.myoops.org/main.php

    C++ Tutorial by Zaychenok
    http://www.youtube.com/watch?v=H1gV4JQI7OI&feature=BFa&list=PL0D836394D2FDDDB6&index=1

    XoaX.net Video Tutorials
    http://xoax.net/

    2013年9月7日 星期六

    Notepad++ 開啟「分割視窗」同時檢視、比對兩份文件

         詳細的設定方式請參考 [重灌狂人- 如何在 Notepad++ 開啟「分割視窗」同時檢視、比對兩份文件?] 文章。
         設定的步驟如下:

    1. 按「檢視」→「現行文件移動 | 拷貝」
    2. 根據需求 勾選 「檢視」→ 「雙窗垂直同步捲動」或 「雙窗水平同步捲動」
     
        另外,如果你要做垂直比對時,最好把 「檢視」→ 「自動斷行」 選項取消,否則可能在捲動視窗時,一個視窗已經捲動到底了,另外一個視窗卻還沒到底的情況。

    [參考資料]
    重灌狂人- 如何在 Notepad++ 開啟「分割視窗」同時檢視、比對兩份文件?

    透過 Chcp 修改 Windows Console 的 code page

            當你在 繁體 windows 下執行 cmd.exe 程式預設的 code page 為 MS950。當你開啟 Console 視窗後,可以執行 chcp 指令來查詢目前使用中的 code page 為何, 而  "使用中字碼頁: 950" 是我電腦查詢到的結果。
           
            如果你要改變 console 所使用的 code page,你可以下達下面的指令

            chcp 437
           
            437 是你所要設定的 code page;下達這個指令只會對你目前設定的 console 視窗有用,關掉 或 重新開啟 另外一個console 視窗時,該視窗還是使用預設的 code page,另外假設在還沒設定新的 code page 時,就執行 A.exe 程式,則該程式所使用的 code page 為預設的 code page。
       

    2013 海昌星眸 廣告歌曲 - 宇恆-HAPPY DAY

    2013年9月6日 星期五

    Ubuntu 修改hostname

         你可以透過修改 /etc/hostname 與 /etc/hosts 檔案來修改 Ubuntu 主機名稱,步驟如下:

    1. 開啟 terminal 視窗

    2. sudo gedit /etc/hostname &
        然後修改你要的名稱, ex: abc

    3. sudo gedit /etc/hosts &
       修改第二行,你應該會看到 [127.0.1.1 你原本的Hostname],將原本的Hostname 改為新的 abc。
     更改此檔的目的在於避免一些網路的 service 會不正常 ex: Apache、Tomcat...etc.

     4. 重新開機即可。

           另外你也可以透過 hostname 來查看你目前的主機名稱與暫時修改主機名稱(重新開機後名稱又會變回去原本的)。

           如果不想重新開機,你可以下達下面的指令來暫時更改主機名稱:
           hostname <新名稱>
           ex: hostname abc

    參考資料:
    Ubuntu: How to Change the Computer Name
    How do I change the hostname without a restart?

    Java Boolean getBoolean 總是回傳 false?

          之前試了 getBoolean 方法想要將字串轉成 boolean 型態,但是傳了 "true"、"True"、"TRUE" 最後的結果總是 false,用了google 查了一下,原來要使用 getBoolean 你必須設定 System 的 properties。 其實在 Java Doc 已經有提及到了,敘述如下:

          Returns true if and only if the system property named by the argument exists and is equal to the string "true".

          If there is no property with the specified name, or if the specified name is empty or null, then false is returned.


    首先你可以透過 System.getProperties() 來取的目前執行你程式的一些系統參數設定,它主要是以 <key>=<value> 的形式顯示出來,所以當你要查詢某一個屬性值時,你可以透過 System.getProperty("key") 的方式得到 其對應的 value 值,如果該 key 不存在則回傳 null。

          另外除了透過 getBoolean 可以轉換成 基本型態的 boolean 值外,我們還可以透過 Boolean.valueOf(String s) 的方式轉換成 boolean的 Wrapper class型態。但 Boolean.valueOf(String s) 方法回傳 true 只有當字串為 "true"(大小寫無關) 時,其餘都回傳 false。

          我們可以透過 setProperty 來設定額外的系統參數,其設定型態也是 key/value的方式 ,setProperty ("key", "value"),除了設定 System.setProperty("TRUE", "TRUE"); 來讓 Boloean.getBoolean("TRUE") 來回傳 true ,我們也可以設定讓 Boloean.getBoolean("YES")也可以回傳 true 的值。

    範例程式:

    public class BooleanDemo {
        public static void main(String[] args) {
            System.out.println(System.getProperties());
            System.out.println("======================================");
            System.out.println(System.getProperty("java.runtime.name"));
            System.out.println("System.getProperty(\"true\") = " + System.getProperty("true"));
            System.out.println("System.getProperty(\"TRUE\") = " + System.getProperty("TRUE"));
            System.out.println("System.getProperty(\"True\") = " + System.getProperty("True"));
            
            System.out.println("Boolean.getBoolean(\"true\") = " + Boolean.getBoolean("true"));
            System.out.println("Boolean.getBoolean(\"TRUE\") = " + Boolean.getBoolean("TRUE"));
            
            System.out.println("Boolean.valueOf(\"true\") = " + Boolean.valueOf("true"));
            System.out.println("Boolean.valueOf(\"TRUE\") = " + Boolean.valueOf("TRUE"));
            
            System.setProperty("TRUE", "TRUE");
            System.setProperty("YES", "True");
            System.out.println("Boolean.getBoolean(\"TRUE\") = " + Boolean.getBoolean("TRUE"));
            System.out.println("Boolean.getBoolean(\"YES\") = " + Boolean.getBoolean("YES"));
            System.out.println("Boolean.getBoolean(\"yes\") = " + Boolean.getBoolean("yes"));
    
            System.clearProperty("YES");
            System.out.println("Boolean.getBoolean(\"YES\") = " + Boolean.getBoolean("YES"));
        }
    }
    
        輸出結果: {java.runtime.name=Java(TM) SE Runtime Environment, sun.boot.library.path=C:\Program Files\Java\jre7\bin, java.vm.version=23.25-b01, java.vm.vendor=Oracle Corporation, java.vendor.url=http://java.oracle.com/, path.separator=;, java.vm.name=Java HotSpot(TM) Client VM, file.encoding.pkg=sun.io, user.country=TW, user.script=, sun.java.launcher=SUN_STANDARD, sun.os.patch.level=Service Pack 3, java.vm.specification.name=Java Virtual Machine Specification, user.dir=C:\Documents and Settings\Josh\JavaCode\BooleanDemo, java.runtime.version=1.7.0_25-b17, java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment, java.endorsed.dirs=C:\Program Files\Java\jre7\lib\endorsed, os.arch=x86, java.io.tmpdir=R:\TEMP\, line.separator= , java.vm.specification.vendor=Oracle Corporation, user.variant=, os.name=Windows XP, sun.jnu.encoding=MS950, java.library.path=C:\Program Files\Java\jre7\bin;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;C:/Program Files/Java/jre7/bin/client;C:/Program Files/Java/jre7/bin;C:/Program Files/Java/jre7/lib/i386;C:\Ruby200\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Program Files\Microsoft SQL Server\90\Tools\binn\;C:\Program Files\Perforce;C:\Program Files\Java\jdk1.7.0_07\bin;C:\Program Files\Android\android-sdk\tools;C:\Program Files\Android\android-sdk\platform-tools;C:\Program Files\apache-ant-1.9.1\bin;C:\Program Files\Perforce\Server;C:\Program Files\eclipse-SDK-4.2-win32;;., java.specification.name=Java Platform API Specification, java.class.version=51.0, sun.management.compiler=HotSpot Client Compiler, os.version=5.1, user.home=C:\Documents and Settings\Josh, user.timezone=, java.awt.printerjob=sun.awt.windows.WPrinterJob, file.encoding=UTF-8, java.specification.version=1.7, java.class.path=C:\Documents and Settings\Josh\JavaCode\BooleanDemo\bin, user.name=Josh, java.vm.specification.version=1.7, sun.java.command=BooleanDemo, java.home=C:\Program Files\Java\jre7, sun.arch.data.model=32, user.language=zh, java.specification.vendor=Oracle Corporation, awt.toolkit=sun.awt.windows.WToolkit, java.vm.info=mixed mode, sharing, java.version=1.7.0_25, java.ext.dirs=C:\Program Files\Java\jre7\lib\ext;C:\WINDOWS\Sun\Java\lib\ext, sun.boot.class.path=C:\Program Files\Java\jre7\lib\resources.jar;C:\Program Files\Java\jre7\lib\rt.jar;C:\Program Files\Java\jre7\lib\sunrsasign.jar;C:\Program Files\Java\jre7\lib\jsse.jar;C:\Program Files\Java\jre7\lib\jce.jar;C:\Program Files\Java\jre7\lib\charsets.jar;C:\Program Files\Java\jre7\lib\jfr.jar;C:\Program Files\Java\jre7\classes, java.vendor=Oracle Corporation, file.separator=\, java.vendor.url.bug=http://bugreport.sun.com/bugreport/, sun.io.unicode.encoding=UnicodeLittle, sun.cpu.endian=little, sun.desktop=windows, sun.cpu.isalist=pentium_pro+mmx pentium_pro pentium+mmx pentium i486 i386 i86} ====================================== Java(TM) SE Runtime Environment
    System.getProperty("true") = null
    System.getProperty("TRUE") = null
    System.getProperty("True") = null

    Boolean.getBoolean("true") = false
     Boolean.getBoolean("TRUE") = false 

    Boolean.valueOf("true") = true
    Boolean.valueOf("TRUE") = true

    Boolean.getBoolean("TRUE") = true
    Boolean.getBoolean("YES") = true
    Boolean.getBoolean("yes") = false

    Boolean.getBoolean("YES") = false


    另外我在 Boolean.parseBoolean(“1”) = false…? 此篇討論文章,看到有人提供自己自製的方法來設定那些字串要回傳 true。 程式碼如下:

    private boolean convertToBoolean(String value) {
        if ("1".equalsIgnoreCase(value)   || 
            "yes".equalsIgnoreCase(value) || 
            "true".equalsIgnoreCase(value)|| 
            "on".equalsIgnoreCase(value))
            return true;
        return false;
    }
    

    參考資料:
    getBoolean(String str) and valueOf(String str) of Boolean class gives different output
    有關 Boolean 的方法使用?
    Boolean.parseBoolean(“1”) = false…?

    2013年8月29日 星期四

    中國信託廣告歌曲- Hillary Bergen - You Are My Reason Why

    之前就想查這首歌是誰唱的,今天心血來潮查了一下,分享給喜歡的人 ~ Enjoy it ~ :)

    2013年7月24日 星期三

    error: Error: No resource type specified (at 'text' with value '@').

        今天要在  android:text 中填入 '@' 字元時 , 在編譯的時候出現這個錯過訊息訊息, 解決這問題就是在前面填入反斜線 ' \ ' 就解決問題了. android:text="\@123".  :)

        出現這個錯誤訊息是因為  @ 在 android xml 中是有意義的

    Refer to:
    http://stackoverflow.com/questions/8753431/at-the-beginning-of-edittext-value

    2013年6月26日 星期三

    解決 Export Signed Application Package... 出現 " ... is not translated in ..." 的問題

        今天想嘗試執行 Export Signed Application Package...時,出現  "... is not translated in..."的 Fatal Error,如下圖所示:

        而其實引起這個問題的原因與解法就寫在右邊的訊息視窗中,可以參考上面的圖示。而下面是我自己驗證過確實可以解決這個問題。

    解法 一:
        執行 Window -> Preferences,點選 Android -> Lint Error Checking,
        將 Lint 的 Missing Translation 項目從 Fatal 改為 Warning. 如下圖所示:
       

    解法 二:
         將 translatable="false" 加入倒出現錯誤訊息的字串中,如下圖所示:



    [關鍵字]
    Android is not translated in 

    [參考鏈結]



    如何新增 Android XML 檔案

          在很多時候我們需要自己新增 Android XML 檔案,例如要支援多國語言、針對不同的螢幕大小、或者螢幕操作的方向 (port直向 / land 橫向)...等等的替代選擇性資源內容。
          透過 ADT 的工具我們可以很簡單的建立新的 Android XML 檔案,方法如下:

    1. 點選工具列的按鈕,如下圖所示:

    2. 選擇要加入的資源型態:

    3. 填入檔案名稱,這邊我們不需要填入副檔名,當建立後 ADT 會幫我加入。另外如果要建立替代選擇性資源,可按下圖的 Next 按鈕繼續設定裝置設定屬性。否則,直接按 Finish 即可在預設的資料夾(如: layout、value、drawable...etc. )內產生該檔案。

    1-2. 如果不點選工具列的按鈕,也可以透過點選專案,右鍵-> Android Tools -> New Resources File... 來叫出 步驟 2 的新增 Android XML 對話框。


    1-3. 步驟 2 的新增 Android XML 對話框的方式也可以透過點選專案,右鍵-> New-> Android XML File 來執行。

        另外,如果你想要新增的是翻譯,則可以透過 Android Graphical Layout 來快速產生簡單的替代選擇性資源資料夾 (只能設定 Language 與 Region,無法設定其他條件 如 ldpi/mdpi 或者 port/land...etc.)與空的 strings.xml 檔案,實際做法請參考下圖:





    2013年6月20日 星期四

    TextView - 顯示上下左右相反文字

         想要在 TextView 中將文字上下左右相反顯示可以將 android:scaleX 與 android:scaleY 屬性設定為 -1f 即可,程式碼如下:
        
    <textview 
       android:id="@+id/tv" 
       android:layout_height="wrap_content" 
       android:layout_width="wrap_content" 
       android:scalex="-1f" 
       android:scaley="-1f" 
       android:text="@string/hello_world"/>
    
    設定後的結果如下圖所示:

         另外除了直接透過設定 xml 檔案來完成上下左右文字的顯示,你也可以用 setScaleX(float)setScaleY(float)  方法在程式碼中做動態的設定。方法如下:

    TextView tv = (TextView)findViewById(R.id.tv);
    tv.setScaleX(-1f);
    tv.setScaleY(-1f);
    

    [參考連結]
    http://www.javaworld.com.tw/jute/post/view?bid=26&id=309372

    2013年6月12日 星期三

    解決 Android Emulator 無法啟動的問題

          今天想要透過 Android Virtual Device Manager 啟動 AVD,但是啟動的過程發生警告的訊息如下:
           Starting emulator for AVD 'Android_4.0.3'
           WARNING: Data partition already in use. Changes will not persist!
           WARNING: SD Card image already in use: C:\Documents and    
           Settings\Josh\.android\avd\Android_4.0.3.avd/sdcard.img
           ko:Snapshot storage already in use: C:\Documents and
           Settings\Josh\.android\avd\Android_4.0.3.avd/snapshots.img
    或者參考下圖

    上網查了一些資料,也嘗試了一些方法但是目前唯一有效的就是在 "Using Eclipse for androidSDK, when I go to run, I get WARNING: Data partition already in use. Changes will not persist!" 看到的解決方法,就是刪除在 .android\avd\[your_device].avd 資料夾底下的所有
    XXX.XXX.lock 的資料夾,請參考下面圖檔。 刪除後,模擬器終於又恢復作用囉。


    2013年6月8日 星期六

    ADT 設定 Preview All Screens 與 All Locales 查看所有Layout 與 語言的效果

            當我們要開發多國語言或者給多個不同螢幕大小裝置的 App 時,我們可以先透過 設定 Preview All Locales 與 Preview All Screens 來查看其顯示的效果。設定後的結果請參考下面的圖示。


    利用 ImageView background 與 src 來合併兩張小 icon

         在某些情況下我們需要將兩張小 icon 合併來顯示成一張小icon。例如我們有很多 icons 而他們的背景圖示都一樣,只有中間的圖示不同,此時我們可以只準備一張背景圖示,另外準備其他不同的小圖示且其背景必須是 transparent 。一切準備好之後我們就可以設定利用background 與 src 屬性來設定圖示,來產生合併的效果,如下圖所示。

          上面圖示的 layout_width 與 layout_height 都是指定 wrap_content,最右邊的為 ImageButton,另外兩個則為 ImageView。使用 wrap_content 時,其 ImageView 大小視 backgroud 或 src 圖示中何者為大。也就是說當你準備的src 大於 background image時,background 圖示有可能被 src 的圖示所掩蓋而無法看出效果。

          另外 backgroud 與 scr的不同是, background 的圖示會根據 ImageView的大小做縮放,且不會保持原本圖示的比例,但是 src 則會保持 原圖的長寬比例做等比例的縮放。

         如果你不想讓 src 做等比例縮放,可以而外設定  android:scaleType="center" ,其效果可以參考中間的小圖示。最左邊圖示只簡單的設定 background 與 src 的圖示,可以看到 src 的圖示被等比例縮放了。

    [其他參考鏈結]




    移除 [Accessibility] Missing contentDescription attribute on image 的警告

           不知何時加入 ImageView 時 Eclipse 在編輯 XML 視窗或者 Graphical Layout 視窗都會出現 Lint 的警告提示,如下圖:

           該警告是從 ATD 16 以後當你沒有設定 contentDescription 屬性給  ImageButton 與 ImageView 時,Lint 會提出 Missing contentDescription attribute on image 的警告。

           contentDescription 屬性的作用主要是要提供一些眼睛不方便的使用者,當使用者移到該物件上面或者點選此物件時,Android  的 Accessibility service 就可以透過 TTS 播放出 contentDescription  中的敘述,這些使用者即使看不見,目前所點選到的物件提供甚麼樣的服務。 詳細的資料可以參考 Accessibility Making Applications Accessible

          即使你對這個警告不理會的話程式還是依然可以順利執行,如果你覺得這個警告非常礙眼又不想要花費腦筋給該物件適當的敘述,你可以很簡單的直接填入下面的敘述到 ImageButton 與 ImageView的屬性當中,即可移除該警告:

    android:contentDescription="@null"


    [其他參考鏈結]





    2013年6月1日 星期六

    API Demo Installation error: INSTALL_FAILED_VERSION_DOWNGRADE and INSTALL_FAILED_CONFLICTING_PROVIDER

           今天試著安裝 Android SDK 裡面的範例專案 API  Demo,編譯完後要安裝到 Emulator 時,在 Console windows 卻出現 Installation error: INSTALL_FAILED_VERSION_DOWNGRADE 的問題,在 "Android Emulator: Installation error: INSTALL_FAILED_VERSION_DOWNGRADE" 上找到了解決方法,解決的方式有兩種:

    1. 在 Emulator 上移除相同名稱的 App 程式
    2. 在 AndroidManifest.xml 中加入 android:versionCode,目前我設定為 2 即可,如果不行的話可以試著調高數值。
          但調完後雖然不會出現 INSTALL_FAILED_VERSION_DOWNGRADE 的錯誤訊息,卻跑出了  INSTALL_FAILED_CONFLICTING_PROVIDER 的錯誤訊息,幸好在 "Android: INSTALL_FAILED_CONFLICTING_PROVIDER" 裡面也找到解決方法。解決的方法就是在
    AndroidManifest.xml 中修改 android:authorities 的內容,同時必須修改有使用到該 provider的 java 檔案。
         
          話說好不容易終於安裝到 Emulator 上,但是執行 Animation 範例總是出現 ANR,真是無言了,不曉得是不是電腦不夠力還是其他問題,Anyway 今天就先這樣囉。

    透過Eclipse 更新 Plug-in 後出現 Type R cannot be resolved to a variable

          今天透過 Eclipse "Check for updates" 去更新一些 plugin 後,在編譯 Android 時總是出現 "Type R cannot be resolved to a variable" 的問題,如下圖所示:

          我確定更新前是可以編譯成功,但不知為何更新完後卻無法編譯 Android project 了,之前更新都沒有遇到這樣的狀況;回想起來更新完後 Eclipse 有跳出一個視窗,但內容我倒是沒去注意,想說跟以前一樣要我重新啟動 Eclipse ,沒想到這次踩到地雷了...Orz.
        幸好似乎有不少人有類似的情況,上網 Google 了一下找到了─"Type R cannot be resolved to a variable" after Android SDK updated"。
         解決方式就是開啟 Android SDK Manager,沒意外應該會出現有可更新項目,將那些項目更新後就解決問題了。

        發生 Type R cannot be resolved to a variable 有很多原因,最主要是因為 R.java 無法自動產生出來,但是為何無法產生可能要去查看看 res 目錄下是否有任何錯誤。
        下面鏈結我是從 "“R cannot be resolved to a variable”?" 討論串中擷取出來的,如果發生的症狀並非與上面一樣的話,或許可以從下面找到你要的解答。

    2013年5月24日 星期五

    Android Graphical Layout 設定Fullscreen 與 直/橫 模式


    • 透過 Android Graphical Layout 切換 Portrait Mode 與 Landscape Mode:
    1. 點選專案中 Layout 的 XML 檔案
    2. 點選 Graphical Layout tab menu (基本上預設會選擇此選項,如果你有點選過 查看 xml 檔案的 tab menu,擇點選時還是會先開啟 查看 XML 的 tab menu,這時可以再點選Graphical Layout)
    3. 可以點選下圖中的圖示或者旁邊下拉的箭頭,選擇 Switch to Landscape,就可以將 Layout 切換成 Landscape Mode (如果則是做切換,可以直接按該圖示即可)。

    • 透過 Android Graphical Layout 將 Layout 特定成 Full Screen 的樣式來檢視:
    1. 在 Graphical Layout 下,點選 AppTheme後會彈出下拉選單。
    2. 選擇 Theme -> Theme.Black.No.TitleBar.FullScreen  即可;基本上你只要設定XXX.No.TitleBar.FullScreen 即可讓 Layout 呈現 Full Screen 的樣式來檢視。注意,這只是讓你檢視 Layout 在 Full Screen 下元件的布局,並不會因此讓你的Application變成 FullScreen。



    • 設定 Theme.Black.No.TitleBar.Fullscreen的效果如下



    2013年5月22日 星期三

    Android Full Screen Activity

    要製作 Full Screen 的 Activity 的方法大致上分成下列兩種,

    1. 在 AndroidManifest.xml 中設定 Theme.NoTitleBar.Fullscreen。
    2. 在 Java 檔案中透過 requestWindowFeature + WindowManager.LayoutParams.FLAG_FULLSCREEN 或者 setTheme( ) 方法設定。
    在 AndroidManifest.xml 檔案中設定, 假如你要讓你所有程式中的 Activity 都是 Full Screen 你可以加在 Application tag 下,而如果只要單純設定一個 Activity 則加入到你想要設定的 Activity tag 下。範例如下所示:

    • 套用整個程式的 Activity
    <application
    ...
    android:theme=
    
    "@android:style/Theme.NoTitleBar.Fullscreen" >
    </application>
    
    • 只套用在所設定的 Activity
    <activity
    android:theme=
    
    "@android:style/Theme.NoTitleBar.Fullscreen" >
    ...
    </activity>
    

    在 java 檔案中設定,你可以將下面的程式碼加到 onCreate( ) method 之中

    requestWindowFeature(Window.FEATURE_NO_TITLE);
     
    //fullscreen
    
    this.getWindow().setFlags(
    
         WindowManager.LayoutParams.FLAG_FULLSCREEN,
         WindowManager.LayoutParams.FLAG_FULLSCREEN );
    
    
    
    或者
    setTheme(android.R.style.Theme_NoTitleBar_Fullscreen);
    


    完整的程式碼如下:

    package com.example.fullscreendemo; import android.os.Bundle; import android.view.Gravity; import android.view.Window; import android.view.WindowManager; import android.widget.LinearLayout; import android.app.Activity; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Set Full screen in Java file method 1 //turn off the window's title bar //requestWindowFeature(Window.FEATURE_NO_TITLE); // fullscreen //this.getWindow().setFlags(
    // WindowManager.LayoutParams.FLAG_FULLSCREEN, // WindowManager.LayoutParams.FLAG_FULLSCREEN);
    LinearLayout ll =
    new LinearLayout(getApplicationContext());
    ll.setOrientation(LinearLayout.VERTICAL);
    ll.setGravity(/*Gravity.CENTER*/Gravity.TOP);
    LinearLayout.LayoutParams lp =
    new LinearLayout.LayoutParams(
    LinearLayout.LayoutParams.MATCH_PARENT,
    LinearLayout.LayoutParams.MATCH_PARENT);
    ll.setLayoutParams(lp);
    ll.setBackgroundResource(
    R.drawable.background2);
    // Set Full screen in Java file method 2
    setTheme(
    android.R.style.Theme_NoTitleBar_Fullscreen);
    setContentView(ll); }
    }
    另外,我發現透過程式碼設定 Full Screen,在 emulator 上面執行,會先看到原本含有 title bar的 Activity,然後才淡出變成 Full Screen (如下圖),而透過 AndroidManifest.xml 檔案設定則沒有這個問題,所以想要在一開始就設定 Full Screen 的 Activity,還是透過 AndroidManifest.xml 檔案設定比較理想。


    範例的結果:

    透過 getDisplayMetrics 方法取的裝置解析度以及判斷直/橫模式

    首先透過 getResources( ) 方法取得 Resources 物件,再經由 Resources 物件的 getDisplayMetrics( ) 方法取得與目前顯示相關的物件 DisplayMetrics,之後再透過  widthPixels (寬) 與 heightPixels (高) 的值來判斷目前顯示是直式(PORTRAIT Mode)或橫式 (LANDSCAPE Mode)。

    範例程式如下:

    package com.example.screenresolutiondemo;
    
    import android.app.Activity;
    import android.content.res.Resources;
    import android.os.Bundle;
    import android.util.DisplayMetrics;
    import android.widget.TextView;
    
    public class MainActivity extends Activity {
    
     @Override
     protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      TextView tv = new TextView(getApplicationContext());
      Resources res = getResources();
      DisplayMetrics metrics = res.getDisplayMetrics();
      tv.setText("螢幕資訊:\n");
      tv.append("寬:" + metrics.widthPixels + "\n");
      tv.append("高:" + metrics.heightPixels + "\n");
      tv.append("DPI:" + metrics.densityDpi + "\n");
      
      if (metrics.widthPixels < metrics.heightPixels) {
       tv.append("目前是直式\n");
      } else {
       tv.append("目前是橫式\n");
      }  
      setContentView(tv);
     }
    }
    
    範例結果:

    切換 Android emulator 直/橫 顯示

    今天想要在 Android emulator 上測試切換 直 / 橫 模式,但不知道快速鍵為何,上網快速查詢瞭一下,在 "How to rotate the Android emulator display?" 上找到想要的資料如下:

    Windows: CTRL + F11 or CTRL + F12

    Mac: Fn + Ctrl + F12

    另外,你也可以在 Android Emulator 上找到更多可用的 Android emulator 快速鍵。

    利用 Google Code Prettify + CSS 測試張貼程式碼

    下面是參考 "改善Google Blog 顯示程式碼的簡單方案 Google Code Prettify + CSS" 該篇文章所呈現出來的效果,如果想要知道如何在Google Blog 張貼程式碼可以參考該篇文章。

        public class HelloWorld {
            public static void main(String [] args) {
                System.out.println("Hello World!");
            }
        }
    設定好之後,就可以透過下面的方式張貼出有 Highlight Syntax 的程式碼了。
    <pre class="prettyprint code">
       輸入想顯示的程式碼
    </pre>