AsyncTask详解

来源:互联网 发布:国家信息中心软件评测中心 编辑:程序博客网 时间:2024/05/03 12:14
AsyncTask是Android 1.5 Cubake加入的用于实现异步操作的一个类,在此之前只能用Java SE库中的Thread来实现多线程异步,AsyncTask是Android平台自己的异步工具,融入了Android平台的特性,让异步操作更加的安全,方便和实用。实质上它也是对Java SE库中Thread的一个封装,加上了平台相关的特性,所以对于所有的多线程异步都强烈推荐使用AsyncTask,因为它考虑,也融入了Android平台的特性,更加的安全和高效。AsyncTask可以方便的执行异步操作(doInBackground),又能方便的与主线程进行通信,它本身又有良好的封装性,可以进行取消操作(cancel())。这个实例用AsyncTask到网络上下载图片,同时显示进度,下载完图片更新UI。
public class AsyncTaskDemoActivity extends Activity {  
    private static final String ImageUrl = "http://s1.pan.bdstatic.com/static/images/new/multiterminal.jpg?r=201308085508?t=201303150000";         
    private ProgressBar mProgressBar;  
    private ImageView mImageView;  
    private Button mGetImage;  
    private Button mAbort;  
      
    @Override  
    public void onCreate(Bundle icicle) {  
    super.onCreate(icicle);  
    setContentView(R.layout.async_task_demo_activity);  
    mProgressBar = (ProgressBar) findViewById(R.id.async_task_progress);  
    mImageView = (ImageView) findViewById(R.id.async_task_displayer);  
    final ImageLoader loader = new ImageLoader();  
    mGetImage = (Button) findViewById(R.id.async_task_get_image);  
    mGetImage.setOnClickListener(new View.OnClickListener() {  
        public void onClick(View v) {  
        loader.execute(ImageUrl);  
        }  
    });  
    mAbort = (Button) findViewById(R.id.asyc_task_abort);  
    mAbort.setOnClickListener(new View.OnClickListener() {  
        public void onClick(View v) {  
        loader.cancel(true);  
        }  
    });  
    mAbort.setEnabled(false);  
    }        
    private class ImageLoader extends AsyncTask<String, Integer, Bitmap> {  
    private static final String TAG = "ImageLoader";  
  
    @Override  
    protected void onPreExecute() {  
        mGetImage.setEnabled(false);  
        mAbort.setEnabled(true);  
        mProgressBar.setVisibility(View.VISIBLE);  
        mProgressBar.setProgress(0);  
        mImageView.setImageResource(R.drawable.icon);  
    }  
      
    @Override  
    protected Bitmap doInBackground(String... url) {  
        //最核心的操作
        try {  
        URL mUrl;  
        HttpURLConnection conn = null;  
        InputStream in = null;  
        OutputStream out = null;  
        final String filename = "local_temp_image";  
        try {  
            mUrl = new URL(url[0]);  
            conn = (HttpURLConnection) mUrl.openConnection();  
            conn.setDoInput(true);  
            conn.setDoOutput(false);  
            conn.setConnectTimeout(20 * 1000);  
            in = conn.getInputStream();  
            out = openFileOutput(filename, Context.MODE_PRIVATE);  
            byte[] buf = new byte[8196];  
            int seg = 0;  
            final long total = conn.getContentLength();  

            long current = 0;             

            while (!isCancelled() && (seg = in.read(buf)) != -1) {  
            out.write(buf, 0, seg);  
            current += seg;  
            int progress = (int) ((float) current / (float) total * 100f);  
            publishProgress(progress);  
            SystemClock.sleep(1000);  
            }  
        } finally {  
            if (conn != null) {  
            conn.disconnect();  
            }  
            if (in != null) {  
            in.close();  
            }  
            if (out != null) {  
            out.close();  
            }  
        }  
           return BitmapFactory.decodeFile(getFileStreamPath(filename).getAbsolutePath());  
        } catch (MalformedURLException e) {  
           e.printStackTrace();  
        } catch (IOException e) {  
           e.printStackTrace();  
        }  
          return null;  
    }  
    @Override  
    protected void onProgressUpdate(Integer... progress) {  
        mProgressBar.setProgress(progress[0]);  
    }  
      
    @Override  
    protected void onPostExecute(Bitmap image) {  
        if (image != null) {  
        mImageView.setImageBitmap(image);  
        }  
        mProgressBar.setProgress(100);  
        mProgressBar.setVisibility(View.GONE);  
        mAbort.setEnabled(false);  
    }  
    }  
}  
总结:注意事项;
1. AsyncTask对象不可重复使用,也就是说一个AsyncTask对象只能execute()一次,否则会有异常抛出"java.lang.IllegalStateException: Cannot execute task: the task is already running"
2. 在doInBackground()中要检查isCancelled()的返回值,如果你的异步任务是可以取消的话。
cancel()仅仅是给AsyncTask对象设置了一个标识位,当调用了cancel()后,发生的事情只有:AsyncTask对象的标识位变了,和doInBackground()执行完成后,onPostExecute()不会被回调了,而doInBackground()和onProgressUpdate()还是会继续执行直到doInBackground()结束。所以要在doInBackground()中不断的检查isCancellled()的返回值,当其返回true时就停止执行,特别是有循环的时候。如上面的例子,如果把读取数据的isCancelled()检查去掉,图片还是会下载,进度也一直会走,只是最后图片不会放到UI上(因为onPostExecute()没被回调)!
这里其实很好理解,想想Java SE的Thread吧,是没有方法将其直接Cacncel掉的,那些线程取消也无非就是给线程设置标识位,然后在run()方法中不断的检查标识而已。
3. 如果要在应用程序中使用网络,一定不要忘记在AndroidManifest中声明INTERNET权限,否则会报出很诡异的异常信息,比如上面的例子,如果把INTERNET权限拿掉会抛出"UnknownHostException"。刚开始很疑惑,因为模拟器是可以正常上网的,后来Google了下才发现原来是没权限,但是疑问还是没有消除,既然没有声明网络权限,为什么不直接提示无网络权限呢?
对比Java SE的Thread

Thread是非常原始的类,它只有一个run()方法,一旦开始,无法停止,它仅适合于一个非常独立的异步任务,也即不需要与主线程交互,对于其他情况,比如需要取消或与主线程交互,都需添加额外的代码来实现,并且还要注意同步的问题。而AsyncTask是封装好了的,可以直接拿来用,如果你仅执行独立的异步任务,可以仅实现doInBackground()。所以,当有一个非常独立的任务时,可以考虑使用Thread,其他时候,尽可能的用AsyncTask

Volley的使用:

http://www.cnblogs.com/lee0oo0/archive/2013/10/28/3392035.html

热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 9岁儿童发烧38度怎么办 5儿童发烧38度怎么办 咳嗽了20多天怎么办 嘴角烂了怎么办涂什么药 感冒发烧到39度怎么办 6岁宝宝发烧头痛怎么办 生完孩子耻骨疼怎么办 顺产底下外阴红肿伤口流脓怎么办 产后便秘怎么办什么方法最有效 一周岁宝宝拉肚怎么办 三岁宝宝拉水怎么办 喝了过期的青汁怎么办 吃了黑心的苹果怎么办 新生儿两天没拉大便怎么办 贝亲奶瓶不漏怎么办 满月婴儿吃多了怎么办 婴儿吃撑了哭闹怎么办 新生儿吃撑了怎么办啊 新生儿吃了奶粉不吃奶怎么办 新生儿不吃奶也不吃奶粉怎么办 奶瓶吸奶费力不顺畅怎么办 宝宝吃奶粉太勤怎么办 香蕉和地瓜一起吃了怎么办 贝亲奶瓶泡沫多怎么办 四个多月的宝宝拉肚子怎么办 宝宝四个月了拉肚子怎么办 四个月宝宝火大怎么办 刚出生的宝宝便秘怎么办 小宝宝破腹产吸了几口羊水怎么办 换奶粉不拉屎了怎么办 婴儿吃奶粉不拉屎怎么办 1岁半突然不喝奶怎么办 6个月宝宝不吃奶粉怎么办 7个月宝宝不吃奶粉怎么办 5个月宝宝不吃奶粉怎么办 一岁两个月宝宝不长肉怎么办 7个月宝宝肚子疼怎么办 奶喝一半凉了怎么办 5个月孩子厌奶怎么办 怀孕后特别不爱吃水果怎么办 宝宝吃了无比滴怎么办