今天我们学习了 AsyncTack, 这是一个异步任务。

那么这个异步任务可以干什么呢?

  因为只有UI线程,即主线程可以对控件进行更新操作。好处是保证UI稳定性,避免多线程对UI同时操作。

  同时要把耗时任务放在非主线程中执行,否则会造成阻塞,抛出无响应异常。

那么在Android中实现异步任务机制有两种方式,Handler和AsyncTask。今天主要讲的是 asyncTack.

  我们通过API 来学习下 整个 AsyncTack

1.为什么要异步任务

  • Android单线程模式
  • 耗时操作放在非主线程(UI线程)中执行

  我们都知道Android是单线程模式,只有主线程才能对UI操作,简称UI线程。

  当然这样的好处是:保证UI的稳定性、准确性,避免多线程同时对UI的操作,导致UI的混乱

  但同时Android是一个多线程的操作系统,不可能把全部的事情放在主线程。

  如果任务堵塞,当时间过长,会抛出ANR(Application Not Responding)错误。

  AsyncTask  能够适当的,简单的用于 UI 线程。这个类不需要操作线程(Thread)就可以完成后台操作将结果返回 UI

  异步任务的定义是一个在后台线程上运行,其结果是在UI线程上发布的计算。

2.AsyncTask为何而生

  • 子线程中更新UI
  • 封装、简化异步操作

  结构

    继承关系

      public abstract class AsyncTask extends Object

    java.lang.Object

      android.os.AsyncTask <params,Progress,Result>

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

    Params : 启动任务时输入参数的类型。

    Progress : 后台任务执行中返回进度值的类型(后台人数执行的百分比)

    Result : 后台执行任务完成后返回结果的类型(后台计算的结果类型)

  注:在一个异步任务中,不是所有的类型总被用。假如一个类型不被使用,可以简单地使用void 类型。

4.构建AsyncTask子类的回调方法

  doInBackground :

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

    用于在执行异步任务,不可以更改主线程中UI。

    当后台计算结束时,调用 UI线程。后台计算结果作为一个参数传递到这步。

    所有耗时的代码,写到这里来(数据库、蓝牙、网络服务)

  onPreExecute :

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

    用于在执行异步任务前,主线程做一些准备工作

    被调用后立即执行,一般用来在执行后台任务前对UI做一些标记。

    在UI线程上调用任务后立即执行。这步通常被用于设置任务,例如在用户界面显示一个进度条。

  onPostExecute :

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

    用于异步任务执行完成后,在主线程中执行的操作

    当后台操作结束时,此方法将会被调用,计算结果将做为参数传递到此方法中,直接将结果显示到UI组件上。

    当后台计算结束时,调用 UI线程。后台计算结果作为一个参数传递到这步。

  onProgressUpdate :

    在doInBackground() 方法调用publishProgress() 方法更新任务的执行进度后,就会触发该方法。

    用于更新异步执行中,在主线程中处理异步任务的执行信息

    此方法被执行,直接将进度信息更新到UI组件上。

    后台线程执行onPreExecute()完后立即调用,这步被用于执行较长时间的后台计算。异步任务的参数也被传到这步。

    计算的结果必须在这步返回,将传回到上一步。在执行过程中可以调用publishProgress(Progress...)来更新任务的进度。

在使用的时候,有几点需要格外注意:

  1.异步任务的实例必须在UI线程中创建。

  2.execute(Params... params)方法必须在UI线程中调用。

  3.不要手动调用onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values),onPostExecute(Result result)这几个方法。

  4.不能在doInBackground(Params... params)中更改UI组件的信息。

  5.一个任务实例只能执行一次,如果执行第二次将会抛出异常。

接下来,我们来看看如何使用AsyncTask执行异步任务操作,我们先建立一个项目,结构如下:

结构相对简单一些,让我们先看看MainActivity.java的代码:

package com.example.multithreadind01;

import java.util.ArrayList;
import java.util.List; import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast; public class MainActivity extends Activity { private String fromDb_str1 = "";
private Button btn;
private Button btn2;
private TextView tv;
private ListView lv;
private BaseAdapter adapter;
private List<User> userList = new ArrayList<User>();
private MyTask mt; protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); // 模拟数据访问产生数据
for (int i = 0; i < 5; i++) {
User u = new User();
u.setUsername("模拟" + i);
u.setSex("女" + i);
userList.add(u);
} tv = (TextView) findViewById(R.id.textView1);
btn = (Button) findViewById(R.id.button1);
btn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// 注意:
// 1 每次需new一个实例,新建的任务只能执行一次,否则会出现异常
// 2 异步任务的实例必须在UI线程中创建
// 3 execute()方法必须在UI线程中调用。
mt = new MyTask(MainActivity.this);
mt.execute(userList, adapter);// 里面的参数是传给 doInBackground }
}); btn2 = (Button) findViewById(R.id.Button2);
btn2.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// 取消一个正在执行的任务,onCancelled()方法将会被调用
mt.cancel(true);
Toast.makeText(getApplicationContext(), "onCancelled()取消", 1)
.show();
}
}); adapter = new BaseAdapter() { public int getCount() {
return userList.size();// listView 循环数量
} public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = MainActivity.this.getLayoutInflater();
View view;
if (convertView == null) {
view = inflater.inflate(R.layout.item, null); // 创建convertView
} else {
view = convertView; // 复用
} TextView tv_username = (TextView) view
.findViewById(R.id.username);
TextView tv_sex = (TextView) view.findViewById(R.id.sex);
tv_username.setText(userList.get(position).getUsername());
tv_sex.setText(userList.get(position).getSex());
return view;
} public Object getItem(int position) {
return null;
} public long getItemId(int position) {
return 0;
}
};
lv = (ListView) findViewById(R.id.listView1);
lv.setAdapter(adapter);
} }

MainActivity.java

MyTask.java的代码:

package com.example.multithreadind01;

import java.util.List;

import android.os.AsyncTask;
import android.widget.BaseAdapter;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast; //构造函数AsyncTask<Params, Progress, Result>参数说明:
//Params 启动任务执行的输入参数
//Progress 后台任务执行的进度
//Result 后台计算结果的类型 public class MyTask extends AsyncTask { private BaseAdapter adapter;
private List<User> userList;
private MainActivity activity;
private ProgressBar progressBar; public MyTask(MainActivity activity) {
this.activity = activity;
} // 1.所有耗时的代码,写到这里来(数据库、蓝牙、网络服务)
// 2.绝对不能碰UI
// doInBackground()方法用于在执行异步任务,不可以更改主线程中UI
protected Object doInBackground(Object... params) { System.out.println("调用doInBackground()方法--->开始执行异步任务");
userList = (List<User>) params[0];
adapter = (BaseAdapter) params[1];
for (int i = 0; i < userList.size(); i++) {
try {
// 为了演示进度,休眠1000毫秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} userList.get(i).setUsername("更改" + i);
userList.get(i).setSex("男" + i);
// publishProgress()为AsyncTask类中的方法
// 常在doInBackground()中调用此方法 用于通知主线程,后台任务的执行情况.
// 此时会触发AsyncTask中的onProgressUpdate()方法
publishProgress(i);
} // userlist,adapter // 返回给前端
return "天气:22度";
} // 准备
// onPreExecute()方法用于在执行异步任务前,主线程做一些准备工作
protected void onPreExecute() {
Toast.makeText(activity, "开始准备", Toast.LENGTH_SHORT).show();
System.out.println("调用onPreExecute()方法--->准备开始执行异步任务");
} // 做完后执行
// onPostExecute()方法用于异步任务执行完成后,在主线程中执行的操作
protected void onPostExecute(Object result) {
String r = result.toString();
TextView tv = (TextView) activity.findViewById(R.id.textView1);
// textView显示请求结果
tv.setText("访问完成!" + r);
System.out.println("调用onPostExecute()方法--->异步任务执行完毕");
} // 分步完成
// onProgressUpdate()方法用于更新异步执行中,在主线程中处理异步任务的执行信息
protected void onProgressUpdate(Object... values) { // 0,1,2,3,4
int bar = Integer.parseInt(values[0].toString());
bar = (bar + 1) * 20;
progressBar = (ProgressBar) activity.findViewById(R.id.progressBar1);
// 更改ProgressBar
progressBar.setProgress(bar);
adapter.notifyDataSetChanged();
System.out.println("调用onProgressUpdate()方法--->更新异步执行中");
} // onCancelled()方法用于异步任务被取消时,在主线程中执行相关的操作
protected void onCancelled() { progressBar = (ProgressBar) activity.findViewById(R.id.ProgressBar2);
// 更改进度条进度为0
progressBar.setProgress(0); System.out.println("调用onCancelled()方法--->异步任务被取消");
} }

MyTask.java

User.java的代码:

package com.example.multithreadind01;

public class User {
private String username;
private String sex;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
} }

User.java

布局文件activity_main.xml代码如下:

<RelativeLayout 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="com.example.multithreadind01.MainActivity" > <TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" /> <ListView
android:id="@+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/button1"
android:layout_marginTop="44dp" >
</ListView> <Button
android:id="@+id/Button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="@+id/listView1"
android:layout_alignTop="@+id/button1"
android:text="取消异步任务" /> <Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/textView1"
android:layout_below="@+id/textView1"
android:layout_marginTop="15dp"
android:text="开始异步任务" /> <ProgressBar
android:id="@+id/progressBar1"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/listView1"
android:layout_alignRight="@+id/button1"
android:layout_below="@+id/button1" /> <ProgressBar
android:id="@+id/ProgressBar2"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/progressBar1"
android:layout_alignLeft="@+id/Button2"
android:layout_alignRight="@+id/Button2"
android:layout_below="@+id/Button2" /> </RelativeLayout>

activity_main.xml

布局文件item.xml代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<TextView
android:id="@+id/username"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="60dp"
android:textSize="45dp"
/> <TextView
android:id="@+id/sex"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="60dp"
android:textSize="45dp"
/>
</LinearLayout>

item.xml

我们来看一下运行时的界面:

以上几个截图分别是初始界面、执行异步任务时界面、执行成功后界面、取消任务后界面。执行成功后,整个过程日志打印如下:

如果我们在执行任务时按下了“取消异步任务”按钮,日志打印如下:

可以看到onCancelled()方法将会被调用,onPostExecute(Result result)方法将不再被调用。

详解Android中AsyncTask的使用: http://blog.csdn.net/liuhe688/article/details/6532519

关于asynctask的取消操作: http://blog.csdn.net/isamu/article/details/9381139

Android中AsyncTask异步的更多相关文章

  1. 详解Android中AsyncTask的使用

    在Android中实现异步任务机制有两种方式,Handler和AsyncTask. Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更 ...

  2. 具体解释Android中AsyncTask的使用

    在Android中实现异步任务机制有两种方式,Handler和AsyncTask. Handler模式须要为每个任务创建一个新的线程,任务完毕后通过Handler实例向UI线程发送消息,完毕界面的更新 ...

  3. Android中AsyncTask的使用

    原文 https://blog.csdn.net/liuhe688/article/details/6532519 在Android中实现异步任务机制有两种方式,Handler和AsyncTask. ...

  4. Android中AsyncTask的使用 (包含文件的下载与存储)

    今天看到大神写的相关详解Android中AsyncTask的使用,真的很是佩服,下面我将学习到的AsynTask知识运用到项目中,其中也涉及一些文件的下载与存储到本地 啥都不说了,直接上代码,我将对其 ...

  5. Android中AsyncTask使用具体解释

    在Android中我们能够通过Thread+Handler实现多线程通信.一种经典的使用场景是:在新线程中进行耗时操作.当任务完毕后通过Handler向主线程发送Message.这样主线程的Handl ...

  6. Android中ListView异步加载图片错位、重复、闪烁问题分析及解决方案

    我们在使用ListView异步加载图片的时候,在快速滑动或者网络不好的情况下,会出现图片错位.重复.闪烁等问题,其实这些问题总结起来就是一个问题,我们需要对这些问题进行ListView的优化. 比如L ...

  7. Android 多线程----AsyncTask异步任务详解

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/3 ...

  8. Android中AsyncTask的简单用法 .

    在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行.在单线程模型中始终要记住两条法则: 1. 不要阻塞UI线程 2. 确保只 ...

  9. android中asynctask的使用实例

    参考此blog写的非常的好http://www.cnblogs.com/devinzhang/archive/2012/02/13/2350070.html MainActivity.java imp ...

随机推荐

  1. hdu 4640 Island and study-sister(状态压缩dp)

    先处理前两个学长到达各个点所需要的最少时间,在计算前两个学长和最后一个学长救出所有学妹的最少时间. #include<stdio.h> #include<string.h> # ...

  2. 关于kali安装vmware的坑,linux套路太深。

    http://www.linuxidc.com/Linux/2015-08/122240.htm 但是还有些坑 安装gcc5.4.1 apt-get install gcc-5 gcc-5所在目录 / ...

  3. ISAP 简介

    刘汝佳的蓝书上已经给出了大部分,先给上完整代码(以草地排水为例). #include<iostream> #include<algorithm> #include<cst ...

  4. 互联网TCP/IP五层模型(一)

    转载自:阮一峰 我们每天使用互联网.你是否想过,它是怎样实现的? 全世界几十亿台电脑,连接在一起,两两通信. 上海的某一块网卡送出信号,洛杉矶的还有一块网卡竟然就收到了.两者实际上根本不知道对方的物理 ...

  5. GiB与GB

    Gibibyte(giga binary byte的缩写)是信息或计算机硬盘存储的一个单位,简称GiB.由来“GiB”.“KiB”.“MiB”等是于1999年由国际电工协会(IEC)拟定了" ...

  6. Qt 学习之路 :访问网络(4)

    前面几章我们了解了如何使用QNetworkAccessManager 访问网络.在此基础上,我们已经实现了一个简单的查看天气的程序.在这个程序中,我们使用QNetworkAccessManager进行 ...

  7. 关于cocostudio加载UI json CCUIHELPER未声明问题

    查看官方的文档,在文档的最后添加了如何加载项目.如下代码: UILayer* ul =UILayer::create(); ul->addWidget(CCUIHELPER->create ...

  8. navigaitonBar的自定义设置

    navigaitonBar的自定义设置 navigationBar介绍: navigationbar就是一个导航视图控制器上面的导航栏. 如何设置这个navigationbar? 首先我们来探讨如何来 ...

  9. wp-content-index文章目录插件使用效果调整

    安装好wp-content-index后进行如下设置: 其中标红处必须标红,用于检索锚点.在文章页面添加如下js代码: $(function() { var wpindex = $("#co ...

  10. 第五章:最后一步准备,1.8的Json模型、状态描述机制详解

    <基于1.8 Forge的Minecraft mod制作经验分享> 1.8的所有纹理材质都需要一个Json来对其描述,这一块感觉是各大神的教程里面涉及最少最浅的,我就斗胆在这分享下我研究了 ...