下面是快速建立一个新线程的方法:java
第一种:直接建立子线程并启动
new Thread() {
@Override
public void run() {
//这里写入子线程须要作的工做
}
}.start();
第二种:先建立子线程,而后启动
private Thread newThread; //声明一个子线程
newThread = new Thread(new Runnable() {
@Override
public void run() {
//这里写入子线程须要作的工做
}
});android
newThread.start(); //启动线程安全
操做是颇有可能并发的,而界面只有一个
这个和买票排队是一回事
买票的人太多了,卖票的只有一个,只能一个一个来
若是你开多线程,让100我的同时去买票,并且不排队,那么后果会怎么样- -
同理,你开多线程,让100个线程去设置同一个TextView的显示内容,每一个显示内容都不同,它该听谁的?多线程
那为何不直接new一个新线程而要使用一个所谓的handler?并发
就是由于new了一个子线程才要用handler的,
否则在主线程里更新UI要handler干什么?画蛇添足
就比如只有1我的来买票,卖票的难道会跟他说:同志,请你排队!?
handle是主线程 ,Thread是从线程。控件数据更改只能在主线程 里,因此要用handleapp
更新UI只能在主线程里进行,不然会报错。但有时咱们在子线程里进行操做须要更新UI,handler就登场了,它能够把子线程的数据传给主线程,让主线程同步操做来更新UI。ide
先来看这样一个例子oop
package com.hua;post
import android.app.Activity;
import android.os.Bundle;this
public class UpdateUInum1Activity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new Thread(new Runnable() {
@Override
public void run() {
setTitle("fengyi.hua");
}
});
}
}
上面就是为了实现用一个Thread来更新Title,能够实现这个功能,刷新UI界面。可是这样是不对的,由于它违背了单线程模型:Android UI操做并非线程安全的而且这些操做必须在UI线程中执行。
有些人以为这个方法确实也多余,为何呢,由于既然是刷新一次,我彻底能够在主线程中执行刷新Title的操做的,为何还要开启线程。这是由于可能涉及到延时或者其它。好比说等待1min后再进行刷新操做,这个时间段要保证主UI线程是可操做的,因此要用到Thread来更新。可是这确实对于android的单线程模型有冲突,不建议使用。使用错误的例子以下:
package com.hua;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
public class UpdateTitleActivity extends Activity {
private void updateTitle() {
Date date = new Date();
int hour, minute, second;
String shour, sminute, ssecond;
hour = (date.getHours() + 8) % 24;
minute = date.getMinutes();
second = date.getSeconds();
if (hour < 10) {
shour = "0" + hour;
} else {
shour = "" + hour;
}
if (minute < 10) {
sminute = "0" + minute;
} else {
sminute = "" + minute;
}
if (second < 10) {
ssecond = "0" + second;
} else {
ssecond = "" + second;
}
setTitle("当前时间:" + shour + ":" + sminute + ":" + ssecond);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Timer timer = new Timer();
timer.scheduleAtFixedRate(new myTask(), 1, 1000);//这里是利用Timer,跟使用Thread是一个效果。表现
//的效果就是屡次更新Title,看会不会出问题。
}
private class myTask extends TimerTask {
@Override
public void run() {
updateTitle();
}
}
}
上面的代码用来每1s刷新一次Title,用来显示当前时间。可是因为android是单线程模型,存在线程安全问题,因此当第二次刷新的时候,出现错误。
正确的作法
上面所述两种方法,分别是Thread方法,和TimerTask方法。在Java中是经常使用的,由于线程安全。可是在单线程模型的android中,是不能用的。正确的方法有2个。
1.Thread+handler
2.TimerTask+handler
3.Runnable+Handler.postDelayed(runnable,time)
例子:Timertask+handler
package com.hua;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
public class UpdateTitleActivity extends Activity {
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
updateTitle();
break;
default:
break;
}
}
};
private void updateTitle() {
Date date = new Date();
int hour, minute, second;
String shour, sminute, ssecond;
hour = (date.getHours() + 8) % 24;
minute = date.getMinutes();
second = date.getSeconds();
if (hour < 10) {
shour = "0" + hour;
} else {
shour = "" + hour;
}
if (minute < 10) {
sminute = "0" + minute;
} else {
sminute = "" + minute;
}
if (second < 10) {
ssecond = "0" + second;
} else {
ssecond = "" + second;
}
setTitle("当前时间:" + shour + ":" + sminute + ":" + ssecond);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Timer timer = new Timer();
timer.scheduleAtFixedRate(new myTask(), 1, 10000);
}
private class myTask extends TimerTask {
@Override
public void run() {
Message msg = new Message();
msg.what = 1;
mHandler.sendMessage(msg);
}
}
}
记住,处理都是在handleMessage里面,固然也能够不在,能够在handler的内类Callback的方法handleMessage里面。Handler跟其Callback也是学问,能够之后讲。
为了解决在Android非UI线程更新UI这个问题,Android提供了一些方法,从其余线程访问UI线程。
// 1. 使用runOnUiThread的方式 runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(MainActivity.this, "sdf", Toast.LENGTH_SHORT).show(); } }); // 2. 使用post的方式 btn.post(new Runnable() { @Override public void run() { Toast.makeText(MainActivity.this, "sdf", Toast.LENGTH_SHORT).show(); } }); // 3. 使用postDelayed的方式 btn.postDelayed(new Runnable() { @Override public void run() { Toast.makeText(MainActivity.this, "sdf", Toast.LENGTH_SHORT).show(); } }, 1000); // 4. 使用Looper的方式 Looper.prepare(); Toast.makeText(MainActivity.this, "sdf", Toast.LENGTH_SHORT).show(); Looper.loop(); // 5. 使用Handler的方式 private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: Toast.makeText(MainActivity.this, "sdf", Toast.LENGTH_SHORT).show(); break; } } }; // 发送消息 handler.sendEmptyMessage(1); 或者 Handler handler = new Handler(Looper.getMainLooper()); handler.post(new Runnable() { @Override public void run() { Toast.makeText(MainActivity.this, "sdf", Toast.LENGTH_SHORT).show(); } })