安卓 线程
一、简述
记--安卓编程中线程的简单使用例子。使用匿名方式、继承方式创建线程。
代码文件:链接: https://pan.baidu.com/s/10saeJ5XxDOpWokn9vB6Y1w 提取码: pkfu
二、方式1--匿名类
// 开启子线程
new Thread(){
@Override
public void run(){
//子线程执行的动作,比如执行test()函数
test();
}
}.start();
例子: 有一个int类型的成员num,子线程每隔一秒将num加2,点击主线程中的按钮将num的当前值显示到TextView。
代码结构
布局:
2.2 效果
注:TextView控件没有立即更新,需要手动更新,所以看到本来是每隔1秒追加打印num的值变为"一股脑"更新了。
源码文件
MainActivity.java文件
package com.example.testthread;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import android.app.Activity;
public class MainActivity extends Activity {
private int num = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 开启子线程
new Thread()
{
@Override
public void run()
{
//子线程要执行的动作,每隔1秒就将num+2
while(true)
{
num += 2;
Sleep(1000);//延时1秒
}
}
}.start();
Toast.makeText(this, "子线程1创建完毕!", Toast.LENGTH_SHORT).show();
}
public void on_btn_main_thread_Clicked(View v)
{
Toast.makeText(this, "主线程!", Toast.LENGTH_SHORT).show();
TextView tv = (TextView)findViewById(R.id.tv_main_thread);
for(int i=0; i<20; i++)
{
tv.append("num="+num+"\n");
Sleep(500);
}
}
public void Sleep(long ms)
{
try {
Thread.sleep(ms);//延时ms毫秒
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
三、方式2--自定义类继承Thread类
方式1的匿名类方式虽然操作"简单",但是难以"控制",比如没有一个实际的操作对象,就不方便在后面进行对子线程的控制,如对子线程的休眠、停止、销毁等操作。还有就是匿名方式不方便"重用"。
自定义一个类继承Thread类,并重写run方法
public class MyThread extends Thread {
@Override
public void run(){
//要执行的动作
}
}
创建子线程并启动
new MyThread().start();//开启子线程,执行run()方法
或
MyThread thread1 = new MyThread();
thread1.start();
例子: 有一个int类型的成员num,子线程每隔一秒将num加2,点击主线程中的按钮将num的当前值显示到TextView。
代码结构
效果:
源码文件
MainActivity.java文件
package com.example.testthread;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import android.app.Activity;
public class MainActivity extends Activity {
private int num = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 开启子线程
new Mythread().start();
Toast.makeText(this, "子线程1创建完毕!", Toast.LENGTH_SHORT).show();
}
public void on_btn_main_thread_Clicked(View v)
{
Toast.makeText(this, "主线程!", Toast.LENGTH_SHORT).show();
TextView tv = (TextView)findViewById(R.id.tv_main_thread);
for(int i=0; i<20; i++)
{
tv.append("num="+num+"\n");
Sleep(500);
}
}
public class Mythread extends Thread
{
@Override
public void run()
{
//子线程要执行的动作,每隔1秒就将num+2
while(true)
{
num += 2;
Sleep(1000);//延时1秒
}
}
}
public void Sleep(long ms)
{
try {
Thread.sleep(ms);//延时ms毫秒
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
四、问题总结
1、子线程更新UI(控件)问题。
测试代码1:在子线程中成功改变TextView控件的文本。
package com.example.testthread;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import android.app.Activity;
public class MainActivity extends Activity {
private int num = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 开启子线程
new Thread()
{
@Override
public void run()
{
//子线程要执行的动作
TextView tv = (TextView)findViewById(R.id.tv_main_thread);
tv.setText("子线程正在运行。。。");
}
}.start();
Toast.makeText(this, "子线程1创建完毕!", Toast.LENGTH_SHORT).show();
}
public void on_btn_main_thread_Clicked(View v)
{
Toast.makeText(this, "主线程!num="+num, Toast.LENGTH_SHORT).show();
}
public void Sleep(long ms)
{
try {
Thread.sleep(ms);//延时ms毫秒
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
运行结果:
测试代码2:在测试代码1的基础上修改"子线程执行的动作"部分,成功运行。
//子线程要执行的动作
TextView tv = (TextView)findViewById(R.id.tv_main_thread);
tv.setText("子线程正在运行");
num += 2;
Sleep(1000);
运行结果:
测试代码3:在测试代码2的基础上修改"子线程执行的动作"部分,延时1秒,二次更改TextView控件的文本,程序崩溃。
//子线程要执行的动作
TextView tv = (TextView)findViewById(R.id.tv_main_thread);
tv.setText("子线程正在运行");
num += 2;
Sleep(1000);
tv.setText("num="+num);
运行结果:
2、如何手动立即更新UI?
在方式1--匿名类中的按钮单击响应代码效果,并没有立即改变TextView控件
public void on_btn_main_thread_Clicked(View v)
{
Toast.makeText(this, "主线程!", Toast.LENGTH_SHORT).show();
TextView tv = (TextView)findViewById(R.id.tv_main_thread);
for(int i=0; i<20; i++)
{
tv.append("num="+num+"\n");
Sleep(500);
}
}
使用Handler更新UI,只需在需要的时候发送一个信号。(有点像Handler是一个独立线程,收到一个信号就进行动作)
例子:子线程每隔1秒发送一个信号给handler,通知handler改变TextView的文本。主线程能够随时的打印num的值。
测试代码:
package com.example.testthread;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private int num;
private TextView tv;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg){
switch(msg.what){
case 0:
tv.setText(num+"");//改变TextView控件的文本
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
num = 1;
tv = (TextView)findViewById(R.id.tv_main_thread);//拿到TextView对象
//开启子线程
new Thread()
{
@Override
public void run()
{
while(true)//每隔1秒发送一个0信号给handler
{
handler.sendEmptyMessage(0);//发送一个0信号给handler,通知handler更新UI
num++;
Sleep(1000);//延时1秒
}
}
}.start();
Toast.makeText(this, "子线程1创建完毕!", Toast.LENGTH_SHORT).show();
}
public void on_btn_main_thread_Clicked(View v)
{
Toast.makeText(this, "主线程!num="+num, Toast.LENGTH_SHORT).show();
}
public void Sleep(long ms)
{
try {
Thread.sleep(ms);//延时ms毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果:
其中发送信号给Handler:
handler.sendEmptyMessageDelayed(0, 1000);//1秒后发送0信号。
handler.sendEmptyMessage(0);//发送0信号