Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 中級開發 >> Android線程的交互,以及使用方法(1)

Android線程的交互,以及使用方法(1)

編輯:中級開發

首先原諒我把文章的標題寫的這麼長。其實我還嫌棄它短了因為 寫不下去了所以我就不寫了。因為我實在不知道該怎麼定義這篇文章的標題或許應該叫 “亂談”比較合適。 這樣可能還體現了 大道至簡的 精髓 呵呵。

    希望和我一樣正在學習android的新手可以通過這篇文章熟悉android線程的交互,以及使用方法。以便將來更好的在自己的程序中運用。也希望大家保持學習android的積極性,一起努力、交流、成長,因為文章比較長 大家可以分幾次閱讀。這篇文章包含了好幾個例子,我之所把它們寫在一起,是覺得它們有一定聯系。 
    
  好吧我們開始讓 我們先從android進程說起吧。

   當一個程序第一次啟動的時候,Android會啟動一個LINUX進程和一個主線程。默認的情況下,所有該程序的組件都將在該進程和線程中運行。同時,Android會為每個應用程序分配一個單獨的Linux用戶。Android會勁量保留一個正在運行進程,只在內存資源出現不足時,Android會參試停止一些進程從而釋放足夠的資源給其他新的進程使用, 也能保證用戶正在訪問的當前進程有足夠的資源去及時的響應用戶的事件。Android會 根據進程中運行的組件類別以及組件的狀態來判斷該進程的重要性,android會 首先停止那些不重要的進程。按照重要性從高到低一共有五個級別:

l  前台進程

前台進程是用戶當前正在使用的進程。只有一些前台進程可以在任何時候都存在。他們是最後一個被結束的,當內存低到根本連他們都不能運行的時候。一般來說, 在這種情況下,設備會進行內存調度,中止一些前台進程來保持對用戶交互的響應。

l  可見進程

可見進程不包含前台的組件但是會在屏幕上顯示一個可見的進程是的重要程度很高,除非前台進程需要獲取它的資源,不然不會被中止。

l  服務進程

運行著一個通過startService() 方法啟動的service,這個service不屬於上面提到的2種更高重要性的。service所在的進程雖然對用戶不是直接可見的,但是他們執行了用戶非常關注的任務(比如播放mp3,從網絡下載數據)。只要前台進程和可見進程有足夠的內存,系統不會 回收他們。

l  後台進程

運行著一個對用戶不可見的activity(調用過 onStop() 方法).這些進程對用戶體驗沒有直接的影響,可以在服務進程、可見進程、前台進 程需要內存的時候回收。通常,系統中會有很多不可見進程在運行,他們被保存在LRU (least recently used) 列表中,以便內存不足的時候被第一時間回收。如果一個activity正 確的執行了它的生命周期,關閉這個進程對於用戶體驗沒有太大的影響。

l  空進程

未運行任何程序組件。運行這些進程的唯一原因是作為一個緩存,縮短下次程序需要重新使用的啟動時間。系統經常中止這些進程,這樣可以調節程序緩存和系統緩 存的平衡。

android 對進程的重要性評級的時候,選取它最高的級別。另外,當被另外的一個進程依賴的時候,某個進程的級別可能會增高。一個為其他進程服務的進程永遠不會比被服 務的進程重要級低。因為服務進程比後台activity進程重 要級高,因此一個要進行耗時工作的activity最好啟動一 個service來做這個工作,而不是開啟一個子進程――特別 是這個操作需要的時間比activity存在的時間還要長的時 候。例如,在後台播放音樂,向網上上傳攝像頭拍到的圖片,使用service可 以使進程最少獲取到“服務進程”級別的重要級,而不用考慮activity目 前是什麼狀態。broadcast receivers做費時的工作的時候,也應該啟用一個服務而不是開一個線程。

2單線程模型 
    當一個程序第一次啟動時,Android會同時啟動一個對應的 主線程(Main Thread),主線程主要負責處理與UI相關的事件,如:用戶的按鍵事件,用戶接觸屏幕的事件以及屏幕繪圖事 件,並把相關的事件分發到對應的組件進行處理。所以主線程通常又被叫做UI線 程。在開發Android應用時必須遵守單線程模型的原則: android UI操作並不是線程安全的並且這些操作必須在UI線程中執行。

    單線程模型會在沒有考慮到它的影響的情況下引起android應用程序性能低下,因為 所有的任務都在同一個線程中執行,如果執行一些耗時的操作,如訪問網絡或查詢數據庫,會阻塞整個用戶界面。當在執行一些耗時的操作的時候,不能及時地分發 事件,包括用戶界面重繪事件。從用戶的角度來看,應用程序看上去像掛掉了。更糟糕的是,如果阻塞應用程序的時間過長(5秒鐘)android會向用戶提示一些信息,即打開一個“應用程序沒有相應(application not responding)”ANR 的對話框。

   其實單線程模型就是默認情況下android把所有操作都放在主線程也就是UI Thread線程中來執行 如果你想 O上邊那段不是說它會阻塞用戶界面嘛  那我可以另起一個線程來執行一些操作 沒錯你的想法非常good 。很給力。那麼接下來 你就會嘗試另起一個線程來 執行一些操作。OK 結果就有兩種可能 一:你在另外開啟的那個線程中執行了一些後台的操作 比如開啟一個服務啊。神馬的。那麼恭喜你 你成功了。 二:第二種可能結果就是 你會收到一個華麗的異常 。這個例子很簡單

下面我們就通過一個小例子來說明這個華麗的異常時怎麼回事? 因為本篇文章的例子比較多所以我為了大家好找 給例子起了名稱 這個例子的名稱是: 異常測試 
布局文件 
<?XML version="1.0" encoding="utf-8"?> 
<RelativeLayout 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/textvIEw01" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello" 
    /> 
<Button 
android:id="@+id/myButton" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:layout_below="@id/textvIEw01" 
android:text="異常測試" 
/> 
<TextVIEw 
android:id="@+id/myTextVIEw" 
android:textSize="15pt" 
android:layout_toRightOf="@id/myButton" 
android:layout_alignTop="@id/myButton" 
android:textColor="#FF0000" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content"/>

</RelativeLayout>

Activity01 類

Java代碼 
1.package xiaohang.zhimeng;   
2.  
3.import android.app.Activity;   
4.import android.os.Bundle;   
5.import android.view.VIEw;   
6.import android.view.VIEw.OnClickListener;   
7.import android.widget.Button;   
8.import android.widget.TextVIEw;   
9.  
10.public class Activity01 extends Activity {   
11.    private Button myButton;   
12.    private TextView myTextVIEw;   
13.  
14.    @Override  
15.    protected void onCreate(Bundle savedInstanceState) {   
16.        super.onCreate(savedInstanceState);   
17.        setContentVIEw(R.layout.main);   
18.        myButton = (Button) findVIEwById(R.id.myButton);   
19.        myTextView = (TextView) findViewById(R.id.myTextVIEw);   
20.        myButton.setOnClickListener(new MyButtonListener());   
21.    }   
22.  
23.    class MyButtonListener implements OnClickListener {  
24.        @Override  
25.        public void onClick(VIEw v) {   
26.            new Thread() {   
27.                @Override  
28.                public void run() {   
29.                    // 我們在這裡更新了UI 設置了TextVIEw的值   
30.                    myTextVIEw.setText("張三");   
31.                }   
32.            }.start();   
33.        }   
34.    }   
35.}  
package xiaohang.zhimeng;

import android.app.Activity;
import android.os.Bundle;
import android.view.VIEw;
import android.view.VIEw.OnClickListener;
import android.widget.Button;
import android.widget.TextVIEw;

public class Activity01 extends Activity {
 private Button myButton;
 private TextView myTextVIEw;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentVIEw(R.layout.main);
  myButton = (Button) findVIEwById(R.id.myButton);
  myTextView = (TextView) findViewById(R.id.myTextVIEw);
  myButton.setOnClickListener(new MyButtonListener());
 }

 class MyButtonListener implements OnClickListener {
  @Override
  public void onClick(VIEw v) {
   new Thread() {
    @Override
    public void run() {
     // 我們在這裡更新了UI 設置了TextVIEw的值
     myTextVIEw.setText("張三");
    }
   }.start();
  }
 }
}


接下來我們以看圖片的方式 看看這是怎樣的一個異常。請大家點擊圖片查看大圖


 


android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. 就是這樣一個異常 這個異常告訴我們不可以再子線程中更新UI元素 比如我們上邊那個例子設置了一個TextVIEw的值。所有與UI相關的操作都不可以在子線程中執行都必須在UI線程中執行。這個異常大家以後可能會經常遇到多加注意就是了。 
   
    我們繼續,下面我們說說線程交互方面的東西。就比如我們想做點這些事情上邊不是說了不能在子線程中更新UI 那比如我想在子線程中定義 一個字符串 然後通過發消息的方式 Message 把這個字符串 發送給主線程也就是UI線程 讓UI線程來 設置這個TextVIEw的值為我們剛剛在子線程中定義的字符串。 或者我想在子線程中開啟音樂服務,或者把它停止該怎麼做呢?  要知道怎麼做先讓我們了解 一下這幾個對象吧!它們分別是

MessageQueue        Handler             Looper   下面對它們進行詳細說明


Message Queue

    在單線程模型下,為 了解決類似的問題,android設 計了一個Message Queue(消息隊列), 線程間可以通過該Message Queue並結合Handler和Looper組 件進行信息交換。 
l  Message Queue

     Message Queue是一個消息隊列,用來存放通過Handler發 布的消息。消息隊列通常附屬於某一個創建它的線程,可以通過Looper.myQueue()得 到當前線程的消息隊列。如果沒有消息隊列對象則會拋出空指針異常 。android在 第一次啟動程序時會默認會為UI thread創建一個關聯的消息隊列,用來管理程序的一些上層組件,activitIEs,broadcast receivers 等等。你可以在自己的子線程中創建Handler與UI thread通訊。也就是說我們程序一啟動我們的UI線程也就是主線程就會有一個消息隊列 ,而如果我們自己另外開啟的一個子線程就不會有MessageQueue(消息隊列)對象。這一點大家務必知道。

l  Handler

    通過Handler你 可以發布或者處理一個消息或者是一個Runnable的 實例。每個Handler都 會與唯一的一個線程以及該線程的消息隊列關聯。當你創建一個新的Handler時候,默認情況下,它將關聯到創建它的這個線程和該線程的消息隊列。也就是說,如果你通過Handler發 布消息的話,消息將只會發送到與它關聯的這個消息隊列,當然也只能處理該消息隊列中的消息。這裡大家就得理解一下了 也就是說我們 一個Handler對應一個線程以及附屬於該線程的消息隊列。就比如 我們現在有一個Handler對象這個Handler在UI線程中創建 叫xh_Handler 那麼我們根據上邊的說明 應該可以告訴我 這個xh_Handler是和那個線程關聯的?  如果我用這個Handler發消息的話它將發給那個線程的消息隊列? 如果你知道了 我想一般情況下你肯定是知道的。說明你很懂。我們繼續。這時我們用這個Handler對象發送消息 
Handler對象也可以發送消息哦,它有發送消息的方法。下面就說到了 待會大家看示例程序也會發現 主要就是看它怎麼使用。

Handler的主要的方法有:

1)   public final boolean sendMessage(Message msg)

把消息放入該Handler所 關聯的消息隊列,放置在消息隊列尾部。 
這裡請允許我多說一句就是 我們把消息放進去的一端 消息不會阻塞但是處理消息的一端就有可能會阻塞。歡迎收看 看圖頻道。 
 

2)   public void handleMessage(Message msg)

    關聯該消息隊列的線 程將通過調用Handler的handleMessage方 法來接收和處理消息,通常需要子類化Handler來 實現handleMessage。

l  Looper

Looper扮演著一個Handler和 消息隊列之間通訊橋梁的角色。程序組件首先通過Handler把 消息傳遞給Looper,Looper把 消息放入隊列。Looper也 把消息隊列裡的消息廣播給所有的Handler,Handler接 受到消息後調用handleMessage進 行處理。

1)   可以通過Looper類 的靜態方法Looper.myLooper得 到當前線程的Looper實 例,如果當前線程未關聯一個Looper實 例,該方法將返回空(null)它不戶拋空指針。

2)   可以通過靜態方法Looper. getMainLooper方法得到主線程的Looper實 例 這裡需要注意一下 主線程默認是有Lo是oper對象的。但是我們自己定義的子線程沒有的。那麼我們怎麼在子線程中得到Looper對象呢?如果一個線程中調用Looper.prepare(),那麼系統就會自動的為該線程建立一個消息隊列,然後調用 Looper.loop();之後就進入了消息循環,這個之後就可以發消息、取消息、和處理消息。這個如何發送消息和如何處理消息可以再其他的線程中通過 Handle來做,但前提是我們的Hanle知道這個子線程的Looper,但是你如果不是在子線程運行 Looper.myLooper(),一般是得不到子線程的looper的。

好了示例演示時間到了。示例名稱:線程交互

  這個例子主要向大家說明線程之間是如何進行交互的。請大家靜下心來好好看看。如果你也是android新手的話。先說一下我們具體要實現什麼功能,一共有三個按鈕 第一個按鈕用來設置一個 TextView上顯示的值。當我們第一次點擊它的時候它就會把值顯示在TextView當我們在一點一下 就會把這個值清空。 什麼也不顯示了。這個按鈕的 的背景圖片我做了點處理。就是默認情況下這個按鈕一張圖片,按下按鈕又會換成另外一張圖片,松開按鈕又會換一張圖片。這是怎麼做到的說完這個例子會給大家解釋。至於線程之間是怎麼傳遞消息的 大家就看代碼吧。 另外2個按鈕時用來 開啟和關閉音樂服務的 ,注意當我們點擊開始按鈕的時候 就會開始播放音樂 並且把歌曲的名稱顯示在一個TextVIEw上。當我們點擊關閉按鈕的時候就會停止音樂的播放,好了廢話不多說了大家看代碼吧。 
  O 對了 差點忘記了我們應該先收看 看圖頻道之運行效果。


 
 
 


  好了下邊我們來看布局文件 一共有2個布局文件 一個是用來定義我們的布局我這裡用的是相對布局 RelativeLayout 下邊是main.XML

<?XML version="1.0" encoding="utf-8"?> 
<RelativeLayout XMLns:android="http://schemas.android.com/apk/res/android" 
    android:orIEntation="vertical" 
    android:layout_width="fill_parent" 
    android:background="@drawable/bg0" 
    android:layout_height="fill_parent"> 
<TextVIEw 
android:id="@+id/textvIEw01" 
android:textColor="#FF0000" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello" 
    /> 
<Button 
android:id="@+id/myButton" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:layout_below="@id/textvIEw01" 
android:background="@drawable/newbtn" 
/> 
<TextVIEw 
android:id="@+id/myTextVIEw" 
android:textSize="15pt" 
android:layout_toRightOf="@id/myButton" 
android:layout_alignTop="@id/myButton" 
android:textColor="#FF0000" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content"/>

<Button 
android:id="@+id/myButton01" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:layout_below="@id/myButton" 
android:text="開始" 
/> 
<Button 
android:id="@+id/myButton02" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:layout_toRightOf="@id/myButton01" 
android:layout_marginLeft="10px" 
android:layout_alignTop="@id/myButton01" 
android:text="停止" 
/> 
<TextVIEw 
android:id="@+id/textvIEw2" 
android:textSize="15pt" 
android:layout_below="@id/myTextVIEw" 
android:layout_toRightOf="@id/myButton02" 
android:layout_alignTop="@id/myButton02" 
android:textColor="#385E0F" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content"/> 
</RelativeLayout>

    那麼另外一個xml文件就是用來定義程序的第一個按鈕的圖片轉換效果。這個怎麼實現等這個例子講解完了,會給大家做一個簡單的說明。這個文件的名字是 newbtn.XML

<?XML version="1.0" encoding="utf-8"?> 
<selector XMLns:android="http://schemas.android.com/apk/res/android"> 
<item android:state_pressed="true" 
android:drawable="@drawable/im1"/> 
<item android:state_focused="true" 
android:drawable="@drawable/im2"/> 
<item android:drawable="@drawable/im3"/> 
</selector>

   下面就是這2個類了 先來看看我們的音樂服務類 MusicService這個類比較簡單。

Java代碼 
1.package xiaohang.zhimeng;   
2.  
3.import android.app.Service;   
4.import android.content.Intent;   
5.import android.media.MediaPlayer;   
6.import android.os.IBinder;   
7.  
8.public class MusicService extends Service{   
9.       
10.    //MediaPlayer對象   
11.    private MediaPlayer player;   
12.       
13.    @Override  
14.    public IBinder onBind(Intent intent) {   
15.        // TODO Auto-generated method stub   
16.        return null;   
17.    }   
18.       
19.    public void onStart(Intent intent, int startId){   
20.        super.onStart(intent, startId);   
21.        //這裡可以理解為裝載音樂文件   
22.        player = MediaPlayer.create(this, R.raw.test);   
23.        //開始播放   
24.        player.start();   
25.    }   
26.       
27.    public void onDestroy(){   
28.        super.onDestroy();   
29.        //停止音樂-停止Service   
30.        player.stop();   
31.    }   
32.}  
package xiaohang.zhimeng;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;

public class MusicService extends Service{
 
 //MediaPlayer對象
 private MediaPlayer player;
 
 @Override
 public IBinder onBind(Intent intent) {
  // TODO Auto-generated method stub
  return null;
 }
 
 public void onStart(Intent intent, int startId){
  super.onStart(intent, startId);
  //這裡可以理解為裝載音樂文件
  player = MediaPlayer.create(this, R.raw.test);
  //開始播放
  player.start();
 }
 
 public void onDestroy(){
  super.onDestroy();
  //停止音樂-停止Service
  player.stop();
 }
}


  在來看我們實現線程交互的這個Activity02類 看看它是怎麼完成 子線程與UI線程的交互的

Java代碼 
1.package xiaohang.zhimeng;   
2.  
3.import android.app.Activity;   
4.import android.content.Intent;   
5.import android.os.Bundle;   
6.import android.os.Handler;   
7.import android.os.Looper;   
8.import android.os.Message;   
9.import android.view.VIEw;   
10.import android.view.VIEw.OnClickListener;   
11.import android.widget.Button;   
12.import android.widget.TextVIEw;   
13.  
14.public class Activity02 extends Activity {   
15.    private Button myButton;//這個按鈕就是我們的第一個按鈕就是實現了圖片變換的那個按鈕   
16.    private Button myButton01;//這個按鈕是用來開啟音樂服務的   
17.    private Button myButton02;//這個按鈕用來停止音樂服務   
18.    //myTextView 由myButton控制這個TextVIEw用來顯示"android小子"  textView由myButton01控制這個TextVIEw用來顯示音樂名稱   
19.    private TextView myTextView, textVIEw;   
20.       
21.    // 得到主線程的Looper對象   
22.    Looper looper = Looper.myLooper();   
23.    // 這個myHandler由主線程創建所以它與主線程關聯   
24.    MyHandler myHandler = new MyHandler(looper);   
25.  
26.    @Override  
27.    protected void onCreate(Bundle savedInstanceState) {   
28.        super.onCreate(savedInstanceState);   
29.        //設置我們的布局文件   
30.        setContentVIEw(R.layout.main);   
31.        //得到我們的Button 按鈕對象 和 TextVIEw對象   
32.        myButton02 = (Button) findVIEwById(R.id.myButton02);   
33.  
34.        myButton = (Button) findVIEwById(R.id.myButton);   
35.        myTextView = (TextView) findViewById(R.id.myTextVIEw);   
36.  
37.        myButton01 = (Button) findVIEwById(R.id.myButton01);   
38.        textView = (TextView) findViewById(R.id.textvIEw2);   
39.  
40.        myButton.setOnClickListener(new MyButtonListener());   
41.        myButton02.setOnClickListener(new MyButton02Listener());   
42.        //給我們的myButton按鈕設置監聽器   
43.        myButton01.setOnClickListener(new Button.OnClickListener() {   
44.            @Override  
45.            public void onClick(VIEw v) {   
46.                new Thread() {   
47.                    @Override  
48.                    public void run() {   
49.                        System.out.println("the thread id is "  
50.                                + Thread.currentThread().getId());   
51.                        System.out.println("the thread name is"  
52.                                + Thread.currentThread().getName());   
53.                        //獲取我們資源文件裡邊的音樂名稱 因為連路徑也獲取了 所以這裡截取了一下   
54.                        String tmusicName = getResources().getString(   
55.                                R.raw.music_name);   
56.                        int b = tmusicName.lastIndexOf("/");   
57.                        int e = tmusicName.lastIndexOf(".");   
58.                        String musicName = tmusicName.substring(b + 1, e);   
59.                        // String musicName =   
60.                        // getResources().getResourceName(R.raw.test);   
61.                        /** 定義消息對象 並且賦予內容 最後發送給UI線程  
62.                          *這裡這個方法要說明一下 myHandler.obtainMessage()-->obtainMessage這個方法用來獲得消息對象  
63.                          *但是這個消息對象會關聯調用它的Handler對象。所以就會關聯myHandler對象 而這個myHandler對象是在UI線程裡邊創建的  
64.                          * 所以很顯然我們這消息會發給主線程的消息隊列 我想這對大家來說根本沒有任何難度  
65.                          */  
66.                        Message message = myHandler.obtainMessage();   
67.                        message.obj = musicName;   
68.                        //這裡這個 arg1 是Message對象攜帶的參數我主要用它來區分消息對象(Message)   
69.                        message.arg1 = 2;   
70.                        //把消息發送給目標對象,目標對象就是 myHandler 就是關聯我們得到的那個消息對象的Handler   
71.                        message.sendToTarget();   
72.                        //開啟音樂服務   
73.                        startService(new Intent(   
74.                                "xiaohang.zhimeng.android.MUSIC"));   
75.                    }   
76.                    //啟動線程   
77.                }.start();   
78.            }   
79.        });   
80.    }   
81.  
82.    // myButton02按鈕的監聽器   
83.    class MyButton02Listener implements OnClickListener {   
84.        @Override  
85.        public void onClick(VIEw v) {   
86.            new Thread() {   
87.                @Override  
88.                public void run() {   
89.                    System.out.println("this thread id is "  
90.                            + Thread.currentThread().getId());   
91.                    System.out.println("this thread name is "  
92.                            + Thread.currentThread().getName());   
93.                    // 停止Service   
94.                    stopService(new Intent("xiaohang.zhimeng.android.MUSIC"));   
95.                }   
96.            }.start();   
97.        }   
98.    }   
99.  
100.    // myButton監聽器 這個按鈕用來設置 myTextVIEw 的值 顯示 或 隱藏 有2種狀態   
101.    class MyButtonListener implements OnClickListener {   
102.        @Override  
103.        public void onClick(VIEw v) {   
104.            CharSequence test_View = myTextVIEw.getText();   
105.            String str = test_VIEw.toString();   
106.            // 當myTextVIEw上邊顯示的文本不等於空的時候   
107.            if (!(str.trim().equals(""))) {   
108.                String str1 = "";   
109.                CharSequence charsq = str1;   
110.                myTextVIEw.setText(charsq);   
111.            } else {   
112.                Runnable r = new Runnable() {   
113.                    public void run() {   
114.                        Message message = myHandler.obtainMessage();   
115.                        message.arg1 = 1;   
116.                        message.obj = "android小子";   
117.                        message.sendToTarget();   
118.                        System.out.println("name is "  
119.                                + Thread.currentThread().getName());   
120.                        System.out.println("id is "  
121.                                + Thread.currentThread().getId());   
122.                    }   
123.                };   
124.                Thread thread = new Thread(r);   
125.                thread.start();   
126.            }   
127.        }   
128.    }   
129.    //MyHandler繼承Handler類 用過覆寫handlerMessage方法 來處理發給附屬於UI線程的消息隊列的消息   
130.    class MyHandler extends Handler {   
131.        public MyHandler() {}   
132.        public MyHandler(Looper looper) {   
133.            super(looper);   
134.        }   
135.        @Override  
136.        public void handleMessage(Message msg) {   
137.            if (msg.arg1 == 1) {   
138.                CharSequence xh_msg = (CharSequence) msg.obj;   
139.                myTextVIEw.setText(xh_msg);   
140.            } else if (msg.arg1 == 2) {   
141.                CharSequence xh2_msg = (CharSequence) msg.obj;   
142.                textVIEw.setText(xh2_msg);   
143.            }   
144.        }   
145.    }   
146.}  
package xiaohang.zhimeng;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.VIEw;
import android.view.VIEw.OnClickListener;
import android.widget.Button;
import android.widget.TextVIEw;

public class Activity02 extends Activity {
 private Button myButton;//這個按鈕就是我們的第一個按鈕就是實現了圖片變換的那個按鈕
 private Button myButton01;//這個按鈕是用來開啟音樂服務的
 private Button myButton02;//這個按鈕用來停止音樂服務
 //myTextView 由myButton控制這個TextVIEw用來顯示"android小子"  textView由myButton01控制這個TextVIEw用來顯示音樂名稱
 private TextView myTextView, textVIEw;
 
 // 得到主線程的Looper對象
 Looper looper = Looper.myLooper();
 // 這個myHandler由主線程創建所以它與主線程關聯
 MyHandler myHandler = new MyHandler(looper);

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  //設置我們的布局文件
  setContentVIEw(R.layout.main);
  //得到我們的Button 按鈕對象 和 TextVIEw對象
  myButton02 = (Button) findVIEwById(R.id.myButton02);

  myButton = (Button) findVIEwById(R.id.myButton);
  myTextView = (TextView) findViewById(R.id.myTextVIEw);

  myButton01 = (Button) findVIEwById(R.id.myButton01);
  textView = (TextView) findViewById(R.id.textvIEw2);

  myButton.setOnClickListener(new MyButtonListener());
  myButton02.setOnClickListener(new MyButton02Listener());
  //給我們的myButton按鈕設置監聽器
  myButton01.setOnClickListener(new Button.OnClickListener() {
   @Override
   public void onClick(VIEw v) {
    new Thread() {
     @Override
     public void run() {
      System.out.println("the thread id is "
        + Thread.currentThread().getId());
      System.out.println("the thread name is"
        + Thread.currentThread().getName());
      //獲取我們資源文件裡邊的音樂名稱 因為連路徑也獲取了 所以這裡截取了一下
      String tmusicName = getResources().getString(
        R.raw.music_name);
      int b = tmusicName.lastIndexOf("/");
      int e = tmusicName.lastIndexOf(".");
      String musicName = tmusicName.substring(b + 1, e);
      // String musicName =
      // getResources().getResourceName(R.raw.test);
         /** 定義消息對象 並且賦予內容 最後發送給UI線程
        *這裡這個方法要說明一下 myHandler.obtainMessage()-->obtainMessage這個方法用來獲得消息對象
        *但是這個消息對象會關聯調用它的Handler對象。所以就會關聯myHandler對象 而這個myHandler對象是在UI線程裡邊創建的
        * 所以很顯然我們這消息會發給主線程的消息隊列 我想這對大家來說根本沒有任何難度
        */
      Message message = myHandler.obtainMessage();
      message.obj = musicName;
      //這裡這個 arg1 是Message對象攜帶的參數我主要用它來區分消息對象(Message)
      message.arg1 = 2;
      //把消息發送給目標對象,目標對象就是 myHandler 就是關聯我們得到的那個消息對象的Handler
      message.sendToTarget();
      //開啟音樂服務
      startService(new Intent(
        "xiaohang.zhimeng.android.MUSIC"));
     }
     //啟動線程
    }.start();
   }
  });
 }

 // myButton02按鈕的監聽器
 class MyButton02Listener implements OnClickListener {
  @Override
  public void onClick(VIEw v) {
   new Thread() {
    @Override
    public void run() {
     System.out.println("this thread id is "
       + Thread.currentThread().getId());
     System.out.println("this thread name is "
       + Thread.currentThread().getName());
     // 停止Service
     stopService(new Intent("xiaohang.zhimeng.android.MUSIC"));
    }
   }.start();
  }
 }

 // myButton監聽器 這個按鈕用來設置 myTextVIEw 的值 顯示 或 隱藏 有2種狀態
 class MyButtonListener implements OnClickListener {
  @Override
  public void onClick(VIEw v) {
   CharSequence test_View = myTextVIEw.getText();
   String str = test_VIEw.toString();
   // 當myTextVIEw上邊顯示的文本不等於空的時候
   if (!(str.trim().equals(""))) {
    String str1 = "";
    CharSequence charsq = str1;
    myTextVIEw.setText(charsq);
   } else {
    Runnable r = new Runnable() {
     public void run() {
      Message message = myHandler.obtainMessage();
      message.arg1 = 1;
      message.obj = "android小子";
      message.sendToTarget();
      System.out.println("name is "
        + Thread.currentThread().getName());
      System.out.println("id is "
        + Thread.currentThread().getId());
     }
    };
    Thread thread = new Thread(r);
    thread.start();
   }
  }
 }
 //MyHandler繼承Handler類 用過覆寫handlerMessage方法 來處理發給附屬於UI線程的消息隊列的消息
 class MyHandler extends Handler {
  public MyHandler() {}
  public MyHandler(Looper looper) {
   super(looper);
  }
  @Override
  public void handleMessage(Message msg) {
   if (msg.arg1 == 1) {
    CharSequence xh_msg = (CharSequence) msg.obj;
    myTextVIEw.setText(xh_msg);
   } else if (msg.arg1 == 2) {
    CharSequence xh2_msg = (CharSequence) msg.obj;
    textVIEw.setText(xh2_msg);
   }
  }
 }
}

  例子的運行效果大家就下載源碼自行測試吧。


本文來自CSDN博客,轉載請標明出處:http://blog.csdn.Net/xqhrs232/archive/2010/12/24/6095684.ASPx

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved