AsyncTask的使用
Posted sq19920518
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AsyncTask的使用相关的知识,希望对你有一定的参考价值。
一、AsyncTask简单介绍
在android中实现异步任务机制有两种方式,Handler和AsyncTask。
Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更新,这种方式对于整个过程的控制比较精细,但也是有缺点的,例如代码相对臃肿,在多个任务同时执行时,不易对线程进行精确的控制。
使用背景
1、开发Android应用时必须遵守单线程模型的原则:
Android UI操作并不是线程安全的,并且这些操作必须在UI线程中执行。
2、单线程模型中始终要记住两条法则:
1). 不要阻塞UI线程 ;
2). 确保只在UI线程中访问Android UI控件。
当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),
主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。
3、Android4.0以上版本中
主线程中不允许访问网络。涉及到网络操作的程序一般都是需要开一个新线程完成网络访问。但是在获得页面数据后,又不能将数据返回到UI界面中 。因为子线程(Worker Thread)不能直接访问UI线程中的成员,也就是说没有办法对UI界面上的内容进行操作,如果操作,将抛出异常:CalledFromWrongThreadException。
其实,android提供了几种在其他线程中访问UI线程的方法:
Activity.runOnUiThread( Runnable )
View.post( Runnable )
View.postDelayed( Runnable, long )
Handler消息传递机制
这些类或方法会使代码很复杂很难理解。为了解决这个问题,Android 1.5提供了一个工具类:AsyncTask,它使创建与用户界面长时间交互运行的任务变得更简单。AsyncTask更轻量级一些,适用于简单的异步处理,原理是线程和Handler的封装。
先看下面代码:
package com.danny_jiang.day07_asynctask_introduce;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
/**
* 案例演示:AsyncTask的使用步骤
* 1 自定义类继承AsyncTask,指定三个泛型
* 2 复写抽象方法doInbackground完成耗时操作,或者其他生命周期方法
* 3 调用AsyncTask.execute方法执行异步任务
*
*/
public class MainActivity extends Activity
private TextView text;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.text);
public void click(View view)
android.util.Log.e("danny", "按钮被点击了!!!");
MyTask task = new MyTask();
task.execute("abc");
/**
* 当继承AsyncTask时,需要指定三个泛型
* 第一个 doInbackground方法的入参类型,也是执行AsyncTask时所需要传入
* 的参数类型(AsyncTask.execute(参数)), 一般是String类型
* 第二个 向用户提示进度信息时使用的参数类型,也就是publishProgress方法的入参类型
* 可以指定为Void类型,说明不需要传参
* 第三个 onPostExecute方法的传参类型,同时也是doInbackground方法的返回值类型
* 一般情况下可以返回byte[]或者String
*
*/
class MyTask extends AsyncTask<String, Void, String>
/**
* 当调用AsyncTask.execute方法之后,此方法立即被调用
* 在主线程中执行,一般做一些准备工作(如UI操作)
*/
@Override
protected void onPreExecute()
super.onPreExecute();
long id = Thread.currentThread().getId();
String name = Thread.currentThread().getName();
android.util.Log.e("TAG", "onPreExecute:" + id + " name is " + name);
/**
* 当onPreExecute方法执行完之后,此方法立即被调用
* 在子线程中完成,一般在此方法中完成耗时操作
* 返回值会被交给onPostExecute方法,进行UI刷新
* (在执行过程中可以调用publishProgress(Progress... values)来更新进度信息)
*/
@Override
protected String doInBackground(String... params)
long id = Thread.currentThread().getId();
String name = Thread.currentThread().getName();
android.util.Log.e("TAG", "doInBackground:" + id + " name is " + name);
for(int i = 0; i < 10; i++)
try
Thread.sleep(1000);
android.util.Log.e("TAG", "任务执行到 " + i);
catch (InterruptedException e)
e.printStackTrace();
return "job finish";
/**
* 当doInbackground方法执行耗时操作之后,此方法会被自动调用
* 入参就是doInbackground的返回值
* 在主线程中执行,可以根据doInbackground返回的数据刷新UI控件
*/
@Override
protected void onPostExecute(String result)
super.onPostExecute(result);
long id = Thread.currentThread().getId();
String name = Thread.currentThread().getName();
android.util.Log.e("TAG", "onPostExecute:" + id + " name is " + name);
text.setText(result);
注意:
1.异步任务的实例必须在UI线程中创建。
2.execute(Params… params)方法必须在UI线程中调用。
3.不要手动调用onPreExecute(),doInBackground(Params…params),onProgressUpdate(Progress… values),onPostExecute(Result result)这几个方法。
4.不能在doInBackground(Params… params)中更改UI组件的信息。
5.一个任务实例只能执行一次,如果执行第二次将会抛出异常。
二、实例演示
package com.danny_jiang.day07_asynctask_progress;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends Activity
private String url = "http://img1.ph.126.net/BmSbVg7ncmVYe4c_pdO77Q=="
+ "/2622783833007290111.png";
private ProgressDialog pd = null;
private ImageView image;
private Button download;
private Button cancle;
private MyTask mTask;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
download = (Button) findViewById(R.id.download);
cancle = (Button) findViewById(R.id.cancle);
image = (ImageView) findViewById(R.id.image);
public void download(View view)
// 注意每次需new一个实例,新建的任务只能执行一次,否则会出现异常
mTask = new MyTask();
mTask.execute(url);
download.setEnabled(false);
cancle.setEnabled(true);
public void cancle(View view)
// 取消一个正在执行的任务,onCancelled方法将会被调用
mTask.cancel(true);
class MyTask extends AsyncTask<String, Integer, byte[]>
// onPreExecute方法用于在执行后台任务前做一些UI操作
@Override
protected void onPreExecute()
super.onPreExecute();
// 创建对话框
pd = new ProgressDialog(MainActivity.this);
// 设置对话框水平样式
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
// 设置titile
pd.setTitle("提示:");
// 设置message
pd.setMessage("Downloading...");
// 显示对话框
pd.show();
// doInBackground方法内部执行后台任务,不可在此方法内修改UI(子线程中执行)
@Override
protected byte[] doInBackground(String... params)
String imageUrl = params[0];
InputStream is = null;
byte[] buffer = new byte[1024];
int len = 0;
// 用来代表所下载图片的总数据
int totalLength = 0;
// 用来代表当前下载的进度
int currentProgress = 0;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
/**
* 以下是真正的网络请求操作
*/
try
URL newUrl = new URL(imageUrl);
HttpURLConnection conn = (HttpURLConnection) newUrl.openConnection();
if (conn != null && conn.getResponseCode() == 200)
// 通过conn获取图片的总数据长度
totalLength = conn.getContentLength();
// 设置进度条最大的进度
pd.setMax(totalLength);
is = conn.getInputStream();
while ((len = is.read(buffer)) != -1)
baos.write(buffer, 0, len);
baos.flush();
// 将当前所读取的进度赋值给currentProgress
currentProgress += len;
// 调用publishProgress公布进度,最后onProgressUpdate方法将被执行
publishProgress(currentProgress);
// 为了演示进度,休眠50毫秒
Thread.sleep(50);
// pd.setProgress(currentProgress);
return baos.toByteArray();
catch (Exception e)
e.printStackTrace();
return null;
// onProgressUpdate方法用于更新进度信息
@Override
protected void onProgressUpdate(Integer... values)
pd.setProgress(values[0]);
// onPostExecute方法用于在执行完后台任务后更新UI,显示结果
@Override
protected void onPostExecute(byte[] result)
super.onPostExecute(result);
Bitmap bm = BitmapFactory.decodeByteArray(result, 0, result.length);
image.setImageBitmap(bm);
// 关闭对话框
if (pd.isShowing())
pd.dismiss();
// onCancelled方法用于在取消执行中的任务时更改UI
@Override
protected void onCancelled()
pd.setProgress(0);
download.setEnabled(true);
cancle.setEnabled(false);
更多介绍见详解AsyncTask
以上是关于AsyncTask的使用的主要内容,如果未能解决你的问题,请参考以下文章