您的位置:首页 > 移动开发 > Android开发

Android:异步调用详解

2013-10-31 13:55 363 查看
在实际应用中经常会遇到比较耗时任务的处理,比如网络连接,数据库操作等情况时,如果这些操作都是放在主线程(UI线程)中,则会造成UI的假死现象,Android中可以使用AsyncTask和Handler两种异步方式来解决这种问题。

AsyncTask:

android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.

使用的优点:

简单,快捷,过程可控

使用的缺点:

在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.

在使用AsyncTask时处理类需要继承AsyncTask,提供三个泛型参数,并且重载AsyncTask的四个方法(至少重载一个)。

三个泛型参数:

1.Param 任务执行器需要的数据类型

2.Progress 后台计算中使用的进度单位数据类型

3.Result 后台计算返回结果的数据类型

在设置参数时通常是这样的:String... params,这表示方法可以有0个或多个此类型参数;有时参数可以设置为不使用,用Void...即可。

四个方法:

1.onPreExecute() 执行预处理,它运行于UI线程,可以为后台任务做一些准备工作,比如绘制一个进度条控件。

2.doInBackground(Params...) 后台进程执行的具体计算在这里实现,doInBackground(Params...)是AsyncTask的关键,此方法必须重载。在这个方法内可以使用publishProgress(Progress...)改变当前的进度值。

3.onProgressUpdate(Progress...) 运行于UI线程。如果在doInBackground(Params...) 中使用了publishProgress(Progress...),就会触发这个方法。在这里可以对进度条控件根据进度值做出具体的响应。

4.onPostExecute(Result) 运行于UI线程,可以对后台任务的结果做出处理,结果就是doInBackground(Params...)的返回值。此方法也要经常重载,如果Result为null表明后台任务没有完成(被取消或者出现异常)。

异步任务类代码:

[java]
view plaincopyprint?

// AsyncTask异步方式下载图片 class DownImageTask extends AsyncTask<String, Integer, Bitmap> { // 执行预处理 @Override protected void onPreExecute() { super.onPreExecute(); // 显示进度条 progressBar.setVisibility(View.VISIBLE); progressBar.setMax(100); } // 后台进程的执行 @Override protected Bitmap doInBackground(String... params) { try { URL url = new URL(params[0]); HttpURLConnection conn = (HttpURLConnection) url .openConnection(); InputStream inputStream = conn.getInputStream(); bitmap = BitmapFactory.decodeStream(inputStream); // 进度条的更新,我这边只是用一个循环来示范,在实际应用中要使用已下载文件的大小和文件总大小的比例来更新 for (int i = 1; i <= 10; i++) { publishProgress(i * 10); Thread.sleep(200); } inputStream.close(); } catch (Exception e) { e.printStackTrace(); } return bitmap; } // 运行于UI线程,对后台任务的结果做出处理,doInBackground方法执行的结果作为此方法的参数 @Override protected void onPostExecute(Bitmap result) { super.onPostExecute(result); ImageView imageView = (ImageView) findViewById(R.id.image); imageView.setImageBitmap(result); progressBar.setVisibility(View.GONE); } // 运行于UI线程,如果在doInBackground(Params...)中使用了publishProgress(Progress...),就会触发此方法 @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); progressBar.setProgress(values[0]); } }

// AsyncTask异步方式下载图片
class DownImageTask extends AsyncTask<String, Integer, Bitmap> {
// 执行预处理
@Override
protected void onPreExecute() {
super.onPreExecute();
// 显示进度条
progressBar.setVisibility(View.VISIBLE);
progressBar.setMax(100);
}
// 后台进程的执行
@Override
protected Bitmap doInBackground(String... params) {
try {
URL url = new URL(params[0]);
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
InputStream inputStream = conn.getInputStream();
bitmap = BitmapFactory.decodeStream(inputStream);
// 进度条的更新,我这边只是用一个循环来示范,在实际应用中要使用已下载文件的大小和文件总大小的比例来更新
for (int i = 1; i <= 10; i++) {
publishProgress(i * 10);
Thread.sleep(200);
}
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
// 运行于UI线程,对后台任务的结果做出处理,doInBackground方法执行的结果作为此方法的参数
@Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
ImageView imageView = (ImageView) findViewById(R.id.image);
imageView.setImageBitmap(result);
progressBar.setVisibility(View.GONE);
}
// 运行于UI线程,如果在doInBackground(Params...)中使用了publishProgress(Progress...),就会触发此方法
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
progressBar.setProgress(values[0]);
}
}


调用代码:

[java]
view plaincopyprint?

public class MainActivity extends Activity { private Button button; private ProgressBar progressBar; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); button = (Button)findViewById(R.id.button); progressBar = (ProgressBar)findViewById(R.id.progressBar); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { ProgressBarAsyncTask asyncTask = new DownImageTask(); asyncTask.execute("http://www.baidu.com/img/baidu_jgylogo3.gif"); } }); }

public class MainActivity extends Activity {
private Button button;
private ProgressBar progressBar;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

button = (Button)findViewById(R.id.button);
progressBar = (ProgressBar)findViewById(R.id.progressBar);

button.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
ProgressBarAsyncTask asyncTask = new DownImageTask();
asyncTask.execute("http://www.baidu.com/img/baidu_jgylogo3.gif");
}
});
}


Handler:

Handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程中)

两个作用:

安排消息或Runnable 在某个主线程中某个地方执行

安排一个动作在不同的线程中执行

Handler中分发消息的方法:

post(Runnable)

postAtTime(Runnable,long)

postDelayed(Runnable,long)

sendEmptyMessage(int)

sendMessage(Message)

sendMessageAtTime(Message,long)

sendMessageDelayed(Message,long)

*以上post开头的方法在主线程中调用。

*以上send开头的方法在其它线程中调用。

示例代码:

[java]
view plaincopyprint?

public class HandlerTestActivity extends Activity {

private Button start;

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.handlertest);
start = (Button) findViewById(R.id.start);
start.setOnClickListener(new startListener());

System.out.println("Activity Thread:" + Thread.currentThread().getId());
}

Handler handler = new Handler(){

@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
if (msg.what == 1) {
//成功,做一些操作
} else {
//失败,..
}
}

};
Runnable thread = new Runnable() {

@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("HandlerThread:" + Thread.currentThread().getId());
//Message message = new Message();
//message.what = 1;

//handler.sendMessage(message);

}
};

class startListener implements OnClickListener {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub

handler.post(thread);
//Thread t = new Thread(thread);
//t.start();
}
}

}

public class HandlerTestActivity extends Activity {

private Button start;

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.handlertest);
start = (Button) findViewById(R.id.start);
start.setOnClickListener(new startListener());

System.out.println("Activity Thread:" + Thread.currentThread().getId());
}

Handler  handler = new Handler(){

@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
if (msg.what == 1) {
//成功,做一些操作
} else {
//失败,..
}
}

};
Runnable thread  = new Runnable() {

@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("HandlerThread:" + Thread.currentThread().getId());
//Message message = new Message();
//message.what = 1;
//handler.sendMessage(message);

}
};

class startListener implements OnClickListener {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
handler.post(thread);
//Thread t = new Thread(thread);
//t.start();
}
}

}


这个程序看上去似乎实现了Handler的异步机制, handler.post(thread)似乎实现了新启线程的作用,不过通过执行我们发现,两个线程的ID相同!也就是说,实际上thread还是原来 的主线程,由此可见,handler.post()方法并未真正新建线程,只是在原线程上执行而已,我们并未实现异步机制。将startListener改写成如下代码就可以实现异步:

[java]
view plaincopyprint?

class startListener implements OnClickListener { @Override public void onClick(View v) { // TODO Auto-generated method stub //handler.post(thread); Thread t = new Thread(thread); t.start(); } }

class startListener implements OnClickListener {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
//handler.post(thread);
Thread t = new Thread(thread);
t.start();
}
}


将runnable放到新创建的线程中执行,这样就实现了异步调用,如果需要在调用完成后通知或修改主线程,需要在Runnable类的run方法中调用handler.sendMessage(message)

[java]
view plaincopyprint?

@Override
public void run() {
// TODO Auto-generated method stub

System.out.println("HandlerThread:" + Thread.currentThread().getId());
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
}

@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("HandlerThread:" + Thread.currentThread().getId());
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: