android經過兩種方法開啓一個線程

        android經過兩種方法開啓一個線程java

你們都知道,在PC上的應用程序當須要進行一些複雜的數據操做,但不須要界面UI的時候,咱們會爲應用程序專門寫一個線程去執行這些複雜的數據操做。經過線程,能夠執行例如:數據處理、數據下載等比較耗時的操做,同時對用戶的界面不會產生影響。在Android應用程序開發中,一樣會遇到這樣的問題。當咱們須要訪問網絡,從網上下載數據並顯示在咱們的UI上時,就會啓動後臺線程去下載數據,下載線程執行完成後將結果返回給主用戶界面線程。android

對於線程的控制,咱們將介紹一個Handler類,使用該類能夠對運行在不一樣線程中的多個任務進行排隊,並使用MessageRunnable對象安排這些任務。在javadoc中,對Handler是這樣解釋的:Handler能夠發送和處理消息對象或Runnable對象,這些消息對象和Runnable對象與一個線程相關聯。每一個Handler的實例都關聯了一個線程和線程的消息隊列。當建立了一個Handler對象時,一個線程或消息隊列同時也被建立,該Handler對象將發送和處理這些消息或Runnable對象。網絡

下面有幾種對Handler對象的構造方法須要瞭解一下:ide

a、若是new一個無參構造函數的Handler對象,那麼這個Handler將自動與當前運行線程相關聯,也就是說這個Handler將與當前運行的線程使用同一個消息隊列,而且能夠處理該隊列中的消息。函數

private Handler handler = new Handler();oop

咱們作這樣一個實驗,在主用戶界面中建立一個帶有無參構造函數的Handler對象,該Handler對象向消息隊列推送一個Runnable對象,在Runnable對象的run函數中打印當前線程Id,咱們比較主用戶界面線程IDRunnable線程ID是否相同。具體代碼以下:
post

public class HandlerTest01 extends Activity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            
            System.out.println("Activity —> " + Thread.currentThread().getId());
            handler.post(r);
        }
     
        private Handler handler = new Handler();
        private Runnable r = new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("Runnalbe —> " + Thread.currentThread().getId());
            }
        };
    }


 經過這個例子的輸出能夠發現,Runnable對象和主用戶界面線程的ID是相同。在這個例子中,咱們直接利用handler對象post了一個runnable對象,至關於直接調用了Runnable對象的run函數,也就說沒有通過start函數調用run(),那麼就不會建立一個新線程,而是在原有線程內部直接調用run()方法,所以輸出的線程Id是相同的。this


 


b
、若是new一個帶參構造函數的Handler對象,那麼這個Handler對象將與參數所表示的Looper相關聯。注意:此時線程類應該是一個特殊類HandlerThread類,一個Looper類的Thread類,它繼承自Thread類。spa


HandlerThread handlerthread = new HandlerThread( "MyThread");
    handlerthread.start();
    private MyHandler handler = new MyHandler(handlerthread.getLooper());
     
    class MyHandler extends Handler {
        public MyHandler() {
     
        }
     
        public MyHandler(Looper looper) {
            super(looper);
        }
    }    

下面這個例子,將介紹如何開啓一個新的線程,並經過Handler處理消息。線程

HandlerTest02.java

public class HandlerTest02 extends Activity {
         
        private MyHandler myhandler = null;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);
            this.setContentView(R.layout.main);
            System.out.println("Activity —> " + Thread.currentThread().getId());
            
            // 生成一個HandlerThread對象,使用Looper來處理消息隊列
            HandlerThread thread =  new HandlerThread( "MyThread");
            // 必須啓動這個線程
            thread.start();
            // 將一個線程綁定到Handler對象上,則該Handler對象就能夠處理線程的消息隊列
            myhandler = new MyHandler(thread.getLooper());
            // 從Handler中獲取消息對象
            Message msg = myhandler.obtainMessage();
            // 將msg對象發送給目標對象Handler
            msg.sendToTarget();
        }
     
        class MyHandler extends Handler {
            public MyHandler() {
                
            }
            
            // 帶有參數的構造函數
            public MyHandler(Looper looper) {
                super(looper);
            }
            
            @Override
            public void handleMessage(Message msg) {
                System.out.println("MyHandler —> " + Thread.currentThread().getId());
            }
        }
    }


根據這個例子返回的結果,能夠看出,新線程Id與主用戶界面的線程Id不一樣。因爲咱們調用了thread.start()方法,真正的建立了一個新線程,與原來的線程處於不一樣的線程上下文中,所以打印輸出的線程Id是不一樣的。

 


c
、若是須要Handler對象去處理消息,那麼就要重載Handler類的handleMessage函數。


private Handler handler = new Handler() {
         
        @Override
        public void handleMessage(Message msg) {
            // TODO : Handle the msg
            // Usually we update UI here.
        }
    }


        注意到註釋部分,咱們一般在handleMessage中處理更新UI界面的操做。
   前面介紹了Handler類的基本使用,可是仍是沒有涉及到Thread類。要想實如今後臺從新開啓一個新的線程,經過該線程執行一些費時的操做,咱們也使用Thread類來完成這個功能。下面咱們先給出一個使用Thread類的例子程序。  

ThreadTest.java

public class ThreadTest extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);
            this.setContentView(R.layout.main);
            System.out.println("Activity —> " + Thread.currentThread().getId());
            
            Thread thread = new Thread(r);
            thread.start();
            try {
                Thread.currentThread().sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            thread.stop();
        }
     
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println("Runnable —> " + Thread.currentThread().getId());
            }
        };
    }


 這個程序執行的結果以下。新線程在建立對象時,傳入了Runnable類的一個對象,在Runnable對象中重載了run()方法去執行耗時的操做;新的線程實例執行了start方法,開啓了一個新的線程執行Runnablerun方法。

 


  上面這些就是我如今接觸到執行線程的方法,在線程中,能夠完成咱們所須要的操做(好比:下載,處理數據,檢測網絡狀態等),使其與UI界面分離,那麼UI界面不會由於耗時操做致使界面被阻塞。
  在《解密Google Android》一書中,發現了這樣一個啓動線程的模型。利用該模型,咱們能夠把一些耗時的操做放到doStuff方法中去執行,同時在updateUIHere方法中進行更新UI界面的操做,就能夠完成一個線程所須要的功能。其餘的說明寫在註釋部分了。


Handler myHandler = new Handler() {
        public void handleMessage(Message msg) {
            updateUIHere();
        }
    }
     
    new Thread() {
        public void run() {
            doStuff();         // 執行耗時操做
            Message msg = myHandler.obtainMessage();
            Bundle b = new Bundle();
            b.putString("key""value");
            m.setData(b);    // 向消息中添加數據
            myHandler.sendMessage(m);    // 向Handler發送消息,更新UI
        }
    }.start();
相關文章
相關標籤/搜索