編輯:關於Android編程
在上一個例子中,最終我們發現,其實用到的線程只有一個,那就是程序的主線程(UI線程)。那麼怎麼把那個例子改成用新建的線程來實現呢,今天我嘗試了一下,寫了下面這個小程序。
當然,首先要聲明一下,今天的這個例子並不是推薦的寫法,而是我為了學習多線程而寫的例子(貌似更常用的是AsyncTask,而不是Thread和Handler去更新UI)。
在今天的這個例子中,我用到了Looper,先說說Looper是什麼
在API中是這麼解釋Lopper的:Class used to run a message loop for a thread。我的理解是Looper是用來控制message queue的類
Looper常用的幾個用法有:
Looper.prepare() 安卓的主線程中會默認調用這個方法來創建消息隊列。但是,如果我們自己新建的線程,如果需要消息隊列,則需要手動調用這個方法。
Looper.loop() 這個方法用在prepare()方法之後,調用該方法之後,進入消息循環。
Looper.getMainLooper() 我在代碼中用到了這個方法,這個方法的作用是獲得主線程的Looper實例
Looper.myLooper() 這個方法用到獲取當前線程的Looper實例
今天這個例子和第二篇中實現的功能一下,我只不過改了一個寫法而已,下面是代碼:
package com.example.handler2; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ProgressBar; public class MainActivity extends Activity { Button startButton = null; Button stopButton = null; ProgressBar progressbar = null; Thread counter = null; //獲取主線程的looper Looper looper = Looper.getMainLooper(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); startButton = (Button) findViewById(R.id.startButton); stopButton = (Button) findViewById(R.id.stopButton); progressbar = (ProgressBar) findViewById(R.id.progressBar); //為button綁定onclicklistener startButton.setOnClickListener(new ButtonOnclickListener()); stopButton.setOnClickListener(new stopOnclickListener()); } class ButtonOnclickListener implements OnClickListener{ public void onClick(View v) { progressbar.setVisibility(View.VISIBLE); counter = new Thread(){ int i = 1; @Override public void run() { // TODO Auto-generated method stub i += 10; Message msg = handler.obtainMessage(); msg.arg1 = i; //讓線程延遲一秒 try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } Log.i("run", "run "+i+"%"); Log.i("run", Thread.currentThread().getName()); msg.sendToTarget(); } }; counter.start(); } } class stopOnclickListener implements OnClickListener{ public void onClick(View v) { //從message queue 中去掉run handler.removeCallbacks(counter); //讓progressbar置成隱藏 progressbar.setVisibility(View.GONE); } } //將handler與主線程關聯 Handler handler = new Handler(looper){ public void handleMessage(android.os.Message msg) { int i =msg.arg1; //根據message中傳來的參數控制進度條 progressbar.setProgress(i); Log.i("run", Thread.currentThread().getName()); if(i<100){ handler.post(counter); }else{ handler.removeCallbacks(counter); progressbar.setVisibility(View.GONE); } }; }; }
但是因為安卓不允許我們在主線程之外的線程中對UI進行修改,所以我在新建的線程中只是進行計數,然後將計數的結果通過message傳遞到主線程中,在主線程中更新進度條。
遺留問題:
本來這個例子到這裡就結束了,但是,我為了深入了解一下就在我新建的線程的run中和主線程Handler的handlerMessage方法中打印了當前線程的名稱:
結果如下:
按照我最初的理解,在日志中應該是主線程和我的線程交替寫入日志,但是實際的情況是在第一次是counter線程,後面打印的都是主線程
請問各位,有誰知道這是為什麼嗎?
我看到在API中Handler的post方法是這麼說明的:Causes the Runnable r to be added to the message queue. The runnable will be run on the thread to which this handler is attached.
難道是,我使用了post方法,就相當於把counter線程的run中的代碼拷貝中主線程中去執行了嗎?如果有誰知道麻煩為我解答一下,不甚感激!
通常也稱作套接字,用於描述IP地址和端口,是一個通信鏈的句柄。在Internet上的主機一般運行了多個服務軟件,同時提供幾種服務。每種服務都打開一個Socket,並綁定
MediaPlayer 其實這個類就是用於播放音頻或者視頻的,那今天就學習學習這個類,這幅圖非常好,讓我偷來了,O(∩_∩)O哈哈~1 --MediaPl
解決 INSTALL FAILED CONFLICTING PROVIDER的問題方法 在安裝Android應用時出現INSTALL FAILED
前言在H5火熱的時代,許多框架都出了底部彈窗的控件,在H5被稱為彈出菜單ActionSheet,今天我們也來模仿一個ios的底部彈窗,取材於蘋果QQ的選擇頭像功能。正文廢