Handler 基本用法--线程间传值
解釋:?
當應用程序啟動時,Android首先會開啟一個主線程 (也就是UI線程) , 主線程為管理界面中的UI控件,進行事件分發, 比如說, 你要是點擊一個 Button ,Android會分發事件到Button上,來響應你的操作。 如果此時需要一個耗時的操作,例如: 聯網讀取數據, 或者讀取本地較大的一個文件的時候,你不能把這些操作放在主線程中,,如果你放在主線程中的話,界面會出現假死現象, 如果5秒鐘還沒有完成的話,會收到Android系統的一個錯誤提示 "強制關閉".?
這個時候我們需要把這些耗時的操作,放在一個子線程中,因為子線程涉及到UI更新,Android主線程是線程不安全的,也就是說,更新UI只能在主線程中更新,子線程中操作是危險的. 會出現如下異常:
即:只有創建該控件的線程才可以操作該控件
這個時候,Handler就出現了 。由于Handler運行在主線程中(UI線程中), 它與子線程可以通過Message對象來傳遞數據, 這個時候,Handler就承擔著接受子線程傳過來的Message對象,(里面包含數據) , 把這些消息放入主線程隊列中,配合主線程進行更新UI。
例子如下:
1》布局文件:activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="com.cxc.threadandhandler.MainActivity" ><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="手動創建線程并與GUI同步 " /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal" ><TextViewandroid:id="@+id/show_info_tv"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:text="顯示后臺任務情況" /><Buttonandroid:id="@+id/start_task_bt"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Start Task" /></LinearLayout></LinearLayout>
效果如下:
2》MainActivity.java代碼
代碼中有很詳細的備注
package com.cxc.handlerdemo;import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}@Overridepublic 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;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {// Handle action bar item clicks here. The action bar will// automatically handle clicks on the Home/Up button, so long// as you specify a parent activity in AndroidManifest.xml.int id = item.getItemId();if (id == R.id.action_settings) {return true;}return super.onOptionsItemSelected(item);} }運行的結果為:
package com.cxc.threadandhandler;import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView;public class MainActivity extends Activity {private static final String TAG = "com.cxc.threadandhandler.mainactivity";private static final int MESSAGE_KEY = 1001;private TextView show_info_tv;private Button start_task_bt;private Handler myHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stubsuper.handleMessage(msg);if (msg.what == MESSAGE_KEY) {// 接收消息并更新UILog.d(TAG, "--thread:" + Thread.currentThread().getId()+"--reciver:"+msg.obj.toString());show_info_tv.setText(msg.obj.toString());}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Log.d(TAG, "---main---" + Thread.currentThread().getId());Log.d(TAG, "---onCreate---");initViews();}private void initViews() {Log.d(TAG, "---initViews---");show_info_tv = (TextView) findViewById(R.id.show_info_tv);start_task_bt = (Button) findViewById(R.id.start_task_bt);start_task_bt.setOnClickListener(myButtonClickListener);}OnClickListener myButtonClickListener = new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubswitch (v.getId()) {case R.id.start_task_bt:// to-do// 將耗時的操作移到子線程中Log.d(TAG, "---Start Task Button Click---");BackgroundThread backgroundThread = new BackgroundThread();new Thread(backgroundThread).start();// 啟動后臺線程,以處理耗時任務break;default:break;}}};class BackgroundThread implements Runnable {public BackgroundThread() {// TODO Auto-generated constructor stub}@Overridepublic void run() {// TODO Auto-generated method stubLog.d(TAG, "-----work thread ---" + Thread.currentThread().getId());backgroundThreadProcessing();}// 在后臺執行一些處理的方法---耗時操作private void backgroundThreadProcessing() {// to-do 耗時操作Log.d(TAG, "-----work thread -backgroundThreadProcessing ---"+ Thread.currentThread().getId());for (int i = 0; i < 10; i++) {String text = show_info_tv.getText().toString();text += ("#" + i);Message msg = new Message();msg.what = MESSAGE_KEY;//用于區分不同的消息msg.obj = text;//消息內容Log.d(TAG, "--thread:" + Thread.currentThread().getId()+"--send:"+text);myHandler.sendMessage(msg);//發送消息// 當前線程(后臺子線程)休眠1000mstry {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}} }
運行結果:
可以看到主線程(UI線程)已經接收到了子線程發送過來的數據。
這一點也可以從程序的Log看出來
06-02 16:25:19.299: D/com.cxc.threadandhandler.mainactivity(10304): ---main---1 06-02 16:25:19.299: D/com.cxc.threadandhandler.mainactivity(10304): ---onCreate--- 06-02 16:25:19.299: D/com.cxc.threadandhandler.mainactivity(10304): ---initViews--- 06-02 16:25:30.259: D/com.cxc.threadandhandler.mainactivity(10304): ---Start Task Button Click--- 06-02 16:25:30.259: D/com.cxc.threadandhandler.mainactivity(10304): -----work thread ---6346 06-02 16:25:30.259: D/com.cxc.threadandhandler.mainactivity(10304): -----work thread -backgroundThreadProcessing ---6346 06-02 16:25:30.259: D/com.cxc.threadandhandler.mainactivity(10304): --thread:6346--send:顯示后臺任務情況#0 06-02 16:25:30.259: D/com.cxc.threadandhandler.mainactivity(10304): --thread:1--reciver:顯示后臺任務情況#0 06-02 16:25:31.259: D/com.cxc.threadandhandler.mainactivity(10304): --thread:6346--send:顯示后臺任務情況#0#1 06-02 16:25:31.259: D/com.cxc.threadandhandler.mainactivity(10304): --thread:1--reciver:顯示后臺任務情況#0#1 06-02 16:25:32.264: D/com.cxc.threadandhandler.mainactivity(10304): --thread:6346--send:顯示后臺任務情況#0#1#2 06-02 16:25:32.264: D/com.cxc.threadandhandler.mainactivity(10304): --thread:1--reciver:顯示后臺任務情況#0#1#2 06-02 16:25:33.264: D/com.cxc.threadandhandler.mainactivity(10304): --thread:6346--send:顯示后臺任務情況#0#1#2#3 06-02 16:25:33.264: D/com.cxc.threadandhandler.mainactivity(10304): --thread:1--reciver:顯示后臺任務情況#0#1#2#3 06-02 16:25:34.264: D/com.cxc.threadandhandler.mainactivity(10304): --thread:6346--send:顯示后臺任務情況#0#1#2#3#4 06-02 16:25:34.264: D/com.cxc.threadandhandler.mainactivity(10304): --thread:1--reciver:顯示后臺任務情況#0#1#2#3#4 06-02 16:25:35.264: D/com.cxc.threadandhandler.mainactivity(10304): --thread:6346--send:顯示后臺任務情況#0#1#2#3#4#5 06-02 16:25:35.264: D/com.cxc.threadandhandler.mainactivity(10304): --thread:1--reciver:顯示后臺任務情況#0#1#2#3#4#5 06-02 16:25:36.264: D/com.cxc.threadandhandler.mainactivity(10304): --thread:6346--send:顯示后臺任務情況#0#1#2#3#4#5#6 06-02 16:25:36.264: D/com.cxc.threadandhandler.mainactivity(10304): --thread:1--reciver:顯示后臺任務情況#0#1#2#3#4#5#6 06-02 16:25:37.269: D/com.cxc.threadandhandler.mainactivity(10304): --thread:6346--send:顯示后臺任務情況#0#1#2#3#4#5#6#7 06-02 16:25:37.269: D/com.cxc.threadandhandler.mainactivity(10304): --thread:1--reciver:顯示后臺任務情況#0#1#2#3#4#5#6#7 06-02 16:25:38.269: D/com.cxc.threadandhandler.mainactivity(10304): --thread:6346--send:顯示后臺任務情況#0#1#2#3#4#5#6#7#8 06-02 16:25:38.269: D/com.cxc.threadandhandler.mainactivity(10304): --thread:1--reciver:顯示后臺任務情況#0#1#2#3#4#5#6#7#8 06-02 16:25:39.269: D/com.cxc.threadandhandler.mainactivity(10304): --thread:6346--send:顯示后臺任務情況#0#1#2#3#4#5#6#7#8#9 06-02 16:25:39.269: D/com.cxc.threadandhandler.mainactivity(10304): --thread:1--reciver:顯示后臺任務情況#0#1#2#3#4#5#6#7#8#9
可以看出,主線程(UI線程)的線程ID為1,而我們自己啟動的線程ID為6346,可以說明它們確實不在一個線程中。
關于線程的相關知識可以參考:Java線程之兩種方法Runnable和Thread的區別
總結
以上是生活随笔為你收集整理的Handler 基本用法--线程间传值的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java线程之两种方法Runnable和
- 下一篇: vim程序编译器使用(整理)