Saturday, June 26, 2010

將自己設計xml的Layout轉成View:LayoutInflater

一般來講,我們用LayoutInflater做一件事:inflate

inflate這個方法總共有四種形式,目的都是把xml表述的layout轉化為View。其中只有一個我個人比較常用,View inflate(int resource, ViewGroup root),另外三個,其實目的和這個差不多。這裡簡單說一下它的用法,相信已經開始實踐的人都差不多用過了。
int resource,也就是resource/layout文件在R文件中對應的ID,這個必須指定。而ViewGroup root則可以是null,null時就只創建一個resource對應的View,不是null時,會將創建的view自動加為root的child。

問題就是為什麼要調用inflate(),而不是用setContentView()讓它自己去inflate?

setContentView()一旦調用, layout就會立刻被貼上UI。而inflate只會把Layout形成一個以view類實現成的對象。到時若有需要時再用 setContentView(view)把它貼上。

以上內容轉載至eoeAndroid論壇 

==========================================

一般來講,我們用LayoutInflater做一件事:inflate。 inflate這個方法總共有四種形式,目的都是把xml表述的layout轉化為View。 
This class is used to instantiate layout XML file into its corresponding View objects . It is never be used directly -- use getLayoutInflater() or getSystemService(String)getLayoutInflater() or getSystemService(String) to retrieve a standard LayoutInflater instance that is already hooked up to the current context and correctly configured for the device you are running on

1. Context.public abstract Object getSystemService (String name) :Return the handle to a system-level service by name. The class of the returned object varies by the requested name. 具體參見文檔。

2. 2種獲得LayoutInflater的方法
(1)通過SystemService獲得LayoutInflater inflater=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); (2)從給定的context中獲取




(3)二者區別:實質是一樣的,請看源碼

  1. public static LayoutInflater from(Context context) {  
  2.     LayoutInflater LayoutInflater =  
  3.             (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
  4.     if (LayoutInflater == null) {  
  5.         throw new AssertionError("LayoutInflater not found.");  
  6.     }  
  7.     return LayoutInflater;  
 3. LayoutInflater.inflate()將Layout文件轉換為View,顧名思義,專門供Layout使用的Inflater。
雖然 Layout也是View的子類,但在android中如果想將xml中的Layout轉換為View放入.java代碼中操作,只能通過 Inflater,而不能通過findViewById(),這一段描述有誤,看如下代碼。看下面文檔寫的已經很清楚。
  1. <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:orientation="vertical"   
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="wrap_content"> 
  5.       
  6.     <LinearLayout android:id="@+id/placeslist_linearlayout"  
  7.         android:layout_width="fill_parent"  
  8.         android:layout_height="wrap_content"  
  9.         android:orientation="vertical"> 
  10.           
  11.   LinearLayout> 
  12. >
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.placeslist_linearlayout); linearLayout.addView(place_type_text);這是可運行的,這上面的xml中,LinearLayout不再是 Layout的代表,而只是一個普通的View。

 4. findViewById有2中形式R.layout.xx 是引用res/layout/xx.xml的佈局文件(inflate方法),R.id.xx是引用佈局文件裡面的組件,組件的id是xx. ..(findViewById方法)。看看R.java配置文件吧,R對文件分類管理,多寫幾個layout.xml後你會發現,所有的組件id都能用 R.id.xx來查看,但是組件不在setContentView()裡面的layout中就無法使用,Activity.findViewById() 會出現NullPointException。

(1)Activity中的findViewById()
 (2)View中的findViewById()
 以上轉載至醋溜的部落格

Friday, June 25, 2010

消除ImageButton的邊框

若想讓圖形按鈕只顯示圖形而不要出現邊框,只要在xml裡將background設成背景顏色即可

Tuesday, June 22, 2010

Android的雜七雜八

1.mp.getCurrentPosition()事件最好不要在程式一開始就啟動(建議有按鈕或時間軸的觸發事件)→可能出現IlleagalArgumentException
2. mp.getCurrentPosition()因為回傳millisecond,數值太微小,很難跟動態歌詞的時間對到。
3.TextView.setVisibiliy()、TextView.setBackgroundColor()這種之類的method都要在onCreat()時就設定好,否則出錯

Sunday, June 20, 2010

在Android使用HttpPost時,出現socketException: permission undenied

這是一個經典錯誤,Socket不能對外連接,錯誤不會被報出,調測的時候,能看到Exception,這個Exception會有很多變體,所以不一一舉例,只要存在網絡互聯,該東東挺身而出,讓你的程序不得運行。原因是:需要訪問到網絡, 所以,在AndroidManifest.xml文件中,需要進行如下配置:


Saturday, June 19, 2010

幽靈程式

我還在開發的mp3播放程式,昨天去請老師幫忙找bug,遇到了一段相當奇怪的狀況

我要將歌詞從txt檔,用BufferedReader.readLine()將資料放進hashMap裡,
我使用String.indexof("a")==1做判斷式,如果第1位是a,那我就不要將這一行放入hashMap。

這個動態歌詞的txt檔一部份是這樣的
[ti:煙花易冷]
[ar:周杰倫]
[al:跨時代]
[by:253057646] 
[00:11.62]繁華聲 遁入空門 折煞了世人
[00:17.59]夢偏冷 輾轉一生 情債又幾本

我的目的只要將"[00:11.62]繁華聲 遁入空門 折煞了世人"這類型的完整歌詞放進hashMap,
怎麼說"a"都應該在第1位元吧,
但怪異的是Eclipse一直跳出判斷式,
可是相同的程式碼在Netbeans去執行卻沒問題。

老師幫我抓出String.indexof("a")的位置居然是==2,
[ar:周杰倫]的"[a"前面,居然隱藏了一個空字元!

更怪的來了,當我真的將[a改成==2後,進入判斷式,判斷式裡面使用一個switch去抓出每行歌詞的資料,
我一樣用String.indexof("[")
但是這時候"["又變成==0!

在一旁跟我一起開發mp3的同學,稱此所謂幽靈程式。

老兄,七月還沒到哩!

Looper和Handler,有如劉備需孔明,孔明也需劉備

之前一直在當柯南,試圖查明Message和Looper、Handler的這段三角關係,什麼時候要用Message,什麼時候還要再多加Looper,Handler又是要幹嘛的?後來看了高煥堂先生第3本著作:物件導向技術與執行緒模式(第三版),才終於知道Looper和Message是連體嬰的關係,
只有不斷的Looper,副執行緒才能不斷的丟出Message,
若沒有Looper,就只會丟僅一次的Message。

而且,Looper的相關功能通常都放在Thread的run()方法中,如下:
public subThread implements Runnalbe{
       public void run(){
            Looper.prepare();
               //程式區塊(譬如像在這裡寫handler.sendMessage(Message);指令)
        Looper.loop();
            }

這兩行method很關鍵,要重複丟出Message,程式碼就要被包含在這2個method當中。

註:如果啟動了Looper,當run()結束時,Thread也不會dead

Wednesday, June 16, 2010

在Eclipse按Ctrl沒有出現java原始碼

解決辦法

When you are coding in Eclipse, press CTRL and click on any core Java class name in your source. Eclipse will now show a screen saying you don't have the sources installed. However, in this screen there is a link saying "Attach source...". Click that link and import the src.zip file from your JDK installation directory (src.zip). This should do the trick

Tuesday, June 15, 2010

UniCode table

符號
代碼
[
'\u005B'
]
'\u005D'
.
'\u002E'

Friday, June 11, 2010

android裡的thread的朋友:Handler

android裡的thread
好像不能即時Toast和TextView.setText()
一直出現錯誤訊息(後來找到原因,你往下看就知道了)
只能跟在run()裡執行seekbar.setProgress()

很怪,若要用thread傳送即時訊息更新,好像要用到android的class:handler(花了一天得結果:這個推論沒有錯!但是更新和加總的動作不是副執行緒做,副執行緒只負責sleep(1000),副執行緒永遠不可能可以傳送資料去給主畫面)


Android為了考量安全性和執行效能,不允許副執行緒直接更改主畫面的資料
eoeAndroid網友ardwing在評論中提到:
Android的用戶界面更新不是一個執行緒安全的進程。但有多危險我也不清楚,就是知道不能在子執行緒上進行更新。也就是說一切更新必須黏在和OnCreate()一起的主執行緒上。但對於多工工作來說,特別是開發遊戲引擎上是一個障礙。 為了解決這問題,Android提供了一個處理程序和sendMessage的機制。使設計者可以把主執行緒看成一個用戶界面更新的大本營。而每個子執行緒則變成一個獨立運作、獨立判斷的小個體。這些小個體遇到一些用戶界面更新的需要,便透過 sendMessage向大本營發出更新要求,讓大本營,也就是主執行緒進行排期更新。而在主執行緒負責接收這些信息的地方就是處理器下跟帶(?)的程序。

高煥堂老師在他的教學網站說:
在每一個進程有一個主線程(Main Thread),它的主要任務是處理與UI有關的事件(Event),所以又常稱為UI線程。主線程可以誕生子線程(Child Thread),而且「經 常」需要誕生子線程。其主要原因是:主線程(UI線程)必須時時刻刻(標準為5秒內)去照顧UI的事件,以便快速回應使用者的要求。因此,UI線程沒空閒去執行較為費時的函數(或工作),只好誕生子線程去 執行較為費時的工作了。在Android平台裡,UI線程與其子線程之分工是很明確的:
l   子線程負責執行費時的工作。
l   主線程負責UI的操作或事件;子線程不可以插手有關UI的事。



以下是我寫的mp3播放程式中,想要即時更新已播放時間,
最後找到的辦法:
副執行緒負責每隔一秒傳message,好讓我主畫面去s=s+1

主執行緒:
1.需新增一個Handler
2.此類別需實作handleMessage()方法
protected void onCreate(Bundle savedInstanceState) {
hr = new Handler(){
             public void handleMessage(Message msg) {
                 switch(msg.what){
                 //檢查msg.what若為ABC,就執行s+1,
                 //並將值設成已播放時間
                 case ABC:
                     if(mp.isPlaying()==true){
                     s++;               
                     tv2.setText(convert());
                     }
                 break;
                 }                         
                 super.handleMessage(msg);
             }
        };

}




在跑迴圈的副執行緒:
1.new一個Message類別
2.裡面使用.what函式
3.執行Handler這個物件的sendMessage()方法,括弧裡夾雜Message物件變數
new Thread(new Runnable(){
            public void run(){
               
                while(true){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                //使用Handler和Message把資料丟給主UI去後續處理
                if(Playist.this.isFinishing()==true){
                    return;
                    }
                Message m = new Message();                               
                 m.what = ABC;               
                 Playist.this.hr.sendMessage(m);               
                }                       
            }
        }).start();



幾個原則:
1.副執行緒永遠不可能改變主畫面的內容,如:setText主畫面的TextView
2.副執行緒的功能只是做"時間管理",任何計算或迴圈還是得交回主執行緒去處理

anim.xml動畫資源檔

res\anim\anim.xml讓程式的文字字串、文字顯示方塊、文字按鈕...具被動畫功能
步驟:
1.使用標籤設定動畫
2.再使用
(1):設定透明度
(2):設定尺寸縮放
(3):設定變形
(4):設定旋轉

Thursday, June 10, 2010

main.xml裡編碼的意義

 
@+id:自動建立R.id類別的資源號碼

Eclipse裡Android的目錄架構

 
每一個檔案都有它獨特的意義:
res\                  放置所有資源檔
res\drawable   放置圖檔
res\layout        定義視窗佈局
res\values        定義文字顯示字串
res\anim\anim.xml   放置動畫定義檔

arrays.xml        定義文字資料陣列
colors.xml        定義繪圖或文字字串顏色
dimens.xml      定義顯示文字的尺寸

Eclipse的快速鍵

指令 功能 備註
[Alt]+[/] 自動補齊函式 sysout+[Alt]+[/]=System.out.println()
[Ctrl]+[/] 將程式碼變成註解
[Ctrl]+[Shift]+[O] 自動加入類別名稱
[Ctrl]+[1] 函數或變數自動更正
[Ctrl]+[Z] 回復上一動
[Ctrl]+[O] 顯示繼承結構
[Alt]+[?] 參數提示 [Ctrl]+[Shift]+[Space]也可以
[Alt]+[Shift]+[S] 呼叫程式碼常用編輯選單

Tuesday, June 8, 2010

Monday, June 7, 2010

歌曲名稱在模擬器變亂碼

android裡的音樂變亂碼
用千千靜聽將音樂屬性改成UTF-8編碼

讓模擬器模擬出SD卡

讓Android模擬器模擬出sd卡
二種方式,
1.在eclipse裡設定模擬
2.在command裡模擬


1. 在eclipse裡設定模擬
Windows / Android SDK and AVD Manager
按「New...」來新增一個 sdcard 映像檔




Run / Run Configurations




在模擬器中
Settings / SD card & phone storage settings
要先按一下 Mount SD card 把記憶卡映像檔掛進來
然後還要 Format SD card 才能使用此記憶卡


Format 完就會顯示記憶卡容量:512MB


●複製檔案進虛擬sd卡






2.在command裡模擬
(1)創建512M的sd卡
在d:\android\android_sdk\tools\底下執行指令:
mksdcard  sdcard 512M d:/android/sdcard.img  
這樣在d:/android/裡就會有sdcard.img
(2)在eclipse裡做設定


提外話:
我通常喜歡在windows xp[系統]→[環境變數]裡,
在Path後面新增「;D:\Android\android-sdk-windows\tools」
然後重開機,這樣的話我在命令提示字元下就可以無憂無慮的使用接下來要用的pdb、emulator等在tools底下才有的功能


回歸正傳:
在[run as]→[run configurations]→[target(tag)]→視窗往上拉長→在additional emulator command line options裡打上:
-sdcard d:\android\sdcard.img



複製檔案進SD卡
在command line
D:\android\android-sdk-windows\tools\底下
打上adb push c:\1.mp3 /sdcard/1.mp3
其中c:\1.mp3是欲複製之路徑名稱在c槽的1.mp3檔案
/sdcard /1.mp3是指要複製進sdcard目錄裡,檔名取為1.mp3,注意要反斜線

註1:若有照之前先在環境變數設Path,就不用在D:\android\android-sdk-windows\tools\底下才能使用adb指令,而可以任選你要的目錄執行adb
註2:使用以上兩種複製檔案的方法,前提都要先將載入SD卡的模擬器開起來

Sunday, June 6, 2010

安裝 Android source code至Eclipse

    撰寫時間︰2010/06/06 18:51
    更新時間︰2012/06/14 1000
    文章更新次數︰2

    因為Android現在都有將Source Code直接放在Android SDK Manager裡供我們下載,所以之前的安裝方式都不需要再理會了。
    除非你想追Android4.0以前的source code。

    安裝Android 4.0 source code方式如下︰

    1.首先,從Android SDK Manager下載Source code。
    下載Android Source code

    2.然後,在你的專案程式碼中,選擇任何一個Android的物件(如︰Activity),按下Ctrl+滑鼠左鍵(這個動作是告訴電腦你想要看Android的Class: Activity 的Source Code)

    3.此時,你的Eclipse告訴你它找不到Activity類別的Source code
    我找不到Activity的Source code

    4.點擊Attach Source按鈕,電腦要你選擇Source Code的目錄

    5.選擇你Android SDK的安裝目錄
     6.按下確定,Eclipse就會幫你把Android Source Code匯入。
    註︰匯入時間蠻久的,你會以為你的Eclipse當掉了。

    7.完成後,就可以看到Android 4.0.3的Activity Source Code了。
    Android class: Activity的Source code

    Enjoy it!


    =============================
    話說: 我們都會想要在程式碼中,直接按Ctrl直接看原始碼 但是Android source卻發生沒安裝的狀況。 解決辦法: 1.安裝msysGit 2.下載Full Installer版本 3.安裝完後,在出現的畫面打上: $git clone git://android.git.kernel.org/platform/frameworks/base.git 4.下載完後,會看到下載的檔案被放到C:\msysgit\base
    (1)首先,我必須先在android_sdk的安裝目錄:android-sdk-windows\platforms\android-8\底下,先創建一個\sources資料夾。
    (2)要將C:\msysgit\base\core\java\android這個目錄,複製到我android_sdk的安裝目錄:android-sdk-windows\platforms\android-8\sources\底下
     
    7.這個步驟要做哦:[File]→[open File]→打開android-sdk-windows\platforms\android-8\sources\android\app\Activity.java,有沒有看到原始碼了呢?   
    8.eclipse現在按ctrl應該都會出現原始碼了。 註:   1.快速連到git網  2.如果也顯示不出java原始碼,參照這篇

在Eclipse裡安裝Tomcat

1.先將eclipse關閉
2.解壓縮TomcatV6放在想放的位置
3.將tomcatPluginV321.zip解壓縮至eclipse\plugin\目錄底下
4.重開eclipse,此時會發現有3隻小貓的快捷按鈕在工具列中了
5.[Windows][Preferences][Server][Runtime Environment][add]→選擇Apache Tomcat v6.0
6.仍然在[Preferences]視窗,選擇[Tomcat]Tomcat version選擇Version 6.x
Tomcat home也選擇一下剛才在第2步驟解壓縮的目錄→[Apply]
7.最後按上ok,應該可以在eclipse裡方便啟用Tomcat

Saturday, June 5, 2010

Android和伺服器的親密關係

AndroidInternet的連線,
整合了Apache 4模組,
也因此,要寫出和http協定相關程式並非難事。




HttpPostHttpGet都會發出"伺服器請求",跟伺服器要資料

HttpPost類別發出伺服器請求的步驟:
1.先建立HttpPost實體
 HttpPost a = new HttpPost();
這個類別,能夠以三種建構子建立:
(1)new HttpPost();
(2)new HttpPost(URI uri);
(3)new HttpPost(String uri);
我在這裡用第3
HttpPost hr = new HttpPost("http://localhost:8080/request.txt");
2.使用HttpPost.setEntity()發出伺服器請求
(1)setEntity(HttpEntity entity)當中,
HttpEnitity原來是介面,
也就是說如果要使用這個method
我們必須有一個HttpEnitity底下的實作類別的實體產生,
而這個實作類別,我們使用new UrlEncodedFormEntity。
(2)UrlEncodedFormEntity這個類別的建構子,API裡寫到有2種建構子可以使用:
UrlEncodedFormEntity(Listextends NameValuePair> parameters, String encoding)
註:String encoding是編碼設定,如:UTF_8
(3)要命喔,當我們開始要用NameValuePair時,才發現這個NameValuePair又是介面!
我們只能使用實作NameValuePair這個介面的實作類別BasicNameValuePair
→也就是說,若我們要add List時,
我們被規定了,只能add(new BasicNameValuePair());
(4)BasicNameValuePair這個類別的建構子是這樣的:
當我們在new這個類別時,放入的namevalue
就是我們要丟出的伺服器請求訊息了。

3.當我們將setEntity()這個method的內容都產生出實體了,
自然就可以直接用HttpPost.setEntity()送出實體封包給伺服器了。




●使用HttpResponse實體來接收伺服器的回應
1.先建立HttpResponse實體
使用new DefaultHttpClient().execute(httpPost的變數名稱)去接收伺服器回應
HttpResponse hr = new DefaultHttpClient().excute(hp);
2.判斷伺服器狀態,若為ok,才執行我們要做的指令
if(httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK ){
//程式碼區塊
}
上面的判斷式 HttpStatus.SC_OK可以改成 ==200
3.確認伺服器有給出回應了,我們才來處理接收到的封包
所以程式碼區塊裡的資料可能如下:
String s = EntityUtils.toString(hp.getEntity());
最後再看我們要將s怎麼做處理。
看是要顯示出來,還是$^%