安卓中在子线成中更新UI会出现错误,为了确保UI显示的正确性,必须统一管理这些更改指令。怎么把子线程中的指令传递到主线程UI中,安卓提供了Handler消息机制。
handler message
void handleMessage(Message msg) handler中的消息处理方法,根据消息的不同做出不同的操作,一般被重写,自己定义消息的内容和操作内容。
final boolean hasMessage(int what)检查消息队列中是否有该消息。
Message obtainMessage()重用消息队列中的消息,第一次会生成一个新的实例。
sendEmptyMessage()发送一个空消息,起始内部还是发送的重用的Message对象,但是并没有指定message的其他内容。
final boolean sendMessge(Message msg)发送一个消息
final boolean sendMessage (Message msg ,long delayMillis)延迟发送message。
其实发送消息只是把他们放在了MessageQueue中,消息获取是Looper的事情。
在Looper的loop方法中有一个无限循环的代码块,他负责不停的从消息队列出取出消息。然后交给相应的handler进行处理。
//继承Handler 重写 handlerMessage方法 自定义对消息的处理方式
class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
//根据自己传进来的消息的变量来识别消息种类 不一定用msg.what
}
}
}
new Thread(new Runnable() {
@Override
public void run() {
//需要处理的操作
//处理完成之后handler发送消息到MessageQueue中
Message msg=handler.obtainMessage();
msg.what=1;
myHandler.sendMessage(msg)
}
}).start();
Message类中一般使用的变量。可以完全把他当成一个简单类型来使用。
public int what;
public int arg1;
public int arg2;
public Object obj;
一个线程内有一个消息队列,一个Looper,可以由多个handler和多个消息。
异步任务AsyncTask
***public abstract class AsyncTask<Params, Progress, Result> 是一个抽象类,params启动任务时候需要传入的参数,progress后台完成任务进度值的类型,result执行任务完成返回值的类型。***
几个主要方法
- doInBackGround(Params…)在后台执行的任务,好比handler系列中子线程内的执行体。
- onProgressUpdate(Progress…)在主线程中运行,相当于handler中handleMessage(msg),比如在方法内设置textView.setText(“文字”)。
- publishProgress(Progress…)完成或完成部分内容向主线程发送消息,相当于handler.sendMessage()。
- onPreExecute 在执行后台操作前调用,做准备工作,比如页面显示进度条等等。
- onPostExecute(result )当线程完成后(doInBackground完成后)自动调用,通知主线程完成。相当于最后一次publishProgress和onProgressUpdate的结合体。
- execute(params…)我们能够调用的方法。参数是我们需要传入线程的内容,与类声明是的类型保持一致。
//一个简单的按钮点击改变按钮文本的示例
//handler message 方法 设置监听器 生成线程示例重写run()方法,线程的执行体,在线程执行完毕后发送消息。
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message msg=myHandler.obtainMessage();
msg.what=1;
msg.obj="返回的文本信息";
myHandler.sendMessage(msg);
}
}).start();
}
});
//handler接受到消息进行识别处理。
private Handler myHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
//
case 1:
mButton.setText(msg.obj.toString());
break;
}
}
};
//AsyncTask 示例
//同样设置监听器 实例化 AsyncTask 启动
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myAsyncTask=new MyAsyncTask();
myAsyncTask.execute();
}
});
//自定义的AsyncTask 因为只是简单任务 所以有些方法可以补充重写
class MyAsyncTask extends AsyncTask<Void,Integer ,String >{
@Override
protected String doInBackground(Void... voids) {
//后台任务执行体
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//一次 或多次向主线程传递消息
publishProgress(100);
return "返回的文本信息";
}
@Override
protected void onPreExecute() {
super.onPreExecute();
//简单任务,不需要前置操作。
}
@Override
protected void onPostExecute(String String) {
super.onPostExecute(String);
//操作完成后 UI操作
mButton.setText(String);
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
//UI操作 耗时任务 进度型任务完成进度
}
}
注意事项:
1.必须在UI线程中创建AsyncTask实例。
2.必须在UI线程中调用exectue()方法。
3.重写的执行任务的方法,有系统负责,我们只需要调用execute方法。
4.每个AsyncTask只能执行一次。
MARK(12)
五色令人目盲,五音令人耳聋,五味令人口爽,驰骋畋猎令人心发狂,难得之货令人行妨。是以圣人 ,为腹不为目,故去彼取此。