1、什么是Handler?
Handler通俗来讲就是用来在各个线程之间发送数据的处理对象。在B线程中,只要获得A线程的Handler,就可以通过handler.sendMessage(messge)方法向A线程发送数据。而当B线程处理完一些耗时操作后,A线程可以通过handler的handlerMessage()方法获得数据
2、主线程
运行所有UI组件。如果任何一个消息用时超过5秒,Android将抛出Application Not Responding,所以一个任务用时超过5秒,应该在一个独立线程中完成它,或者延迟处理它。
子线程没有办法对UI界面的内容进行操作,如果操作,将抛出CalledFromWrongThreadException。为了实现子线程中操作UI界面,Android中引入了Handler消息传递机制。至此,我们学过的子线程操作UI界面的方法有:1、异步任务;2、Loader;3、Handler
3、常用类
a、Handler :处理者,负责Message的发送及处理。主要作用:1、在工作线程中发送消息;2、在主线程中获取并处理消息。
b、Message:消息,其中包含了消息标识,消息处理对象以及处理的数据。由MessageQueue统一列队,最终由Handler处理
c、MessageQueue:消息队列,将Message串联起来,等到Looper的抽取,按照FIFO规则(先进先出)
d、Looper:消息泵,不断的从MessageQueue中抽取Message执行。一个MessageQueue需要对应一个Looper
4、常用类的方法及属性
a、Handler类
1、handleMessage()用在主线程中(可以根据获得的消息更新UI),构造Handler对象时,重写handleMessage()方法,根据工作线程返回的消息标识,获得消息并执行相应操作
2、sendEmptyMessage()用在工作线程中,发送空消息
3、sendMessage()用在工作线程中,将消息(Message对象)发送(给主线程)
b、Message类
1、arg1,arg2 用来存放整型数据,可节省系统资源arg1 and arg2 are lower-cost alternatives to using
2、obj 用来存放Object数据
3、what 就是一个消息的标记,用来区分消息,为int类型
b、Message类
1、message虽然可以通过new Message()方法获得,但是通常使用Message.obtain()方法或handler.obtainMessage()方法从消息池中获得空消息对象,节省系统资源
2、arg1、arg2 若传递的数据为int型,用此属性,节省内存
3、what 就是用于识别消息的标记
4、如果需要从工作线程返回很多消息信息,可以借助Bundle对象将这些数据集中在一起,放在obj属性中
5、备注:
a、通过getResource().getAssets().open(“文件名”);返回值为InputStream,以流的形式打开assets目录下的文件
b、Looper对象用来为一个线程开启一个消息循环,从而操作MessageQueue;
默认情况下,Android创建的线程没有开启消息循环Looper,但是主线程例外。
系统自动为主线程创建Looper对象,开启消息循环;
所以主线程中使用new来创建Handler对象。而子线程中不能直接new来创建Handler对象就会异常。
子线程中创建Handler对象,步骤如下:
Looper.prepare();
Handler handler = new Handler() {
//handlemessage(){}
}
Looper.loop();
Demo1:
构造Handler对象
private Handler handler = new Handler() {
// 现在在主线程中,故可以更新UI(是主线程的接收处理方法)
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
txtShow.setText(msg.arg1 + " " + msg.arg2 + " " + msg.obj);
break;
default:
break;
}
};
};
子线程:
new Thread() {
public void run() {
int count = 0;
while (count < 100) {
Message message = new Message();
// message.what值为int类型,就是一个消息的标识,用来区分消息
message.what = 1;
// arg1,arg2可以传递整数类型,节省系统资源
// arg1 and arg2 are lower-cost alternatives to using
message.arg1 = count;
message.arg2 = count * 10;
// 用来存放非整形数据
message.obj = "count = " + count;
// (子线程中)通过handler对象的sendMessage()方法将消息(Message对象)发送(给主线程)
handler.sendMessage(message);
count++;
SystemClock.sleep(1000);
}
};
}.start();
Demo2:
子线程下载图片数据,传给主线程更新UI
构建Handler对象
private Handler handler = new Handler() {
//主线程handler对象根据message的不同标识采取相应操作
@Override
public void handleMessage(Message msg) {
/**
* 所犯错误:
* pdShow若在外面创建,因为要走三遍handleMessage()方法,所以会创建三个pdShow
* 而case 2的dismiss()只关闭了第三个Show()
*/
// pdShow = new ProgressDialog(MainActivity.this);
switch (msg.what) {
//工作线程发送what为0,代表工作线程开启;主线程相应显示对话框
case 0:
pdShow = new ProgressDialog(MainActivity.this);
pdShow.setTitle("title");
pdShow.setIcon(R.drawable.ic_launcher);
pdShow.setMessage("洪荒之力已开启");
pdShow.show();
break;
//工作线程发送what为1,将代表需要的数据加载完毕,通过Message对象获得数据
case 1:
ivShow.setImageBitmap((Bitmap) msg.obj);
break;
//工作线程发送what为2,代表工作线程执行完毕,关闭对话框
case 2:
pdShow.dismiss();
break;
default:
break;
}
}
};
子线程:
public void start(View v) {
new Thread() {
public void run() {
//当工作线程刚开始时,希望显示进度对话框,此时让handler发送一个空消息即可
handler.sendEmptyMessage(0);
byte[] data = OkHttpUtils.getByteArrayByUrl(url);
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,
data.length);
//Message虽然可以通过new来获取,
//但是通常使用Message.obtain()方法或handler.obtainMessage()方法
//来从消息池中获得空消息对象,以节省资源
Message msg = Message.obtain();
msg.what = 1;
msg.obj = bitmap;
handler.sendMessage(msg);
// SystemClock.sleep(6000);
//当工作线程执行完毕,希望关闭进度对话框,此时让handler发送一个空消息即可
handler.sendEmptyMessage(2);
};
}.start();
}
Demo3:
子线程不断发送图片的偏移量,主线程中(根据图片位置)设置使图片偏移
public class MainActivity extends Activity {
private ImageView ivShow = null;
private float x, y;
//错误:这样声明falgX为false,flagY为true
// private boolean flagX , flagY = true;
private boolean flagX = true;//标志图片是否往上走
private boolean flagY = true;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
if (x > 400) {
flagX = false;
} else if (x < 10) {
flagX = true;
}
if (flagX) {
x += msg.arg1;
} else {
x -= msg.arg1;
}
if (flagY) {
flagY = false;
y += msg.arg2;
} else {
flagY = true;
y -= msg.arg2;
}
ivShow.setX(x);
//在这里,y方向的正方向为向下,所以y += msg.arg2后,setY(y)向下移动
ivShow.setY(y);
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
ivShow = (ImageView) findViewById(R.id.ivShow);
//在onAttachedToWindow()方法之前,ImageView都没有显示在屏幕上,所以getX()为0
/**
* onAttachedToWindow()方法,将控件显示在界面上
*/
// x = ivShow.getX();
// y = ivShow.getY();
}
public void play(View v) {
//获得ivShow离父容器左边缘距离
x = ivShow.getX();
y = ivShow.getY();
new Thread() {
public void run() {
while (!Thread.interrupted()) {
// Message msg = handler.obtainMessage();
Message msg = Message.obtain();
msg.arg1 = 10;
msg.arg2 = 50;
msg.what = 1;
handler.sendMessage(msg);
//生成100到600之间的随机数
SystemClock.sleep(new Random().nextInt(500)+100);
}
};
}.start();
}
}
Demo4:
设置一个页面,每一秒切换一张图片同时中间有秒倒计时
public class MainActivity extends Activity {
private TextView txtShow = null;
private ImageView ivShow = null;
private List<Drawable> list = null;
private boolean flag = true;
private int index = 0;
private int remain = 60;
private Handler clockHandler = new Handler();
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0:
ivShow.setImageDrawable(list.get(index++));
if (index == list.size()) {
index = 0;
}
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
setData();
switchImage();
setTime();
}
private void setTime() {
new Thread() {
public void run() {
/**
* 通过handler的post方法将Runnable对象发送到消息队列中
* 该Runnable将附加在当前handler定义的线程中即主线程中执行
* 此处如果使用的handler为设置图片的handler,则设置图片与设置时间会有先后(添加在一个队列中)
*/
clockHandler.post(new Runnable() {
@Override
public void run() {
remain--;
if (remain < 0) {
flag = false;
txtShow.setText("还看");
} else {
txtShow.setText("remain:" + remain);
}
/**
* handler的postDelayed(Runnable,delay)方法,
* 将此Runnable对象发送到消息队列中,延时delay时间后run
*/
clockHandler.postDelayed(this, 1000);
}
});
};
}.start();
}
private void switchImage() {
new Thread() {
public void run() {
while (flag) {
Message msg = Message.obtain();
handler.sendEmptyMessage(0);
SystemClock.sleep(1000);
}
};
}.start();
}
private void setData() {
// getResources().obtainTypedArray()根据普通数组资源名称获取实际普通数组
// 获得资源文件中TypeArray对象
TypedArray typedArray = getResources().obtainTypedArray(
R.array.arraysImgs);
list = new ArrayList<Drawable>();
for (int i = 0; i < typedArray.length(); i++) {
list.add(typedArray.getDrawable(i));
}
}
private void initView() {
txtShow = (TextView) findViewById(R.id.txtShow);
ivShow = (ImageView) findViewById(R.id.ivShow);
}
@Override
public 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;
}
}