AsyncTask基础(笔记)

安卓异步任务 ---AsyncTask

为什么要异步任务:

1.Android单线程模型

2.耗时操作放在非主线程中执行

AsyncTask为何而生

1.子线程中更新UI

2.封装,简化异步操作

构造AsyncTask子类的参数

AsyncTask<Params, Progress, Result>是一个抽象类,通常用于被继承,继承AsyncTask需要指定如下三个泛型参数:

Params: 启动任务时输入的参数的类型,也就是execute()方法中,传入的参数

Progress: 后台任务执行中返回进度值的类型,进度更新时用到

Result 后台执行任务完成后返回结果的类型,如果后台是从网络上获取一张图片,那么就返回Bitmap类型

构建AsyncTask子类的回调方法

(插入知识:什么是回调函数)你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。(转自知乎 作者:常溪玲)

doInBackground  必须重写,异步执行后台线程将要完成的任务

onPreExecute   执行后台耗时操作前被调用,通常用户完成一些初始化操作

onPostExecute  当doInBackground()完成后,系统会自动调用,并将doInBackground方法返回的值传给该方法。

onProgressUpdate 在doInBackground()方法中调用publishProgress()方法更新任务的执行进度后,就会触发该方法。可以很清楚的了解耗时操作的完成进度

函数执行顺序演示代码:

MyAsynTask.java

package com.example.app;

import android.os.AsyncTask;
import android.util.Log;

public class MyAsynTask extends AsyncTask<Void, Void, Void> {

	@Override
	protected Void doInBackground(Void... arg0) {
		// TODO Auto-generated method stub
		Log.d("sr", "doInBackground");
		publishProgress();
		return null;

	}

	@Override
	protected void onPostExecute(Void result) {
		// TODO Auto-generated method stub
		super.onPostExecute(result);
		Log.d("sr", "onPostExecute");
	}

	@Override
	protected void onPreExecute() {
		// TODO Auto-generated method stub
		super.onPreExecute();
		Log.d("sr", "onPreExecute");
	}

	@Override
	protected void onProgressUpdate(Void... values) {
		// TODO Auto-generated method stub
		super.onProgressUpdate(values);
		Log.d("sr", "onProgressUpdate");
	}

}

MainActivity.java

package com.example.app;

import android.os.Bundle;
import android.app.Activity;
import android.app.TaskStackBuilder;
import android.view.Menu;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		MyAsynTask task = new MyAsynTask();
		task.execute();
	}

}

输出结果:

下面是实例演示(加载一张网络图片):

异步线程:下载图像

UI线程:设置图像

还是在原来的工程中:

新建ImageTest.java类,继承Activity,创建OnCreate()方法。新建布局文件image.xml,里面有一个imageView显示图片 和一个进度条

image.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    android:orientation="vertical" >

    <ImageView
        android:id="@+id/image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    <ProgressBar
        android:id="@+id/progressbar"
        android:visibility="gone"
        android:layout_centerInParent="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</RelativeLayout>

ImageTest.java

package com.example.app;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.ProgressBar;

public class ImageTest extends Activity {

	private ImageView mImageView;
	private ProgressBar mProgressBar;
	private static String URL = "http://image.zhaiba.com/2015/7/1/201507011732462088603781.jpg";//网路图片地址

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.image);

		mImageView = (ImageView) findViewById(R.id.image);
		mProgressBar = (ProgressBar)findViewById(R.id.progressbar);
	}

}

接下来创建AsynTask异步处理

在ImageTest.java中创建内部类MyAsyncTask 继承AsyncTask

ImageTest.java

package com.example.app;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;

public class ImageTest extends Activity {

	private ImageView mImageView;
	private ProgressBar mProgressBar;
	private static String URL = "http://image.zhaiba.com/2015/7/1/201507011732462088603781.jpg";//网路图片地址

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.image);

		mImageView = (ImageView) findViewById(R.id.image);
		mProgressBar = (ProgressBar)findViewById(R.id.progressbar);
		//设置传递进去的参数
		new MyAsyncTask().execute(URL);//可以传入一个,或多个参数
	}

	class MyAsyncTask extends AsyncTask<String, Void, Bitmap>
	//第一个参数传入URL,所以是String,第二个参数不需要返回加载的进度,所以设置为Void,第三个值为返回值类型,这里是图片,所以设置为Bitmap
	{

		@Override
		protected void onPreExecute() {
			// TODO Auto-generated method stub
			super.onPreExecute();
			//将隐藏的进度条显示出来,提示用户等待
			mProgressBar.setVisibility(View.VISIBLE);//显示进度条

		}

		@Override
		protected void onPostExecute(Bitmap result) {
			// TODO Auto-generated method stub
			super.onPostExecute(result);
			//操作UI 设置图像
			mProgressBar.setVisibility(View.GONE);
			mImageView.setImageBitmap(result);
		}

		@Override
		protected Bitmap doInBackground(String... params) {//参数为不定长的数组,这是从execute()方法中传入的参数
			// TODO Auto-generated method stub
			//获取传递进来的参数
			String url = params[0];//上面execute方法中传入的参数第一个参数为URL
			Bitmap bitmap = null;
			URLConnection connection;
			InputStream is;
			try {
				connection = new URL(url).openConnection();
				is = connection.getInputStream();//获取输入流
				BufferedInputStream bis = new BufferedInputStream(is);
				//通过decodeStream方法解析输入流
				bitmap = BitmapFactory.decodeStream(bis);//将输入流解析为图像
				is.close();
				bis.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			//将bitmap作为返回值返回后面调用的方法
			return bitmap;//返回图像
		}

	}

}

配置AndroidManifest增加网络权限,声明activity

<uses-permission android:name="android.permission.INTERNET"/>

..............

<activity

android:name=".ImageTest"></activity>

在主页上添加一个按钮,点击,进入ImageTest那个activity

Activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

   <Button
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="Image_Test"
       android:onClick="loadImage"/>

</LinearLayout>

MainActivity.java

package com.example.app;

import android.os.Bundle;
import android.app.Activity;
import android.app.TaskStackBuilder;
import android.content.Intent;
import android.view.Menu;
import android.view.View;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		MyAsynTask task = new MyAsynTask();
		task.execute();
	}

	public void loadImage(View view)
	{
		startActivity(new Intent(this, ImageTest.class));
	}

}

这个例子特别好。

下面的例子就是模拟进度条的更新。

进度条布局progressbar.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    android:orientation="vertical" >
    <ProgressBar
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/pg"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"/>

</RelativeLayout>

创建类ProgressBarTest.java

package com.example.app;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.ProgressBar;

public class ProgressBarTest extends Activity {

	private ProgressBar mProgressBar;
	private MyAsyncTask mTask;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.progressbar);

		mProgressBar = (ProgressBar)findViewById(R.id.pg);
		mTask = new MyAsyncTask();
		mTask.execute();
	}

	class MyAsyncTask extends AsyncTask<Void,Integer, Void> //第二个参数因为要实时的返回进度条的状态,所以要Integer参数
	{

		@Override
		protected Void doInBackground(Void... arg0) {
			// TODO Auto-generated method stub
			//模拟进度更新
			for(int i = 0; i < 100; i ++){
				publishProgress(i); //去调用下面那个onProgressUpdate方法
				try {
					Thread.sleep(300);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			return null;
		}

		@Override
		protected void onProgressUpdate(Integer... values) {
			// TODO Auto-generated method stub
			super.onProgressUpdate(values);
			//获取进度更新值
			mProgressBar.setProgress(values[0]);//当前进度值
		}

	}

}

为主页添加一个测试进度条按钮,设置点击方法后,运行:

可以看到进度条在动态的更新

但是这样存在一个问题,返回后重新加载,再返回后重新加载,发现进度条不发生变化,因为每次返回加载都启动了一个异步任务,当前需要加载时有可能上次的任务还没有执行完,所以当前的进度条不更新。

把任务的生命周期设置为activity一样

在ProgressBarTest.java 中重写onPause()方法

@Override
	protected void onPause() {
		// TODO Auto-generated method stub
		super.onPause();
		if(mTask != null && mTask.getStatus() == AsyncTask.Status.RUNNING){//任务不为空切正在运行
			mTask.cancel(true);
			//cancel方法只是将对应的AsyncTask标记为cancel状态,并不是真正的取消线程的执行
		}
	}

将当前任务设置为cancel状态,然后在doInBackground方法和onProgressUpdate方法中中判断一下

<span style="white-space:pre">		</span>protected Void doInBackground(Void... arg0) {
			// TODO Auto-generated method stub
			//模拟进度更新
			for(int i = 0; i < 100; i ++){
				if(isCancelled())
					break;
				publishProgress(i); //去调用下面那个onProgressUpdate方法
				try {
					Thread.sleep(300);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			return null;
		}

		@Override
		protected void onProgressUpdate(Integer... values) {
			// TODO Auto-generated method stub
			super.onProgressUpdate(values);
			if(isCancelled())
				return ;
			//获取进度更新值
			mProgressBar.setProgress(values[0]);//当前进度值
		}

使用AsyncTask注意事项

必须在UI线程中创建AsyncTask的实例

必须在UI线程中调用AsyncTask的execute()方法

重写的四个方法时系统调用的,不能手动调用

每个AsyncTask只能被调用(execute())一次,多次调用将会引发异常(它的四个方法只有doInBackground是异步处理,不能直接更新UI,其他三个方法可以更新UI。

源代码下载:AsyncTask加载网路图片,模拟进度条的更新

附上网友写的一篇笔记:http://www.cnblogs.com/caobotao/p/5020857.html

时间: 2024-11-09 08:58:18

AsyncTask基础(笔记)的相关文章

java String 类 基础笔记

字符串是一个特殊的对象. 字符串一旦初始化就不可以被改变. String s = "abc";//存放于字符串常量池,产生1个对象 String s1=new String("abc");//堆内存中new创建了一个String对象,产生2个对象 String类中的equals比较字符串中的内容. 常用方法: 一:获取 1.获取字符串中字符的个数(长度):length();方法. 2.根据位置获取字符:charAt(int index); 3.根据字符获取在字符串中

网络基础笔记——OSI七层模型

OSI七层模型 由于整个网络连接的过程相当复杂,包括硬件.软件数据封包与应用程序的互相链接等等.如果想要写一支将联网全部功能都串连在一块的程序,那么当某个小环节出现问题时,整只程序都需要改写.所以我们将整个网络分成数层,每层都有自己独立的功能,而且每层的代码都可以独立撰写,因为相互之间不会干扰.如此一来,当某个小环节出现问题时,只要将该层的代码改写即可.并且这样可以让整个网络层次更加的清晰. 在网络上传输信息就像是一个发包裹的过程,从己方的应用程序开始往第七层的包裹里塞数据,再依次塞到第一层的包

[Java基础笔记]数组

Java基础笔记 定义数组: int[] numbers = new int[100]; //方法一 double[] num = new double[10]; int[][] a = new int[2][5]; 通过new创建的数组,元素默认值为0(0.0) int[] scores = {5,4,33,12,46}; //方法二 int[][] a = { //位数不足,自动补0 {5,3,2,1,6}, {10,12,14,15}, }; 数组特性:存储的都是同类型数据:长度定义后不可

C# 基础笔记(第一篇)

C#基础 概念:.net与c#.net/dontnet:一般指.net framework框架,一种平台,一种技术c#(charp):一种编程语言,可以开发基于.net的应用. *java既是一种技术又是一种编程语言.                           .net都能干什么?开发桌面应用程序   Winforminternet应用程序    Asp.net/webservice C/S:客户机(Client)/服务器模式(Server)B/S:浏览器(Browser)/务器模式(

我的LINUX基础笔记

Linux系统管理      1 Day   2014.5.23 su -name   切换用户passwd 密码   更改密码gnome-terminal    伪CLI   桌面终端程序1.查看内核版本uname -r    2.查看红帽系统版本cat /etc/redhat-rdlease3.查看LINUX标准分发版信息  lsb_release4.查看网卡的IP,MAX       ifconfig                       ifconfig eth 10.0.0.10

Nginx基础笔记

Nginx基础笔记 资源 安装 ubuntu下 编译安装 基本操作 HTTP基本配置 配置说明 配置文件目录结构 配置文件结构 模块 模块化 index模块 Log模块 Real IP模块 Access模块 Rewrite模块 Proxy模块 upstream模块 其他 配置静态化目录 负载均衡 控制页面缓存 nginx的内置变量 nginx小结 资源 资源 Nginx 官网 Nginx 官方下载地址 Nginx最佳实践配置项目 地址 Nginx Configuration wiki 教程 ag

MYSQL基础笔记(三)-表操作基础

数据表的操作 表与字段是密不可分的. 新增数据表 1 Create table [if not exists] 表名( 2 字段名 数据类型, 3 字段名 数据类型, 4 字段n 数据类型 --最后一行不需要加逗号 5 )[表选项]; If not exists:如果表名不存在,那么就创建,否则不执行创建代码,实现检查功能. 表选项:控制表的表现 1.字符集:charset/character 具体字符集:--保证表中数据存储的字符集. 2.校对集:collate 具体校对集: 3.存储引擎:e

REDIS基础笔记

Redis基础笔记 资源链接 简介 简介 安装 五种数据类型及相应命令 1. 字符串类型 2. 散列类型 3. 列表类型 4. 集合类型 5. 有序集合 其他 事务 SORT 生存时间 任务队列 发布/订阅模式 Python中使用Redis 实际实例 管理 其他 资源链接 推荐书籍:<Redis入门指南> 资源列表: redis命令速查command | CMD索引-中文 | CMD树-中文 redis源码github 下载地址redis.io The Little Redis book 入口

php代码审计基础笔记

出处: 九零SEC连接:http://forum.90sec.org/forum.php?mod=viewthread&tid=8059 ---------------------------------------------------------- team:xdsec&90sec author:wilson blog:http://blog.wils0n.cn/ 文章链接:wilson's blog_php代码审计基础笔记[求人气~~] ----------------------

web服务的一些基础笔记

1. MIME(Multipurpose Internet Mail Extension,多用途互联网邮件扩展) 它是SMTP能够传输非文本格式文件的根源,将他引入到HTTP,那么HTTP也可以传输图片声音等非文本格式的文件,所以他也是HTTP可以传输非文本格式文件的根源. 将非文本数据在传输数据前重新编码为文本格式,接收方能够用相反的方式将其重新还原为原来的格式,还能够用相应的程序来打开. 2.flash,Applet(Java中), Flash也是一种变成语言.可以有动态网页. 3.动态网页