Sean's Note: 3月 2013

2013年3月29日 星期五

Measure the display width of a string

我們常常會用 Graphics2D.drawString("Hello", 100, 100); 在元件上畫出字串,

若想要依字串畫出來的大小來決定其位置,可以先取得 FontMetrics 物件,

FontMetrics fm = getFontMetrics(font);

再透過 FontMetrics.getHeight() 和  fm.stringWidth(String) 即可拿到該字串的高和寬。

Static variables are not resetting when the application is destroyed

當 APP 觸發 OnDestory() 而結束時,所宣告的 static variables 並不會因此而重設,

必須手動重設,這是因為當 class 被載入時,靜態變數就會一直存在直到 class

被卸載,像是 Remove 整個 APP 時或系統記憶體不足的時候。

Do not use Socket with DataInputStream

今天在寫的 socket 程式時,使用 DataInputStream/DataOutputStream 來傳遞資料,

發現用 DataInputStream 時,能夠一次讀到的 bytes 很少,每次都是 1448 bytes

(不知道怎麼算出來的?),讀的也很慢。試著改用 BufferedInputStream/BufferedOutputStream

來傳遞資料發現變快許多,而且每次能讀的的 bytes 也比較多,都是 1448 的整數倍,

1448, 2896(2x1448), 4344(3), 8688(6), 30408(21), 33304(23), 36200(25)... 等。

2013年3月28日 星期四

new Socket 時發生 Exception

今天想寫一個 Android 的 Client 端將資料傳輸到 PC 的 Server 端。

我在 onCreate() 時去 new Socket(strIP, 27015) 卻發生 NullPointerException

strIP 明明就不是 null pointer,傳進去後卻莫名變成 null 了。

在網路上也找不到相關的資料,索性試著將 new Socket 一行移至 OnClick(),

這時跑出了另一個 NetworkOnMainThreadException,於是讓我找到了相關的文章。

根據 Why Ice Cream Sandwich Crashes Your App 這篇文章的說明,Android 3.0 以上

不允許在 UI thread 裡做以下的運算:
  • Opening a Socket connection (i.e. new Socket()).
  • HTTP requests (i.e. HTTPClient and HTTPUrlConnection).
  • Attempting to connect to a remote MySQL database.
  • Downloading a file (i.e. Downloader.downloadFile()).
解決方法: AsyncTask, Thread, Service(Android)

Debugging with Android SDK source code

之前已提過 [Eclipse] 對 Java SDK source code debug

對於 Android SDK source code debug 也是一樣,問題是要如何取得 Android SDK

的 source code 呢? 對於 Android 4.0 之前需要用 Repro 和 Git 這類的工具將 source

抓下來,到了 4.0 之後不需要在這麼麻煩,直接在 Android SDK Manager 就可以

下載,下載完後在 Debug perspective 對該 process 按下滑鼠右鍵選擇

Edit Lookup Path... 設置對應路徑即可。

▲ Android SDK Manager

[Eclipse] 對 Java SDK source code debug

我們可以安裝 JRE 或 JDK 來開發 Java 程式,但若要看到 Java SDK 的 source code,

並針對其 Debug,我們就只能安裝 JDK 了。

只要在 Window → Preferences → Java → Installed JREs → Search.... 設置 JDK 所安裝的

路徑即可。如此一來便可透過 F3Ctrl + 滑鼠左鍵看到定義 String 的 class 檔,而不會

有 "Source not found" 的訊息頁跑出來。

2013年3月26日 星期二

Cursor 在 OnStop 完之後被 Reset 了?

今天在使用 Cursor 時發現,使用開發的 App 到一半關螢幕,

使其觸發 OnStop() 事件,在當下 c.getPosition() 的值還是對的,

OnRestart() 回來後,c.getPosition() 卻變成 -1,也就是被重新指回頭了。

不知道是預期的行為還是怎樣,只好用個變數在 OnStop() 時記下,

OnRestart() 回來後,在把 cursor 指向原來的位置。

Macro # 和 ## 的用法

使用 # 可以把巨集引數變為一個字串,而 ## 則把兩個巨集引數串接在一起。

例如:
#define STR(s) #s
#define EXP(a,b) int(a##e##b)

printf ("Number %s\n", STR(655.3)); // Number 655.3
printf ("Number %s\n", EXP(5, 2));  // int(5e2), Number 500

2013年3月25日 星期一

讀取外部記憶體的圖片並秀在 ImageView 上

Step 1: 宣告外部記憶體 URI 位置
Uri uriMedia = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;

Step 2: Query URI 的資料,利用 c.moveToNext() 取得繞行所有圖片的資料。
Cursor c = managedQuery(uriMedia, null, null, null, null);

Step 3: 取得 _id 後,建立該圖片完整的 URI。
uriSource = Uri.withAppendedPath(uirMedia, c.getString(0));

取得完整的 URI 後,有兩種方法可以秀出圖片:

Step 4.1: 利用 URI 的 stream data 建立 Bitmap 物件。
ContentResolver resolver = getContentResolver();
resolver.openInputStream(uriSource)
imageView.setImageBitmap(bitmap); 

Step 4.2: 直接將 URI 當參數設給 imageView
imageView.setImageURI(uriSource);

在這邊要注意的是,Android 單一程式的記憶體空間只能使用到 16~128MB,所以當

圖片太大不管是 setImageBitmap 或 setImageURI,都有可能造成 Out of Memory 的

錯誤訊息。解決方法可見 Loading Large Bitmaps Efficiently

Runtime.getRuntime().totalMemory() 可以查看應用程式目前的記憶體(Heap Size)大小,

Heap Size 是動態增長的。

Runtime.getRuntime().maxMemory() 可以查看應用程式的記憶體(Heap Size)能增長到多大。

2013年3月5日 星期二

把常用的 TortoiseSVN 功能整合進 Visual Studio

我們可以將 TortoiseSVN 常用的功能,如 Log 和 Blame 整合進 Visual Studio,

步驟如下:

開啟 VS -> Tools -> External Tools...

[External Tools]






















Command: C:\Program Files\TortoiseSVN\bin\TortoiseProc.exe

Arguments(Log): /command:log /path:"$(ItemPath)"

Arguments(Blame): /command:blame /path:"$(ItemPath)" /line:$(CurLine)

如此一來,就可以在 VS 上對某一段 code 做 Log 和 Blame 啦! 相當好用!

2013年3月4日 星期一

利用指令透過 Visual Studio 開啟指定檔案


我們可以在執行檔 C:/Program Files/Microsoft Visual Studio 8/Common7/IDE/devenv.exe

後面加上:

A.cpp /command "Edit.Goto 200"

或是

/edit A.cpp

兩者的差異是,前者會開啟新的 VS 並可指定行號,後者會用已開啟的 VS 做為編輯器,

但無法指定行號。

[Notepad++] 開啟某文件並留在某一行

這對開啟程式碼文件頗實用,指令如下:

C:\Program Files\Notepad++\notepad++.exe C:\a.cpp -n200

即可開啟 a.cpp 這個檔案,並停留在 200 行的位置。

更多的 Command Line 可參考:
1. http://npp-community.tuxfamily.org/documentation/notepad-user-manual/command-line
2. http://sourceforge.net/apps/mediawiki/notepad-plus/index.php?title=Command_Line_Switches