Android:异步调用详解
来源:互联网 发布:grub2手动引导ubuntu 编辑:程序博客网 时间:2024/05/01 07:31
在实际应用中经常会遇到比较耗时任务的处理,比如网络连接,数据库操作等情况时,如果这些操作都是放在主线程(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表明后台任务没有完成(被取消或者出现异常)。
异步任务类代码:
- // 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> {// 执行预处理@Overrideprotected void onPreExecute() {super.onPreExecute();// 显示进度条progressBar.setVisibility(View.VISIBLE);progressBar.setMax(100);}// 后台进程的执行@Overrideprotected 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方法执行的结果作为此方法的参数@Overrideprotected 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...),就会触发此方法@Overrideprotected void onProgressUpdate(Integer... values) {super.onProgressUpdate(values);progressBar.setProgress(values[0]);}}
调用代码:
- 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开头的方法在其它线程中调用。
示例代码:
- 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改写成如下代码就可以实现异步:
- 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)
- @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);}
- Android:异步调用详解
- Android:异步调用详解
- android 异步调用
- C# Winform异步调用详解
- C# Winform异步调用详解
- C# Winform异步调用详解
- Android UI线程异步调用
- Android 异步链式调用设计
- Android 异步链式调用设计
- android AsyncTask异步调用方法
- C#异步调用四大方法详解
- C#异步调用四大方法详解
- C#异步调用四大方法详解
- C#异步调用四大方法详解
- C#异步调用四大方法详解
- C#异步调用四大方法详解
- C#异步调用四大方法详解
- C#异步调用四大方法详解
- UITableView的头 headView
- C/C++随机数生成 rand() srand()
- ASCII 码
- js 递归 返回
- sqlserver脚本时间计算
- Android:异步调用详解
- 怎样才能检测到链表中循环
- 装机工具软件收藏
- I2C协议指东
- android 上传图片
- UITableView分割线样式与颜色
- 【记录】cygwin下折腾个人配置环境
- 用C语言获取任意文件的长度(可能大于2GB)
- Flex中的Bindable的用法