[Android] ‘aapt’ error. Pre Compiler Build aborted. (aapt.exe crash)

又是個Android SDK的很嚴重的Bug

從8/16發現,一直到現在9月了,才把這個嚴重的Bug給繞過去

搞了一個多月了,終於不用再找其他電腦頂替了

 

2011-08-16 00 58 01.png

 

 

 

怎麼說呢

使用的是Windows版Android SDK r12版(最新)

使用Java版本:已測試JDK 6u23 6u24 6u25 6u26皆有這狀況

只要是在Library裡面有drawable,aapt.exe又是在verbose模式底下

就一定會crash

 

請大家集氣反映給google請他修掉這個Bug~

 

 

測試方式如下

  1. open an Android project under eclipse and call it ‘a’
  2. open the ‘a’ properties and check the ‘Is Library’ check box.
  3. open another Android project and name it ‘b’.
  4. open it’s properties and add ‘a’ as an android library it uses.
  5. open the android plugin preferences and change the build from silent to verbose
  6. clean both projects.
  7. on linux everything is neat, on windows it crashes after the line:’baseFile zd has flavor (null)’ which according to linux should be:’baseFile 0 has flavor ,,,,,,,,,,,hdpi,,,,,,,’ most chances null pointer exception occurs here, the question is why only on windows ?

 

  1.  eclipse開一個專案叫A
    2.  A專案  滑鼠右鍵 >  內容,勾上Is Library
    3.  開另一個專案叫B
    4.  B專案 滑鼠右鍵 > 內容,引用A專案的函式庫
    5.  在eclipse裡, Windows > Preferences > Android > Build

Build output的選項為Verbose

  1.   二個專案分別做 Project > Clean

  2.  跳出Bug

[2011-09-03 01:41:01 – (專案名稱A)] Refreshing resource folders.
[2011-09-03 01:41:01 – (專案名稱A)] Starting full Pre Compiler.
[2011-09-03 01:41:01 – (專案名稱A)] Removing generated java classes.
[2011-09-03 01:41:01 – (專案名稱A)] Preparing generated java files for update/creation.
(android-sdk路徑)platform-toolsaapt.exe package -m -v –auto-add-overlay
-J (專案路徑A)gen -M (專案路徑A)AndroidManifest.xml -S (專案路徑A)res
-S (專案路徑B)res -I (android-sdk路徑)platformsandroid-8android.jar 
[2011-09-03 01:41:05 – (專案名稱A)] ‘aapt’ error. Pre Compiler Build aborted.

把系統產生的ㄧ大串指令貼到cmd上得到

(…..前面略)
Including resources from package: (android-sdk路徑)platformsandroid-8android.jar

applyFileOverlay for drawable
trying overlaySet Key=icon.png
baseFile zd has flavor (null)

 


 

解決方法其實上面就有提到了

我還是補一下圖好了

 

在eclipse裡, Windows > Preferences

2011-09-03 02 15 05.png  

 

 

在 Android > Build這裡,將Build output改為Silent或是Normal即可繞過這個Bug

2011-09-03 02 17 58.png  


 

另外,順道一提

2011-09-03 02 30 27.png  

 

Android SDK r12版目前只能搭配 Java JDK 1.6.0 (6u xx)版唷~

(文章截止Java出到 JDK 1.6.0 (6u27) )

不能直接灌JDK 7喔

因為JDK 7的金鑰計算工具有改

JDK 6版預設使用MD5
JDK 7版預設使用SHA-1

在使用Google Map的時候,算key.store的時候,就會不管怎麼樣都會驗證不過  (哇哈哈~~)

 

 

 

補充:JDK7的使用者需要加上 -v 這個參數,使用MD5數值

keytool -v -list -keystore ~/.android/debug.keystore

就可以用它產生金鑰了, (感謝BB大大提供的方法)

 

 

Google  API 註冊頁面

http://code.google.com/android/maps-api-signup.html

2011-09-03 02 33 43.png  

 

 

 

 

希望大家能感受到Android小綠機器人快樂的體驗

而不會做小綠機器人的噩夢 (對開發者而言啦XD)

 

Google呀Google.   大家都在接連修正你的Bug…..(囧)

 

參考文章

http://stackoverflow.com/questions/6887886/debugging-android-tools-code-under-windows
http://comments.gmane.org/gmane.comp.handhelds.android.devel/146994

[Android] Google出的Android萬用驅動,驅動裝不上嗎?請看這

2011-08-20 01 44 53.png

 

 

我先說,這不一定適用所有其他非Android的usb驅動
這就要煩請你自已測試了,如有成功可以不吝分享給我

這是一篇不是給初學者看的文章,裡面盡是一堆歪招 haha

—————————————————————————–

之前我遇到一台白牌機的Android驅動裝不上,問了朋友他說

到SDK manager裡面,要確定一個叫做Google USB Driver有安裝

 

2011-08-20 01 54 28.png

2011-08-20 01 55 34.png   

然後

 

在我的電腦 右鍵 > 內容  找到裝置管理員  

2011-08-20 01 45 09.png2011-08-20 01 46 32.png

找到Android

2011-08-20 01 47 22.png

右鍵 > 更新驅動程式

2011-08-20 01 48 39.png  

 

選擇 Browse my computer for driver software

2011-08-20 01 49 28.png

 

 

 

 

這個是重點,Let me pick from a list device drivers on my computer

2011-08-20 01 49 52.png

 

 

到了選擇類型的頁面,選Show All Devices,直接按下一步

2011-08-20 01 50 56.png

 

按下have Disk…..   (從磁片安裝)

2011-08-20 01 51 38.png

 

 

 

選擇其路徑

 

然後選擇路徑      <你裝的android SDK的路徑>extrasgoogleusb_driverandroid_winusb.inf

我的是

C:Program FilesAndroidandroid-sdkextrasgoogleusb_driverandroid_winusb.inf

2011-08-20 01 51 52.png

找到android_winusb.inf

2011-08-20 01 53 33.png  

 

就會有三個可以選,隨便選,但通常是第一個

2011-08-20 01 52 25.png

詢問驅動程式簽章事宜,直接按確定繼續

2011-08-20 01 52 36.png  

 

就安裝完成了

2011-08-20 01 52 58.png

 


如果你的驅動已經安裝完畢的話就不用看這篇了

搞不定的話請跟我一起繼續奮鬥………

 

 

我的win7裝好了  但xp遲遲無法這樣安裝

 

 

 

 

 

 

有一天,我無意間開了android_winusb.inf

這才恍然大悟

 

有了這一招,應該沒有所謂的上不了的驅動

只是上了會不會跳藍底白字的畫面而已

 


2011-09-03 03 14 08.png

 

這是Google USB Driver, r4

裡面的android_winusb.inf  內容

 

;
; Android WinUsb driver installation.
;
[Version]
Signature           = "$Windows NT$"
Class               = AndroidUsbDeviceClass
ClassGuid           = {3F966BD9-FA04-4ec5-991C-D326973B5128}
Provider            = %ProviderName%
DriverVer           = 12/06/2010,4.0.0000.00000
CatalogFile.NTx86   = androidwinusb86.cat
CatalogFile.NTamd64 = androidwinusba64.cat

;
; This section seems to be required for WinUsb driver installation.
; If this section is removed the installer will report an error
; "Required section not found in INF file".
;
[ClassInstall32]
Addreg = AndroidWinUsbClassReg

[AndroidWinUsbClassReg]
HKR,,,0,%ClassName%
HKR,,Icon,,-1

[Manufacturer]
%ProviderName% = Google, NTx86, NTamd64

[Google.NTx86]

%SingleAdbInterface%        = USB_Install, USBVid_18d1&Pid_0005&Rev_0223&MI_01
%SingleAdbInterface%        = USB_Install, USBVid_18d1&Pid_0005&MI_01

; HTC Dream

%SingleAdbInterface%        = USB_Install, USBVID_0BB4&PID_0C01
%CompositeAdbInterface%     = USB_Install, USBVID_0BB4&PID_0C02&MI_01
%SingleBootLoaderInterface% = USB_Install, USBVID_0BB4&PID_0FFF
; HTC Magic
%CompositeAdbInterface%     = USB_Install, USBVID_0BB4&PID_0C03&MI_01
;
;Moto Sholes
%SingleAdbInterface%        = USB_Install, USBVID_22B8&PID_41DB
%CompositeAdbInterface%     = USB_Install, USBVID_22B8&PID_41DB&MI_01
;
;Google NexusOne
%SingleAdbInterface%        = USB_Install, USBVID_18D1&PID_0D02
%CompositeAdbInterface%     = USB_Install, USBVID_18D1&PID_0D02&MI_01
%SingleAdbInterface%        = USB_Install, USBVID_18D1&PID_4E11
%CompositeAdbInterface%     = USB_Install, USBVID_18D1&PID_4E12&MI_01
%CompositeAdbInterface%     = USB_Install, USBVID_18D1&PID_4E22&MI_01

[Google.NTamd64]
; HTC Dream
%SingleAdbInterface%        = USB_Install, USBVID_0BB4&PID_0C01
%CompositeAdbInterface%     = USB_Install, USBVID_0BB4&PID_0C02&MI_01
%SingleBootLoaderInterface% = USB_Install, USBVID_0BB4&PID_0FFF
; HTC Magic
%CompositeAdbInterface%     = USB_Install, USBVID_0BB4&PID_0C03&MI_01
;
;Moto Sholes
%SingleAdbInterface%        = USB_Install, USBVID_22B8&PID_41DB
%CompositeAdbInterface%     = USB_Install, USBVID_22B8&PID_41DB&MI_01
;
;Google NexusOne
%SingleAdbInterface%        = USB_Install, USBVID_18D1&PID_0D02
%CompositeAdbInterface%     = USB_Install, USBVID_18D1&PID_0D02&MI_01
%SingleAdbInterface%        = USB_Install, USBVID_18D1&PID_4E11
%CompositeAdbInterface%     = USB_Install, USBVID_18D1&PID_4E12&MI_01
%CompositeAdbInterface%     = USB_Install, USBVID_18D1&PID_4E22&MI_01

[USB_Install]
Include = winusb.inf
Needs   = WINUSB.NT

[USB_Install.Services]
Include     = winusb.inf
AddService  = WinUSB,0x00000002,WinUSB_ServiceInstall

[WinUSB_ServiceInstall]
DisplayName     = %WinUSB_SvcDesc%
ServiceType     = 1
StartType       = 3
ErrorControl    = 1
ServiceBinary   = %12%WinUSB.sys

[USB_Install.Wdf]
KmdfService = WINUSB, WinUSB_Install

[WinUSB_Install]
KmdfLibraryVersion  = 1.9

[USB_Install.HW]
AddReg  = Dev_AddReg

[Dev_AddReg]
HKR,,DeviceInterfaceGUIDs,0x10000,"{F72FE0D4-CBCB-407d-8814-9ED673D0DD6B}"

[USB_Install.CoInstallers]
AddReg    = CoInstallers_AddReg
CopyFiles = CoInstallers_CopyFiles

[CoInstallers_AddReg]
HKR,,CoInstallers32,0x00010000,"WdfCoInstaller01009.dll,WdfCoInstaller","WinUSBCoInstaller2.dll"

[CoInstallers_CopyFiles]
WinUSBCoInstaller2.dll
WdfCoInstaller01009.dll

[DestinationDirs]
CoInstallers_CopyFiles=11

[SourceDisksNames]
1 = %DISK_NAME%,,,i386
2 = %DISK_NAME%,,,amd64

[SourceDisksFiles.x86]
WinUSBCoInstaller2.dll  = 1
WdfCoInstaller01009.dll = 1

[SourceDisksFiles.amd64]
WinUSBCoInstaller2.dll  = 2
WdfCoInstaller01009.dll = 2

[Strings]
ProviderName                = "Google, Inc."
SingleAdbInterface          = "Android ADB Interface"
CompositeAdbInterface       = "Android Composite ADB Interface"
SingleBootLoaderInterface   = "Android Bootloader Interface"
WinUSB_SvcDesc              = "Android USB Driver"
DISK_NAME                   = "Android WinUsb installation disk"
ClassName                   = "Android Phone"

 


這份文件要從最後的[Strings]
這區塊開始看

 

 

2011-09-03 02 42 00.png  

比對了一下,這個驅動

類別名叫Android Phone

驅動有三個,個別叫做

Android ADB Interface
Android Composite ADB Interface
Android Bootloader Interface

驅動有分32位元版和64位元版

紅字的部分就是我們要更動的

 

步驟如下:  (XP測試可用)

  1.  先判斷你的作業系統是  32位元(x86)   還是  64位元(x64)

決定你這行是要加在 [Google.NTx86]   還是 [Google.NTamd64]  區塊

  1.  找到裝置管理員,找到那驚嘆號的Android上面按一下   右鍵  ->  內容

2011-09-03 03 17 14.png   

 

在詳細資料頁籤裡面,找到硬體識別碼  (Hardware Ids)  (這是重點)

2011-09-03 03 17 02.png

把這些文字選起來按 Ctrl +  C   然後在文字編輯器貼上

 

我的有二筆資料,如下

 

USBVid_18d1&Pid_0005&Rev_0223&MI_01
USBVid_18d1&Pid_0005&MI_01

 

 

  1.   依樣畫葫蘆,將文字加上去

 

%SingleAdbInterface%        = USB_Install, USBVid_18d1&Pid_0005&Rev_0223&MI_01
%SingleAdbInterface%        = USB_Install, USBVid_18d1&Pid_0005&MI_01

開頭至於要加哪一個(SingleAdbInterface , CompositeAdbInterface ),都試試看

2011-09-03 03 19 14.png  

 

 

  1.    然後就存檔,重新裝驅動看看,一定會抓到「非常合適」的驅動

因為你手動把他改上去了嘛   XDDD

 

 

 

(Win7 會出現這個大紅色的警示視窗,不用裡他直接按Install this driver software anyway)

2011-09-03 03 20 49.png

就安裝成功了

2011-09-03 03 21 12.png  

 

 

  1.   再來打開cmd  ,用cd 指令切到       <你裝的android SDK的路徑>platform-tools

我的是

C:Program FilesAndroidandroid-sdkplatform-tools

然後鍵入指令

adb kill-server

然後再鍵入指令

adb start-server

重新啟動連接介面的程式

 

神奇的事情就發生了喔
我把驅動裝好了~~~

[Android]解決INSTALL_FAILED_INSUFFICIENT_STORAGE

開發時出現

[2011-08-03 14:50:26 – videoAdsTest] Installation error: INSTALL_FAILED_INSUFFICIENT_STORAGE

[2011-08-03 14:50:26 – videoAdsTest] Please check logcat output for more details.
[2011-08-03 14:50:27 – videoAdsTest] Launch canceled!

代表說模擬器的程式空間被裝滿了

手動到

menu > 設定 > 管理應用程式  手動移除一些之前測試的程式.

 

或是關掉模擬器,重新啟動模擬器時選擇Wipe User Data

[Android]解決模擬器invalid command-line parameter問題

之前更新Android的SDK之後,打開模擬器出現了以下的問題

2011-08-03 20 57 45.png   

上面寫的是

invalid command-line parameter: Files.
Hint: use ‘@foo’ to launch a virtual device named ‘foo’.
please use -help for more information

意思說是指令列錯誤

 


查了網路上的資料

2011-08-03 21 02 13.png

在Eclipse的  Window >  Preferences  中

2011-08-03 21 04 15.png

 

在左側Android的選項中,重新指定SDK的路徑

 

 

我的設定是

D:Program Files (x86)Androidandroid-sdk

手動修改成

D:Progra~2Androidandroid-sdk

像這樣

2011-08-03 21 05 34.png

 

如果你的SDK是裝在

C:Program FilesAndroidandroid-sdk

那就手動修改成

C:Progra~1Androidandroid-sdk

這樣就OK了

————————————————————————–  

 

因為以前的檔名(資料夾名稱)都要符合DOS的8+3的規定

檔名只能有8個字元加上3個字元的副檔名

 

到了之後才有所謂的長檔名(沒有這種限制)

在DOS裡的長檔名表示就是,打出8個字之後,加上~符號

第一個就1號  第二個就2號……以此類推

原文

Explanation: All nowadays folder names longer than 8 characters have their old DOS equivalent name (8 characters with no spaces).

So:
– “C:Program Files…” is converted into “C:Progra~1…”
– “C:Program Files (x86)…” becomes “C:Progra~2…”

 

至於為何會倒退回之前的表示法

我想這Bug  以後會被修掉吧

 

 

參考資料

http://ideanotion.net/android-sdk-invalid-command-line-parameter-files-error/

[Android] 讓你開發的Android程式也支援APP2SD

device1.png   

一個程式開發成這樣感覺起來也很偉大吧,所謂的APP2SD

一點都不難

這是 Android 2.2 的特色,只要在開發程式時給一個設定值

Android 2.2的系統會自動跳出這個視窗,詢問使用者是否將程式裝在記憶卡上

節省手機上有限的空間

至於如何做搬移,這就是Android系統自己會去調配的事情

它不會全部將程式裝在記憶卡上,而會搬移大部分的資料到記憶卡上

只會留下必要的程式在手機的儲存空間

也就是大家所謂的APP2SD

 

大部分的討論串大多是在如何強制讓系統直接搬移程式

在這裡教你如何在程式開發的角度上,把這項功能也考量進去

 

對於遊戲….等大容量的程式,Android官方是比較推薦上述類型的程式裝在記憶卡上

 


 

開發需求

只要一個最低需求

Android 2.2 (API Level:8)

做為最低開發的目標程式標準

(當然手機也要隨著配合啦….)

 

—————————————————————

AndroidManifest.xml 中,在<manifest> </manifest>的標籤上

加入一個android:installLocation的參數,本例為"auto"

如以下所示:

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

      package="com.J_Test.TestProject"

      android:versionCode="1"

      android:versionName="1.0"

      android:installLocation="auto">

    <uses-sdk android:minSdkVersion="8"
/>

    <application android:icon="@drawable/icon" android:label="@string/app_name">

        <activity android:name=".main"

                  android:label="@string/app_name">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

    </application>

</manifest>

—————————————————————

關於installLocation

關鍵的參數android:installLocation

有三種參數能使用

internalOnly  就是只能限制於在主記憶體中運作

auto 就是自動判斷

preferExternal  是希望能裝在記憶卡中(例如:遊戲….)

不是所有程式都使用auto讓程式判斷就好

 

 

Android官方也提到

有些類型的程式不應該使用APP2SD的

因為把資料裝在記憶卡需考量到

記憶卡如果無緣無故被退出,程式很有可能會當掉(crash)

當然,沒有該有安裝程式的那張記憶卡,程式不會在Android系統中出現icon

 

 

 

 

Services  程式有寫到服務,需要在系統中常駐運行的

Alarm Services 有使用定時提醒的服務,記憶卡退出代表無法正常提醒使用者

Input Method Engines  你開發的程式是做為輸入法的程式

Live Wallpapers 你開發的程式是做為定時換桌布的類型的

Live Folders  放在Android桌面上的動態文件夾,記憶卡被卸載時,該資料夾會暫時消失

App Widgets   你開發的程式是有提供桌面的插件的

Account Managers   程式有使用到Account Manager這個class元件的

Sync Adapters  程式有使用到AbstractThreadedSyncAdapter這個class元件的

Device Administrators  程式有使用到DeviceAdminReceiver這個元件的,做為系統管理類型的

Broadcast Receivers listening for "boot completed"  你的程式會隨著系統開機而會自動執行的,系統剛開機時

 

 

在是否搬移頁面的提示框按下是,出現該程式的詳細資訊

device2.png

按下移至USB儲存裝置

device3.png

就把資料移到記憶卡裡了,就成功了

 device4.png

官方網站說明

http://developer.android.com/guide/topics/manifest/manifest-element.html#install
 http://developer.android.com/guide/appendix/install-location.html

參考資料

http://www.pin5i.com/showtopic-android-2.2-apk-installlocation.html

[Android] Desire HD adb.exe android 2.3.3 crash

注意:這只是網友的ㄧ個小更新,要尋求正統android.com官方的更新

如果官方的更新沒辦法解決問題才來看這裡

 

會出問題的

機種: HTC Desire HD

ROM: Android 2.3.3  (核心版本: 2.36.405.8 RADIO:12.54.60.25_26.09.04.11_M2)

就是使用機器達人出的特調GRI40-2的ROM

http://gfans.bryan.tw/2011/05/05/1894

 

Android SDK r11 (目前最新的)

在Windows 7 x64仍然會出現問題

在Windows XP x32似乎已解決問題,但還是偶爾不穩定

 

Android SDK r10 是確定不管是x32還是x64都有相同的問題

 

Version: Helios Service Release 2
Build id: 20110301-1815

Android Development Toolkit (ADT)
Version: 10.0.1.v201103111512-110841

Dalvik Debug Monitor Service (DDMS)
Version: 10.0.1.v201103111512-110841

Android Debug Bridge version 1.0.26

 

————————————————————–

後來更新到Android SDK r12仍然有這個問題

 

可能就要服用adb patch

 

http://android.googlecode.com/issues/attachment?aid=8293722374312378755&name=adb.exe&token=f780c80896314348c1a12f980f1aa9b0

 

 

 

(google了一下)

類似問題適用

http://forum.xda-developers.com/archive/index.php/t-938593.html
http://stackoverflow.com/questions/5455553/adb-crashing-in-eclipse
http://stackoverflow.com/questions/4573019/adb-crashes-when-device-attached-with-eclipse
http://stackoverflow.com/questions/4573019/adb-crashes-when-device-attached-with-eclipse

 

參考網址

http://code.google.com/p/android/issues/detail?id=12141

[Android] debug不用線,用ADB連接3G/wifi手機

介紹一個很酷的功能無意間看到的

常用Eclipse的人都知道

不管是來開發程式的,還是知名部落客拿來截圖免root權限的

都會用到DDMS

 

通常要用連接USB傳輸線連接到實體手機

等待DDMS跳出你的手機之後才做下一步動作 (開發程式,截圖…等等)

 

這裡教你debug不用線,用3G或wifi直接無線Deploy程式

直接線上出Log

真的還蠻酷的

 

條件

曾經連接過USB做過設定的手機

 

設定方法

1.  先確定手機有電,3G或Wifi的網路有開

2.  用 USB 傳輸線接上你的手機

3.  找到Android SDK的路徑 platform-tools/ 資料夾路徑

(每個人裝位置因作業系統或個人喜好的都不太一樣)

以SDK r11為例,用32位元的Windows用exe版的安裝預設在

C:\Program Files\Android\android-sdk\platform-tools

 

4.  按Win key + R,在執行的視窗中打入 cmd

打入指令 (綠色的為指令,黑色的部分為說明)

C:\

cd C:\Program Files\Android\android-sdk\platform-tools

意思是切換資料夾到剛剛找的路徑

adb tcpip 5555 

意思是用tcpip連線,連接埠號5555做Debug伺服器

 

5.  然後就可以脫離USB連線了

在同一個地方再打入像是

adb connect 192.168.1.3:5555 

中間換成你手機的IP位址

意思是讓電腦使用網路連線到你的手機

 

6.  這時候你就可以用無線做操作了

你可以打 adb logcat 

就會動態傳輸手機的Log到畫面上 (按Ctrl+C結束)

 

打入adb devices,就會列出這個特別的裝置

List of devices attached
192.168.1.3:5555     device

就不會是類似

List of devices attached
SH11KRX10258    device

這樣

 

回到Eclipse上,DDMS已經出現這個特別的裝置了

————————————————————

還原回正常的USB傳輸線的模式,要打 adb usb

 

————————————————————

官方原文截錄

  1. 用 USB 傳輸線接上你的手機
  2. 到Android SDK的路徑 platform-tools/ 資料夾
  3. directory, enter adb tcpip 5555 at the command prompt.
  4. Enter adb connect <device-ip-address>:5555 You should now be connected to the Android-powered device and can issue the usual adb commands like adb logcat.
  5. To set your device to listen on USB, enter adb usb.

http://developer.android.com/guide/topics/usb/index.html

 

————————————————————

補充

Root手機的用戶有福了 🙂

可以不用像是上面這麼複雜喔

Google Market裡面有提供

類似這種Wifi ADB的這種軟體唷

只是需要Root………不知道這是啥的就跳過這段吧

 

adbWireless (Widget version)

https://market.android.com/details?id=siir.es.adbWireless

WiFi ADB

https://market.android.com/details?id=com.ttxapps.wifiadb

 

其中我最喜歡這套

ADB over WIFI Widget
Mehdy Bohlool

https://market.android.com/details?id=bohlool.net.wifiadb

他安裝完沒有甚麼變化和圖示

 

要去桌面 menu >  小工具

然後找到ADB over WIFI Widget

就會有個圖示在你的桌面摟

 

 

電腦這端用上述的

adb connect 192.168.1.3

(192.168.1.3是那隻上面看到的IP)

就可以連上去成為一個裝置摟

 

不用的時候就按一下小綠人就又回復正常摟

 

 

這樣就可以遠端桌面,遠端debug摟

是不是粉方便呢?

 

 

 

 

 

[Android] 使用HTTP的POST方式和網頁表單溝通

 

2011-04-21 02 04 20.png  


2012.08.13版主回覆:

底下好多留言都詢問,奇怪?怎麼模擬器上都出現文字
然後網頁上沒出現?

不要再相信沒有事實根據的說法了 (大誤
不要再說沒有小弟不才,沒有爬文 

請移步至新版:

http://j796160836.pixnet.net/blog/post/30577968

個人還是建議從本篇看起,概念比較清楚


 

 最近常常被問到這些問題

Android要怎麼接MySQL資料庫呀? MySQL在網路上

Android怎麼接上雲端的資料庫?

Android怎麼傳送表單內容?

 

這些答案都在這裡

網路上的資料庫,不太容易,也不建議直接與資料庫做溝通

因為涉及到資訊安全的東西

 

 

可以用網頁來做中間的介面,讓二者產生關聯

做類似WebServices的東西
(雖然不是真正的WebServices,但其角色是類似的)

 


伺服器端

你可以簡單寫個印字串的程式,如果收到POST的封包

就印出其內容

如果是PHP可能這樣寫

<?php

        //宣告utf-8的編碼

        header("Content-Type:text/html; charset=utf-8");

        $data=$_POST[‘data’];

        echo "data=".$data;

?>

把寫好程式,取名httpPostTest.php

把他擺到htdoc底下 (windows)

或是/var/www/ (ubuntu)

或是/var/www/html (Fedora, Cent OS)

用ASP可能這樣寫

<%@ LANGUAGE=VBScript CodePage=950%>
<%
data=request("data")
response.write "data="&data
%>

不管如何,請照你的伺服器語言撰寫

 


Android手機端

 

可以用範例程式碼來解決問題

這些範例仿間找的到

因為過於複雜,所以我又重新整理了其範例給大家看

 

關鍵程式碼不到5行,但重點是在於你對Android的UI介面認識與否

和動態網頁的語言的熟練度

 

 


照慣例,文字要放在string.xml裡

/res/values/string.xml

<?xml version="1.0" encoding="utf-8"?>

<resources>

    <string name="app_name">httpPostTest</string>

    <string name="help_txt">請輸入文字以便使用POST傳送:</string>

    <string name="txt_message_hint">請輸入文字</string>

    <string name="send">送出</string>

</resources>


看一下Layout檔

/res/layout/main.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

<TextView 

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

    android:text="@string/help_txt"

    />

    <EditText

    android:id="@+id/txt_message"

    android:hint="@string/txt_message_hint"

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

   />

   <Button

   android:id="@+id/send_btn"

   android:text="@string/send"

   android:layout_width="fill_parent"

   android:layout_height="wrap_content"

   />

</LinearLayout>

 

這裡沒甚麼特別,就是一個EditText來讓使用者能打入資料

然候一個按鈕讓系統傳送封包到寫死的網址路徑

 


程式碼要上了

main.java

 

package com.J_Test.httpPostTest;

 

/*

 * ====httpPostTest範例====

 * 1. 請先確認Apache有沒有正確執行

 * 2. 放入以下PHP代碼到htdoc資料夾中(或是/var/www/)等路徑

 *

 

 <?php

 //宣告utf-8的編碼

 header("Content-Type:text/html; charset=utf-8");

 $data=$_POST[‘data’];

 echo "data=".$data;

 ?>

 

 *

 * 3. 修改uriAPIIP和檔案名稱為正確 (請用電腦對外之IP)

 * (不可用127.0.0.1因為Android手機上也有本機位址)

 *

 */

 

import java.io.IOException;

import java.util.ArrayList;

import java.util.List;

 

import org.apache.http.HttpResponse;

import org.apache.http.NameValuePair;

import org.apache.http.client.ClientProtocolException;

import org.apache.http.client.entity.UrlEncodedFormEntity;

import org.apache.http.client.methods.HttpPost;

import org.apache.http.impl.client.DefaultHttpClient;

import org.apache.http.message.BasicNameValuePair;

import org.apache.http.protocol.HTTP;

import org.apache.http.util.EntityUtils;

 

import android.app.Activity;

import android.os.Bundle;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.EditText;

import android.widget.Toast;

 

publicclass main extends Activity implements OnClickListener

{

    private EditText txtMessage;

    private Button sendBtn;

    private String uriAPI = "http://192.168.1.3/httpPostTest.php";

 

    @Override

    publicvoid onCreate(Bundle savedInstanceState)

    {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

 

        txtMessage = (EditText) findViewById(R.id.txt_message);

        sendBtn = (Button) findViewById(R.id.send_btn);

 

        if (sendBtn != null)

        {

            sendBtn.setOnClickListener(this);

        }


    }

 

    @Override

    publicvoid onClick(View v)

    {

        if (v == sendBtn)

        {

            String msg = null;

            if (txtMessage != null)

            {

                msg = txtMessage.getEditableText().toString();

                String result = sendPostDataToInternet(msg);

 

                // 印出網路回傳的文字

                if (result != null)

                    Toast.makeText(this, result, Toast.LENGTH_LONG).show();

            }

        }

    }

 

    private String sendPostDataToInternet(String strTxt)

    {

        / 建立HTTP Post連線 /

        HttpPost httpRequest = new HttpPost(uriAPI);

        /*

         * Post運作傳送變數必須用NameValuePair[]陣列儲存

         */

        List<NameValuePair> params = new ArrayList<NameValuePair>();

        params.add(new BasicNameValuePair("data", strTxt));

        try

        {

            / 發出HTTP request /

            httpRequest.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));

            / 取得HTTP response /

            HttpResponse httpResponse = new DefaultHttpClient()

                    .execute(httpRequest);

            / 若狀態碼為200 ok /

            if (httpResponse.getStatusLine().getStatusCode() == 200)

            {

                / 取出回應字串 /

                String strResult = EntityUtils.toString(httpResponse

                        .getEntity());

 

                // 回傳回應字串

                return strResult;

            }

 

        } catch (ClientProtocolException e)

        {

            Toast.makeText(this, e.getMessage().toString(), Toast.LENGTH_SHORT)

                    .show();

            e.printStackTrace();

        } catch (IOException e)

        {

            Toast.makeText(this, e.getMessage().toString(), Toast.LENGTH_SHORT)

                    .show();

            e.printStackTrace();

        } catch (Exception e)

        {

            Toast.makeText(this, e.getMessage().toString(), Toast.LENGTH_SHORT)

                    .show();

            e.printStackTrace();

        }

        returnnull;

    }

 

}

 

 


最後是AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

      package="com.J_Test.httpPostTest"

      android:versionCode="1"

      android:versionName="1.0">

    <uses-sdk android:minSdkVersion="8" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">

        <activity android:name=".main"

                  android:label="@string/app_name">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

    </application>

    <!– 這裡加入可以存取網路的權限 –>

    <uses-permission android:name="android.permission.INTERNET" />

</manifest>

 

這裡很重要也很容易疏忽

除了Activity要在這裡註冊外

能對外上網的權限也在這裡註冊

如果遇到

WARN/System.err(503): java.net.SocketException: Permission denied

就該發現權限少了這一項

<uses-permission android:name="android.permission.INTERNET" />

另一個權限也常用,但仿間書常常會遺漏

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

就是能夠存取手機記憶卡的權限

 

 


這樣有看懂嗎?

 

主要重點在這裡

  / 建立HTTP Post連線 /

  HttpPost httpRequest = new HttpPost(uriAPI);

這個HttpPost是主要的Class名,這裡要填入存取的網址

 

然後

 /*

  * Post運作傳送變數必須用NameValuePair[]陣列儲存

  */

  List<NameValuePair> params = new ArrayList<NameValuePair>();

  params.add(new BasicNameValuePair("data", strTxt));

 

使用系統指定的資料格式BasicNameValuePair

BasicNameValuePair在new的時候裡面為二個字串,一個是名稱,一個是值

這裡用"data"當名字,值就是剛剛讓使用者打的資料

 

  / 發出HTTP request /

  httpRequest.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));

的  HTTP.UTF_8 可以指定編碼格式,不過要跟伺服器端相同(照我範例走的話是不用動)



2011-04-21 02 18 45.png  

其實這個Android其實是跟以下網頁的功能是相同的

有些值你可以對照看看,相關對照的字詞都用顏色標明了

可以將它另存到httpPostTest.htm

 

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”&gt;

<html xmlns="http://www.w3.org/1999/xhtml”&gt;

<head>
<meta http-equiv="Content-Language" content="zh-tw" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF_8" />
<title>httpPostTest</title>
<head></head>
<body>
請輸入文字以便使用POST傳送:<br />
<form method="POST" action="http://192.168.1.3/httpPostTest.php">
<input type="text" name="data" size="20" value="請輸入文字" /><br />
<input name="Submit1" type="submit" value="送出" /><br />
</form>
</body>
</html>

 


延伸

其實網頁大多喜歡把很多功能做在一個檔裡,就是用一個隱藏值來判斷現在進行到那個階段

本例用op當階段的旗標

 

PHP版:

請輸入文字以便使用POST傳送:<br />
<form method="POST" action="<?php echo $_SERVER[‘PHP_SELF’]; ?>">
<input type="text" name="data" size="20" value="請輸入文字" /><br />
<input type="hidden" name="op" value="showValue" />
<input name="Submit1" type="submit" value="送出" /><br />
</form>

 

ASP版:

 

請輸入文字以便使用POST傳送:<br />
<form method="POST" action="<%=Request.ServerVariables("PATH_INFO")%>">
<input type="text" name="data" size="20" value="請輸入文字" /><br />
<input type="hidden" name="op" value="showValue" />
<input name="Submit1" type="submit" value="送出" /><br />
</form>


2011-04-21 02 05 40.png

   2011-04-21 02 17 35.png  

 

2011-04-21 02 25 29.png  

 

不過還是再三的提醒

範例程式碼很簡陋,指是要讓大家看懂其中的語法

真正寫程式使用的時候

 

要記得在伺服器判斷輸入的型別

更不要直接讓表單直接下SQL指令

 

怕被資料隱碼攻擊(SQL Injection)

 

這是很危險低~~~~

 

 

參考資料
Google Android SDK開發範例大全 佘志龍等人著
悅知文化

[Android] 從新建專案看版面Layout設計

這部分給剛入門的Android新手看的,寫的不好請多包涵

 

一個Android手機程式中

一個畫面,包含可能程式化的內容,就可以稱為一個Activity

定義不重要,這只是我的解釋而已

至少一個Activity會抓一個Layout檔,來顯示版面

才能做之後的事情

 

———————————————————–

 

而Android的版面Layout基本上都是用XML做定義的

XML概念跟HTML有那麼一點點相似,但不太一樣

XML自訂性較高,但也較嚴謹,只要出錯整的檔都會讀不出來

基本上原則就是

  • Node要成雙成對,沒有結束符號要加上 / 符號
  • Root Node素只能有一個

這部分就不再贅述

 

 

這是剛新建專案的Layout

layout.xml,路徑在res/layout/main.xml

新開的檔會以建立的Activity做名稱,一個Activity可以有一個Layout檔,也可以用人家的(自己沒有)

<?xml version=“1.0” encoding=“utf-8”?>

<LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”

    android:orientation=“vertical”

    android:layout_width=“fill_parent”

    android:layout_height=“fill_parent”

    >

<TextView 

    android:layout_width=“fill_parent”

    android:layout_height=“wrap_content”

    android:text=“@string/hello”

    />

</LinearLayout>

 

 

首先看看Layout檔

HelloWorld只會有二個控制項,也是首先會接觸到的

TextView 

手機螢幕部分只要眼睛看的見的幾乎都是控制項,叫做View

有以下屬性

    android:layout_width  為控制項的寬度

    android:layout_height  為控制項的高度

單位可以填dip,也是最常用的,就是單位螢幕點(相對長度),依解析度和螢幕尺寸不同而會有不同

也可以填像素px啦 (這樣會失去自動調整的能力,官方不建議)

也可以填以下屬性:

    “fill_parent”    代表填滿父控制項,在這裡通常是指撐滿螢幕(寬度或是高度)

  “wrap_content” 就是指依照你內容有多少就給你多少(寬度或是高度)

android:text  就是要顯示的文字拉

 

怎麼沒有看到  Hello World, main!   呢?

原來文字存到string.xml裡了

“@string/hello” 這樣就是在指,去string.xml找到名為hello的字串,當然也可以直接打上去拉,只是不建議這樣做,以後有關多國語言會提到

 

 

這裡是string.xml,路徑在res/value/string.xml

<?xml version=“1.0” encoding=“utf-8”?>

 

<resources> 

    <string name=“hello”>Hello World, main!</string>

    <string name=“app_name”>Hello World test</string>

</resources> 

 

之後會提到android:id的部分,這裡先不提

 

———————————————————–

再來講

LinearLayout 

這種Layout的家族統稱稱為ViewGroup

ViewGroup可以想成各種View的群組,有以下幾種

  • AbsoluteLayout
  • RelativeLayout
  • FrameLayout
  • LinearLayout

通常也最常用的就是LinearLayout,原因無他,只是方便好用

LinearLayout只會做一件事,指定一個方向(垂直或是水平)

然後不管控制項有多大,全部照樣往下(或往右)排排站

 

在這裡LinearLayout有以下屬性

xmlns:android=“http://schemas.android.com/apk/res/android”   這句話絕對不能省略,放在最外層的那控制項即可

依據XML的特性,要去指定一些標籤的定義,就像法條才會有憑有據

android:orientation=“vertical”   就是排列方向為垂直(由上而下)

android:orientation=“horizontal”   就是排列方向為水平(由左而右)

 

———————————————————–

講一下

RelativeLayout 

好了

在Layout檔看起來如下:

 

<RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android” 

    android:layout_width=“fill_parent”

    android:layout_height=“fill_parent”

    >

 

</RelativeLayout>

看起來跟LinearLayout沒啥不同

但多的特性就多了

首先,他沒有android:orientation可以用,因為他是用控制項的相對位置去編排的

如果控制項沒有設定那些多出來的參數,很有可能會發生二控制項重疊

裡面的控制項屬性會多出二種類型的屬性

  • 邊框位置
  • 跟另一個控制項的相對位置

屬性有以下:

 

android:layout_alignLeft 

android:layout_toRightOf 

android:layout_below 

android:layout_above 

android:layout_alignParentLeft 

android:layout_alignParentTop 

android:layout_alignParentRight 

android:layout_alignParentBottom 

android:layout_centerInParent 

 

 

邊框位置

先有一個控制項位置做絕對位置,才能做相對位置的判定嘛

以word的文字編排方式可以很直覺的理解

android:layout_alignParentLeft  靠左對齊,(吸附邊框左邊)

 

android:layout_alignParentTop   靠上對齊,(吸附邊框上方)

android:layout_alignParentRight   靠右對齊,(吸附邊框右邊)

android:layout_alignParentBottom   靠下對齊,(吸附邊框下方)

android:layout_centerInParent    置中,(計算放在正中間)

這類型就是以RelativeLayout的邊框做位置,做對齊

 

而另一種就是以別人的控制項位置做為自己的控制項位置

 

android:layout_toLeftOf       這在(等下要寫的控制項的名)的左邊

android:layout_toRightOf        這在(等下要寫的控制項的名)的右邊

android:layout_below        這在(等下要寫的控制項名)的下面

android:layout_above       這在(等下要寫的控制項名)的上面

 

這個等下要寫控制項的名稱,很重要

控制項的順序也很重要

基本上,這個名子一定要再你的Layout上有提及

還有這個控制項名稱要在XML敘述上比現在這個控制項還要早出現

XML的Layout檔上基本上可以先寫靠左或靠右對齊的控制項敘述

才寫這種相對敘述

 

控制項在XML裡寫的順序很重要

—————————————————–

 

 

補充:FrameLayout 

 

FrameLayout可以想成是RelativeLayout的功能閹割版

 

RelativeLayout的部份

 

1. 能對齊View的框邊

例如:

android:layout_alignParentLeft  靠左對齊,(吸附邊框左邊)

或是

2. 設定二格View之間的排列關係

例如:

android:layout_toLeftOf       這在(等下要寫的控制項的名)的左邊

上面都提過了

 

 

FrameLayout只剩下

 

對齊View的框邊的功能

android:layout_gravity  來指定

如果在其中的View有二個設定成一樣的話呢

就會「依序」重疊上去

 

注意一點,只有RelativeLayoutFrameLayout 

才會發生控制項有重疊的現象

如果版面看似調不出來,可以檢查一下是否為二個控制項重疊

或是版面出界了

 

版面出界的狀況在初期很容易發生

 

像是LinearLayout 裡面有二個控制項

第一個控制項是  android:layout_width=“fill_parent”    android:layout_height=“fill_parent”

填滿全螢幕

第二個  android:layout_width=wrap_content    android:layout_height=wrap_content

這樣第二個一定出界的

 

設定上要小心

 

—————————————————–

所有的View和ViewGroup都可能需要android:id這東西

他會在Compile專案時會產生一個R檔,就是gen/你的package名稱/R.java

這個R檔會包含你的所有Layout上的所有id和string.xml上的名稱….等等內容,沒事別去動他

寫法如下

    android:id=“@+id/tv01”

這裡的@就是叫程式去R檔裡面找到代稱叫做tv01的id名稱

這裡的+號不能省略,代表的是我需要在R檔裡新增一個id名稱叫做

這個所有的Layout檔都適用,不同Layout裡的控制項id最好是要不一樣

在一個Layout檔中,控制項的id一定要不同

 

到時候程式可以用findViewById去依照這個id抓取其控制項

 

—————————————————–

底下寫一個LinearLayout的範例,改用RelativeLayout會怎麼寫

 

現在用LinearLayout來撰寫Layout

 

<?xml version=“1.0” encoding=“utf-8”?>

<LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”

    android:orientation=“vertical”

    android:layout_width=“fill_parent”

    android:layout_height=“fill_parent”

    >

<TextView 

    android:id=“@+id/tv01”

    android:layout_width=“wrap_content”

    android:layout_height=“wrap_content”

    android:text=“Text01”

    />

    <TextView 

    android:id=“@+id/tv02” 

    android:layout_width=“wrap_content”

    android:layout_height=“wrap_content”

    android:text=“Text02”

    />

    <TextView 

    android:id=“@+id/tv03”

    android:layout_width=“wrap_content”

    android:layout_height=“wrap_content”

    android:text=“Text03”

    />

    <TextView 

    android:id=“@+id/tv04”

    android:layout_width=“wrap_content”

    android:layout_height=“wrap_content”

    android:text=“Text04”

    />

    <TextView 

    android:id=“@+id/tv05”

    android:layout_width=“wrap_content”

    android:layout_height=“wrap_content”

    android:text=“Text05”

    />

</LinearLayout>

 

 

—————————————————–

改用RelativeLayout會變成

 

 

<?xml version=“1.0” encoding=“utf-8”?>

<RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”

    android:layout_width=“fill_parent”

    android:layout_height=“fill_parent”

    >

<TextView 

    android:id=“@+id/tv01”

    android:layout_alignParentTop=“true”

    android:layout_alignParentLeft=“true”

    android:layout_width=“wrap_content”

    android:layout_height=“wrap_content”

    android:text=“Text01”

    />

    <TextView 

    android:id=“@+id/tv02” 

    android:layout_below=“@id/tv01”

    android:layout_width=“wrap_content”

    android:layout_height=“wrap_content”

    android:text=“Text02”

    />

    <TextView 

    android:id=“@+id/tv03”

    android:layout_below=“@id/tv02”

    android:layout_width=“wrap_content”

    android:layout_height=“wrap_content”

    android:text=“Text03”

    />

    <TextView 

    android:id=“@+id/tv04”

    android:layout_below=“@id/tv03”

    android:layout_width=“wrap_content”

    android:layout_height=“wrap_content”

    android:text=“Text04”

    />

    <TextView 

    android:id=“@+id/tv05”

    android:layout_below=“@id/tv04”

    android:layout_width=“wrap_content”

    android:layout_height=“wrap_content”

    android:text=“Text05”

    />

</RelativeLayout>

 

 

 

 

android:orientation=“vertical”

[Android] 多執行緒-Handler和Thread的關係

要寫Android,難懂的多執行緒一定要給他搞懂
在Android當中,如果做超過5秒被系統強制關閉
(收到Application not Responsed簡稱ANR)
onCreate()如果做超過10秒就會跳ANR

所以繁重的事情不能在onCreate()裡頭做

有沒有解決辦法?? 就是Thread 中文叫執行緒

搞不清楚?

 

用現實的例子說明好了

 

Thread ==>  做工的工人 

Runnable ==> 要做的工作事項 (工作說明書)

 

一般的Thread,工人請他來,指定工作給他做。做完就收工閃人回家

有一種Thread,他的性質比較不一樣

算是包月的那種特約駐點工人吧,要簽合約的(笑)

上班時間跟公務員一樣,就算沒事情做也要standby在那裡

這種工人他會有個經紀人幫他管要給他作的事

 

HandlerThread ==>  特約工人

Handler ==>  特約工人的經紀人

———————————————————————————-

回到程式,一般來說,Activity 執行的時候

會有個 UI Thread 或叫 main Thread
就是你程式本身原有的執行緒,管著畫面呈現…..等等事物

main Thread (或叫UI Thread)就是你的程式進入點

 

而main Thread,他也是個HandlerThread

可以給他一個Handler,做接收訊息之用

———————————————————————————-

(以下程式碼只是示意,要表達程式碼的邏輯概念

實際上在運行的時候,模擬器的畫面不會產生任何的變化

可以把它當範本使用,稍加修改)

 

 

package com.J_Test.HandlerAndThread;

 

import android.app.Activity;

import android.os.Bundle;

import android.os.Handler;

import android.os.HandlerThread;

 

publicclass main extends Activity {

    /** Called when the activity is first created. */

    //找到UI工人的經紀人,這樣才能派遣工作  (找到顯示畫面的UI Thread上的Handler)

    private Handler mUI_Handler = new Handler();

    //宣告特約工人的經紀人

    private Handler mThreadHandler;

    //宣告特約工人

    private HandlerThread mThread;

 

    @Override

    publicvoid onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

 

       

        //聘請一個特約工人,有其經紀人派遣其工人做事 (另起一個有HandlerThread)

        mThread = new HandlerThread(“name”);

        //Worker待命,等待其工作 (開啟Thread)

        mThread.start();

        //找到特約工人的經紀人,這樣才能派遣工作 (找到Thread上的Handler)

        mThreadHandler=new Handler(mThread.getLooper());

       

       

        //請經紀人指派工作名稱 r,給工人做

        mThreadHandler.post(r1);

    }

   

    //工作名稱 r1 的工作內容

    private Runnable r1=new Runnable () {

        publicvoid run() {

            // TODO Auto-generated method stub

           

            //………………………..

            //做了很多事

           

            //請經紀人指派工作名稱 r,給工人做

            mUI_Handler.post(r2);

           

        }

    };

    //工作名稱 r2 的工作內容

    private Runnable r2=new Runnable () {

        publicvoid run() {

            // TODO Auto-generated method stub

           

            //………………………..

            //顯示畫面的動作

           

        }

    };

 

    @Override

    protectedvoid onDestroy() {

        super.onDestroy();

       

        //移除工人上的工作

        if (mThreadHandler != null) {

            mThreadHandler.removeCallbacks(r1);

        }

        //解聘工人 (關閉Thread)

        if (mThread != null) {

            mThread.quit();

        }

    }

}



—————

2011.10.17更新新版,請前往:

http://j796160836.pixnet.net/blog/post/29895257