虽然使用Intent Service 和创建AsyncTasks是非常有用的捷径,但还是有一些需要创建和管理自己的线程来执行后台处理的场景。通常的情况就是存在长时间运行或者相互联系的线程,它们需要一些比目前两种技术描述的更加微秒或者复杂的管理操作。
这里我们将介绍如何创建和启动新的Thread对象,以及如何在更新UI前与GUI线程同步。
可以使用Android的Handler类与java.lang.Thread中提供的线程类创建和管理子线程。
代码清单如下:
1>布局如下
1.1>效果
1.2>代码如下:
<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" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Thread用于耗时任务 + Handler用于GUI同步" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="@+id/show_info_tv"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="显示后台任务情况" />
<Button
android:id="@+id/start_task_bt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Task" />
</LinearLayout>
</LinearLayout>
2>代码如下
2.1>详细代码如下:
package com.demo.cxc.threadhandlerdemo;
import android.os.Handler;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private TextView show_info_tv;
private Button start_task_bt;
/*
//在主线程上初始化一个handler
//每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程)
//Handler对象初始化后,就默认与对它初始化的进程的消息队列绑定
//在这里myHandler与GUI线程(主线程)的消息队列绑定
*/
private Handler myHandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "---onCreate---Thread id:" + Thread.currentThread().getId());
initViews();
}
private void initViews() {
Log.d(TAG, "---initViews---thread id:" + Thread.currentThread().getId());
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);
}
View.OnClickListener myButtonClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.start_task_bt:
// to-do
// 将耗时的操作移到子线程中
Log.d(TAG, "---Start Task Button Click---");
Thread myThread = new Thread(null,
doBackgroundThreadProcessingRunnable, "background");
myThread.start();
break;
default:
break;
}
}
};
// 执行后台处理方法的Runnable
private Runnable doBackgroundThreadProcessingRunnable = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
Log.d(TAG, "---doBackgroundThreadProcessingRunnable run---thread id :" + Thread.currentThread().getId());
backgroundThreadProcessing();
}
};
// 在后台执行一些处理的方法---耗时操作
private void backgroundThreadProcessing() {
// to-do 耗时操作
for (int i = 0; i < 10; i++) {
Log.d(TAG, "*****thread id :" + Thread.currentThread().getId() + "---backgroundThreadProcessing---i:" + i);
// 当前线程休眠1000ms
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 在UI主线程上使用Handler发布doUpdateGUI Runnable
/*
* doUpdateGUIRunnable对象并没有新建一个单独的线程,
* 而是运行在myHandler所在的线程中,
* 在这里就是GUI线程中
* */
myHandler.post(doUpdateGUIRunnable);
}
}
// 执行updateGUI方法的Runnable
private Runnable doUpdateGUIRunnable = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
Log.d(TAG, "++++++doUpdateGUIRunnable run---thread id :" + Thread.currentThread().getId());
updateGUI();
}
};
// 这个方法必须由UI线程调用
private void updateGUI() {
// to-do 更新UI
show_info_tv.setText(show_info_tv.getText().toString() + "¥¥");
}
}
2.2>运行效果:
2.3> Log输出如下:
06-04 15:52:12.949 27514-27514/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ ---onCreate---Thread id:1
06-04 15:52:12.949 27514-27514/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ ---initViews---thread id:1
06-04 15:52:19.829 27514-27514/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ ---Start Task Button Click---
06-04 15:52:19.829 27514-28040/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ ---doBackgroundThreadProcessingRunnable run---thread id :14444
06-04 15:52:19.829 27514-28040/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ *****thread id :14444---backgroundThreadProcessing---i:0
06-04 15:52:20.829 27514-28040/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ *****thread id :14444---backgroundThreadProcessing---i:1
06-04 15:52:20.829 27514-27514/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ ++++++doUpdateGUIRunnable run---thread id :1
06-04 15:52:21.829 27514-28040/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ *****thread id :14444---backgroundThreadProcessing---i:2
06-04 15:52:21.829 27514-27514/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ ++++++doUpdateGUIRunnable run---thread id :1
06-04 15:52:22.834 27514-28040/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ *****thread id :14444---backgroundThreadProcessing---i:3
06-04 15:52:22.834 27514-27514/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ ++++++doUpdateGUIRunnable run---thread id :1
06-04 15:52:23.829 27514-28040/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ *****thread id :14444---backgroundThreadProcessing---i:4
06-04 15:52:23.829 27514-27514/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ ++++++doUpdateGUIRunnable run---thread id :1
06-04 15:52:24.829 27514-28040/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ *****thread id :14444---backgroundThreadProcessing---i:5
06-04 15:52:24.829 27514-27514/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ ++++++doUpdateGUIRunnable run---thread id :1
06-04 15:52:25.829 27514-28040/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ *****thread id :14444---backgroundThreadProcessing---i:6
06-04 15:52:25.834 27514-27514/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ ++++++doUpdateGUIRunnable run---thread id :1
06-04 15:52:26.834 27514-28040/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ *****thread id :14444---backgroundThreadProcessing---i:7
06-04 15:52:26.834 27514-27514/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ ++++++doUpdateGUIRunnable run---thread id :1
06-04 15:52:27.834 27514-28040/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ *****thread id :14444---backgroundThreadProcessing---i:8
06-04 15:52:27.839 27514-27514/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ ++++++doUpdateGUIRunnable run---thread id :1
06-04 15:52:28.834 27514-28040/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ *****thread id :14444---backgroundThreadProcessing---i:9
06-04 15:52:28.834 27514-27514/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ ++++++doUpdateGUIRunnable run---thread id :1
06-04 15:52:29.839 27514-27514/com.demo.cxc.threadhandlerdemo D/MainActivity﹕ ++++++doUpdateGUIRunnable run---thread id :1
从以上Log 可以看出,doUpdateGUIRunnable确定是运行在GUI线程中,即myHandler.post(doUpdateGUIRunnable)会使doUpdateGUIRunable对象运行在创建myHandler的线程中,在这里也就是GUI线程中了。