1.背景
Android是单线程模型,在应用程序启动时,Android会启动一个主线程(UI线程),主线程负责与UI相关的事件,如按键,触屏,绘图等。
不过仍然可以在UI线程中处理非UI相关的事件,但是这是一件危险的事情,有可能会造成ANR。
原因,单线程模型下更新UI是线程安全的,省去了很多逻辑上的处理。(???)
2.实例
如下图,当点击Button1,执行
for(i = 0 ; i< 1000000000 ;i++){
}
点击Button2,show一个Toast
代码如下
package com.wenfang.practice;
import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class test extends Activity {
private TextView mTextView;
private Button mButton1;
private Button mButton2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView)findViewById(R.id.tv1);
mButton1 = (Button)findViewById(R.id.bt1);
mButton2 = (Button)findViewById(R.id.bt2);
mButton1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
long i ;
for(i = 0 ; i< 1000000000 ;i++){
}
mTextView.setText(String.valueOf(i));
}
});
mButton2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "You clicked Button2", Toast.LENGTH_SHORT).show();
}
});
}
}
按照上诉代码,可以执行,但是在click Button1之后,去click Button2会alway发生ANR
原因就是Android的单线程模型,UI更新相关只能在主线程中完成,当click Button2时,主线程还在执行i++,当超过5秒就会发生ANR
如何解决这个问题,Android中可以利用Handler来处理。
package com.wenfang.practice;
import android.R.string;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class save extends Activity {
private static final String TAG = "Handler";
private TextView mTextView;
private Button mButton1 ;
private Button mButton2;
private Handler handler;
private Thread testThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView)findViewById(R.id.tv1);
mButton1 = (Button)findViewById(R.id.bt1);
mButton2 = (Button)findViewById(R.id.bt2);
handler = new MyHandler();
testThread = new MyThread();
mButton1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
testThread.start();
}
});
mButton2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "You clicked Button2", Toast.LENGTH_SHORT).show();
}
});
}
class MyHandler extends Handler{
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
switch (msg.what){
case 1:
mTextView.setText(msg.obj.toString());
break;
}
}
}
class MyThread extends Thread{
String content = "This is from another thread";
int what = 1;
long currentId = this.getId();
@Override
public void run() {
// TODO Auto-generated method stub
long i;
for(i = 0 ; i< 1000000000 ;i++){
}
Message msg = new Message();
msg.what = what;
msg.obj = i;
handler.sendMessage(msg);
}
}
}
上面的例子中,将i++的操作放在了另外一个线程中执行,当点击Button1 之后再去点击Button2,此时会show Toast,一段时间后i++完成后,Handler将消息发给主线程消息队列,然后再主线程中更新TextView。
在单线程模型中的两条原则,
1.不要阻塞UI线程
2.在UI线程中只访问Android的UI工具包
3.疑问
1.Handler的处理机制
2.当连续两次点击Button时,也会crash,原因是Tread alread start
(后续处理)