指切正题,为何要选择异步加载?
由于UI线程(也可叫主线程)负责处理用户输入事件(TP事件,显示事件等),直接与用户交互,如果UI线程阻塞,直接会影响用户的体验效果,严重的会报ANR错误。所以我们需要把耗时操作移出主线程,在子线程中进行处理。
下面罗列几种实现异步加载的方式。
代码如下
package UseThred;
public class TestThread extends Thread{
public String behavior;
public TestThread(String behavior){
this.behavior = behavior;
}
@Override
public void run() {
System.out.println(behavior);
}
}
实现如下:
package UseThred;
public class UseThread {
public UseThread() {
// TODO Auto-generated constructor stub
}
public static void main(String[] args) {
TestThread thread1 = new TestThread("行为1");
TestThread thread2 = new TestThread("行为2");
}
}
自定义一个类继承Thread类,在run()里面执行耗时操作,start()执行
class TestRunnable implements Runnable {
private String behavior;
public TestRunnable(String behavior) {
this.behavior = behavior;
}
@Override
public void run() {
System.out.println(behavior);
}
}
public class UseThread {
public UseThread() {
// TODO Auto-generated constructor stub
}
public static void main(String[] args) {
TestRunnable runnable1 = new TestRunnable("runnable1");
TestRunnable runnable2 = new TestRunnable("runnable2");
TestRunnable runnable3 = new TestRunnable("runnable3");
Thread t1 = new Thread(runnable1);
Thread t2 = new Thread(runnable1);
Thread t3 = new Thread(runnable1);
t1.start();
t2.start();
t3.start();
}
}
这种方式感觉繁琐一点,自定义类实现Runnable接口,然后加入new Thread,最后start(). 但是java中是单继承方式,需要实际的类进行操作,所以使用实现接口的方式较多一点。
当然我一般选择偷懒:
new Thread(new Runnable() {
@Override
public void run() {
//耗时操作执行
}
}).start();
作为一个Android开发,怎么能忘了Android独有的异步加载方式呢?因为有时候我们需要在子线程能更新UI,这些方式就比较繁琐了。
先说一下Android使用传统Java线程方法异步并更新UI的方法
1.使用runOnUiThread
new Thread() {
public void run() {
// 1.执行耗时操作
runOnUiThread(new Runnable(){
@Override
public void run() {
// 2.更新UI
button_show.setText("refresh");
}
});
}
}.start();
ps: runOnUiThread是Activity的方法,注意引用上下文对象。
2.post或者posrDelay
new Thread() {
public void run() {
// 1.执行耗时操作 postDelay/post
button.post(new Runnable() {
@Override
public void run() {
// 2.UI
button_show.setText("post");
}
});
}
}.start();
3.Handler + Message或者Handler + Thread + Message
简单说就是主线程写一个Handler,子线程中通过handler传递消息。代码如下。
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0:
//拿到数据 ,更新UI
String data = (String)msg.obj;
button.setText(data);
break;
default:
break;
}
}
};
private void setUI() {
new Thread(new Runnable(){
@Override
public void run() {
// 1.进行耗时操作
// 2.传递数据
mHandler.sendEmptyMessage(0);
Message msg =new Message();
msg.obj = "数据";//传送Object;
mHandler.sendMessage(msg);
}
}).start();
}
4.AsyncTask
这是最普遍的用法之一了,无聊的面试官总会问你这个异步加载怎么实现,其实我想回答他,百度,然后CV大法进行面向搜索引擎开发。附上代码吧,也省的我以后百度了。
private class MyTask extends AsyncTask {
//执行后台任务前做一些UI操作
@Override
protected void onPreExecute() {
button.setText("loading...");
}
//执行后台任务(耗时操作),不可在此方法内修改UI
@Override
protected String doInBackground(String... params) {
return null;
}
//更新进度信息
@Override
protected void onProgressUpdate(Integer... progresses) {
progressBar.setProgress(progresses[0]);
button.setText("loading..." + progresses[0] + "%");
}
//执行完后台任务后更新UI
@Override
protected void onPostExecute(String result) {
button.setText(result);
}
//取消执行中的任务时更改UI
@Override
protected void onCancelled() {
button.setText("cancelled");
}
}
下面说几个关于AnsysTask老生长谈的几个注意点:
1.必须在UI线程中创建异步任务的实例。
2.必须在UI线程中调用execute(Params... params)方法。
3.不要手动调用其中继承的方法。
4.不能在doInBackground(Params... params)中更改UI组件的信息。
5.一个任务实例只能执行一次,如果执行第二次将会抛出异常。