其實市面上與網路上已經有很多詳解了
但若不是自己親自實作run一次的話,應該還是會很不清楚如何使用
有關thread handler runnable之間的關係,其實可以參考清新下午茶

不過若是初學者看完應該還是不知道在說什麼
但是其實我本身也沒有比這更詳細的說明方法,所以想要詳細解釋還是看清新下午茶會比較清楚
那今天主要還是就一些thread相關的基本限制做一些說明

《Thread-執行緒》

首先,有修過作業系統的應該知道Thread究竟是什麼,應該也知道哲學家用餐問題(Dining Philosophers)
不過沒修過沒學過的應該就不清楚,簡單來說,Thread就像是一條十字路口
只有一條路有車時,就算紅燈也沒關係(現實還是會罰錢......這是舉例),但十字路口都有車要經過時,就需要紅綠燈的配置了

此時,會行駛的只有顯示綠燈的直行車可以通過,而這就是一條Thread
另外一條路的車因為紅燈而停下,必須等自己的燈號轉變才能動
這條十字路口就是一個Thread,隨著紅綠燈的轉變而調整兩條路的動態

在程式裡,這個十字路口就是很單純的一個work flow、程序,必須按照順序才能依次往下執行,Step by step
然後,如果車子一多,塞車了,程式塞住了,我們就得要有其他道路來舒緩車流,這就是Multi-Thread,多執行緒的概念
我想我還是說的很簡略,若是對執行緒的概念有其他問題歡迎發問~

那,下面開始說明Thread在Android裡扮演的角色了

《Android Thread》

Android與iOS都有其 main thread 與 back thread,而 main thread 又稱 UI thread
顧名思義,UI thread(main thread)就是用來處理各種 UI 的控制
而另一個,back thread主要是用來進行資料的控制,包含使用 Internet Connect

UI thread(main thread)僅有一條,但 back thread 可以開許多條
只是 UI thread 有一些限制,只有在 UI thread 裡可進行 UI 的控制,不可於其他新增(new 出來)的 thread進行
相對的,關於網路的連接,不管是使用 http protocol 還是其他 socket protocol,都不能在 UI thread(main thread)進行

故如何 handle UI thread(main thread) 與 back thread,是 Android 與 iOS Developer需要熟練的課題
這是無法避免的宿命!(遠通發言人調)
一個好的 Developer 必須熟知 Thread 的重要性,如果無法熟練,就......再多練練!

以下是我無聊玩animation時順便作出的程式碼

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initView();
    final Animation am = new AlphaAnimation((float) 1, 0);
    am.setDuration(3000);
    am.setRepeatCount(5);
    titleIcon.setAnimation(am);
    new Thread(new Runnable() {
        
        @Override
        public void run() {
            am.startNow();
            handle.post(mRefresh);             
        }
    }).start();
}

am 是 Animation 的物件,有使用到 am 的都是 Animation 相關的控制
不過今天是談Thread 與 Handler 還有 Runnable,所以關於 Animation 就暫時跳過
我們可以看到,上面我直接 new 了一個 Thread 的物件,意思是我開了一個 back thread,而 Thread 物件裡也 new 一個 Runnable的物件(這個部分其實可以額外宣告一個Runnable的物件,然後進行呼叫)

然後我們就在 Runnable 物件裡執行這條 back thread 需要做的事情

        public void run() {
            am.startNow();
            handle.post(mRefresh);             
        }

關於這段程式碼,am依然是 Animation 相關的執行,這邊我們還是跳過
handler是為了掌握我們應該在哪條 thread 進行工作而設置出來的管理者
而這段程式碼是為了呼叫 main thread,也就是 UI thread 裡的 名稱為 mRefresh 的 Runnable 物件而設置

private void refresh() {
    titleIcon.setVisibility(View.GONE);
}

private Runnable mRefresh = new Runnable() {
    
    @Override
    public void run() {
        refresh();
    }
};

這兩個 function,第一個是在 UI thread(main thread)裡進行的更新函式:圖片的隱藏與空間釋放
第二個宣告為 Runnable 物件的 mRefresh,則是要執行的工作:執行第一個 function
我們使用 handler 將執行的程序從 back thread 跳回 UI thread(main thread),並進行 UI 的更新

不然如果持續在 back thread 執行 UI 更新的話,會跳出 Exception,程式會 crash
所以我們通常會在 back thread 進行資料的交換、計算、收發
當我們得到資料或需要 callback 時,就利用 handler 進行其他 thread 任務的呼叫

《Android Handler》-20140218補充-

千萬記得要存檔......
上面那句話是因為......我打完後直接很順手的滑了上一頁......然後就......悲劇了......
以下重新打......

關於這次 Handler 的補充,是因為有人提醒我說 code 裡面沒有 new Handler(),必須在 onCreate()裡面給值
不過,其實我是設置成 global,並在宣告時就 new Handler() 了
當然沒有詳細敘述這部分,造成誤會很抱歉Orz

所以既然都打了,就把 Handler 詳細敘述一下好了

Handler 顧名思義,他是一個管理者、控制者,專門控制 thread (執行緒)與 runnable (賦予之工作)
舉個例子,我們正在高鐵這條由南至北的 thread 上,突然,車長・Handler 突然出現要我們立刻轉換到台鐵的 thread 上
現實雖然是不可能執行,但是在android中,這個動作會強制執行,而這就是 Handler 所扮演之角色

(例子舉得很詭異......)

所以如果我們要實作 multi-thread,就必須熟練應用 Handler 這轉換 thread 的工具
以下放上程式碼,不過以後大概還是會斟酌考量完整的 code ,雖然可供作參考,但只看沒實際練習,一樣不會有長進
所以之後還是只會將片段重點程式碼放上,其他 new 一個物件的小程式碼可能就會被我忽略掉了

這就是我常常忽略 PM (Handler)的原因(咦?)

public class MainActivity extends Activity {
    
    Handler     handle = new Handler();
    ImageView   titleIcon;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        final Animation am = new AlphaAnimation((float) 1, 0);
        am.setDuration(3000);
        am.setRepeatCount(5);
        titleIcon.setAnimation(am);
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                am.startNow();
                handle.post(mRefresh);             
            }
        }).start();
    }
    
    private void initView() {
        titleIcon = (ImageView) findViewById(R.id.imageView_ResumeTitle);
    }
    
    private void refresh() {
        titleIcon.setVisibility(View.GONE);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
    
    private Runnable mRefresh = new Runnable() {
        
        @Override
        public void run() {
            refresh();
        }
    };
    
}


-20140218補充-

這裡所說的是 handler 最簡單最基本的用法,用熟了就可以利用這個進行 multi-thread 的實作
這好像是我第一篇技術文,拿我曾經非常不熟的 thread 來開刀
若是說明有錯與不完善之處,請不吝提出,若是初學者有看不懂的地方也歡迎提問!

下一篇會寫仿 iOS 的 Delegate(預告)

謝謝收看~

另外目前每個月於最後一週六在臺北會舉辦 Android Developer 開發者讀書會
說是讀書會,但主要還是以實作討論分享為主。

然後我個人於每個月月中在桃園楊梅有開設免費的 Android 程式設計教學,歡迎初學程式或有興趣者來聆聽
雖然有人數限制,不過目前參加人數很少還不用太擔心~但不會超出10人,因為必須確保品質

以上。

Comments

comments powered by Disqus