android中的耗时操作需要放在子线程中去执行

asynctask是对Handler和和线程池的封装,直接使用比THread效率更加的高效因为封装了线程池,比我们每次直接new Thread效率更高
 

需要注意的是onPreExecute在主线程中执行,一般用来显示提示视图

doInBackground在分线程中执行,完成任务的主要工作

onPostExecute在doInBackGround()执行完成在主线程中执行,用来更新界面

publishProgress 在子线程中发布当前的进度,进度发布之后就会触发主线程调用onProgressUpdate函数被调用

现在我们来做一个简单的测试用例

我们通过asynTask下下载一个apk

首先我们先搭建一个apk的下载环境

我们在自己的电脑下载一个tomacat,启动tomacat ,把需要下载的apk放置在tomacat的root目录下

E:\apache-tomcat-6.0.45-windows-x64\apache-tomcat-6.0.45-windows-x64\apache-tomcat-6.0.45\webapps\ROOT

我们让手机和当前的电脑在同一个局域网内

package im.weiyuan.com.myasynctask;

import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.SystemClock;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast; import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL; public class MainActivity extends AppCompatActivity { Button btn_main_down;
private File apkFile;
private ProgressDialog dialog; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("123456","onCreate is called");
btn_main_down = (Button) findViewById(R.id.btn_main_down);
btn_main_down.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MyAsyncTask task = new MyAsyncTask();
/**
* 自己电脑上的apk的下载地址
* * **/
task.execute("http://10.12.8.8:8080/EncryptCardManager.apk");
}
}); } public class MyAsyncTask extends AsyncTask<String,Integer,String>{ /**
* 在主线程中进行初始化视图的操作
* */
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.e("123456:", "onPreExecute is called:");
dialog = new ProgressDialog(MainActivity.this);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.show(); //准备用于保存APK文件的File对象 : /storage/sdcard/Android/package_name/files/xxx.apk
apkFile = new File(getExternalFilesDir(null), "update.apk");
} /****
* 分线程中进行联网操作,下载apk
* */
@Override
protected String doInBackground(String... params) {
try {
Log.e("123456:", "doInBackground is called:"+params[0]);
//1. 得到连接对象
String path = params[0];
URL url = new URL(path);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
//2. 设置
//connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
connection.setReadTimeout(10000);
//3. 连接
connection.connect();
//4. 请求并得到响应码200
int responseCode = connection.getResponseCode();
if(responseCode==200) {
//设置dialog的最大进度
dialog.setMax(connection.getContentLength()); //5. 得到包含APK文件数据的InputStream
InputStream is = connection.getInputStream();
//6. 创建指向apkFile的FileOutputStream
FileOutputStream fos = new FileOutputStream(apkFile);
//7. 边读边写
byte[] buffer = new byte[1024];
int len = -1;
while((len=is.read(buffer))!=-1) {
fos.write(buffer, 0, len);
//8. 显示下载进度
//dialog.incrementProgressBy(len);
//在分线程中, 发布当前进度
publishProgress(len); //休息一会(模拟网速慢)
//Thread.sleep(50);
SystemClock.sleep(10);
} fos.close();
is.close();
}
//9. 下载完成, 关闭, 进入3)
connection.disconnect();
} catch (Exception e) {
e.printStackTrace();
Log.e("123456 exception:",e.getMessage());
return e.getMessage();
}
return "apk download sucess";
}
/**
* 在主线程中更新进度条
* */ @Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
dialog.incrementProgressBy(values[0]);
} /***
* apk下载完成,在主线程中关闭进度条
* */
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
dialog.dismiss();
if("apk download sucess".equalsIgnoreCase(s)){
Toast.makeText(MainActivity.this,"apk 下载成功",Toast.LENGTH_LONG).show();
installAPK();
}else {
Toast.makeText(MainActivity.this,"apk下载失败"+s,Toast.LENGTH_LONG).show();
} }
} /**
* 启动安装APK
*/
private void installAPK() {
Intent intent = new Intent("android.intent.action.INSTALL_PACKAGE");
intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
startActivity(intent);
} }

总结下:在去背景世联面试的时候,就问题到了我这个问题

asynTask最大的优点是,子线程执行完成后可以把线程执行完成后的结果通过给主线程

2、接下来我们有这样的一个需求,当如果doInBackgroud执行的任务必须在10秒之内执行完成,如果10秒之内没有执行完成,我们就取消任务

如何达到该需求了AsyncTask提供了一个get函数,该函数值阻塞的,如果放在UI线程中会阻塞UI

package im.weiyuan.com.myasynctask;

import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.SystemClock;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast; import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; public class MainActivity extends AppCompatActivity { Button btn_main_down;
private File apkFile;
private ProgressDialog dialog;
private MyAsyncTask task; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
task = new MyAsyncTask();
Log.i("123456","onCreate is called");
btn_main_down = (Button) findViewById(R.id.btn_main_down);
btn_main_down.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) { /**
* 自己电脑上的apk的下载地址
* * **/
task.execute("http://10.12.8.8:8080/EncryptCardManager.apk");
}
}); new Thread(new Runnable() {
@Override
public void run() {
try {
task.get(10000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
/****
*
* 如果doInBackGround代码执行的时间超过10秒就会抛出这个异常
* */
e.printStackTrace();
Log.d("123456","TimeoutException"); /**
* 调用cancel函数取消正在执行的doInBackGround任务,这个时候正在执行的任务被取消,就给抛出异常
*
* doInBackGround任务被取消,不会在调用onPostExecute方法
*
* 调用cancel在主线程就会调用onCancelled方法
* **/
task.cancel(true);
}
}
}).start(); } public class MyAsyncTask extends AsyncTask<String,Integer,String>{ /**
* 在主线程中进行初始化视图的操作
* */
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.e("123456:", "onPreExecute is called:");
dialog = new ProgressDialog(MainActivity.this);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setCancelable(false);
dialog.show(); //准备用于保存APK文件的File对象 : /storage/sdcard/Android/package_name/files/xxx.apk
apkFile = new File(getExternalFilesDir(null), "update.apk");
} /****
* 分线程中进行联网操作,下载apk
* */
@Override
protected String doInBackground(String... params) {
try {
Log.e("123456:", "doInBackground is called:"+params[0]);
//1. 得到连接对象
String path = params[0];
URL url = new URL(path);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
//2. 设置
//connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
connection.setReadTimeout(10000);
//3. 连接
connection.connect();
//4. 请求并得到响应码200
int responseCode = connection.getResponseCode();
if(responseCode==200) {
//设置dialog的最大进度
dialog.setMax(connection.getContentLength()); //5. 得到包含APK文件数据的InputStream
InputStream is = connection.getInputStream();
//6. 创建指向apkFile的FileOutputStream
FileOutputStream fos = new FileOutputStream(apkFile);
//7. 边读边写
byte[] buffer = new byte[1024];
int len = -1;
while((len=is.read(buffer))!=-1) {
fos.write(buffer, 0, len);
//8. 显示下载进度
//dialog.incrementProgressBy(len);
//在分线程中, 发布当前进度
publishProgress(len); //休息一会(模拟网速慢)
//Thread.sleep(50);
SystemClock.sleep(10);
} fos.close();
is.close();
}
//9. 下载完成, 关闭, 进入3)
connection.disconnect();
} catch (Exception e) {
e.printStackTrace();
Log.e("123456 doInBack exce:",e.getMessage());
return e.getMessage();
}
return "apk download sucess";
}
/**
* 在主线程中更新进度条
* */ @Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
dialog.incrementProgressBy(values[0]);
} /***
* apk下载完成,在主线程中关闭进度条
* */
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Log.e("123456:", "onPostExecute is called:");
dialog.dismiss();
if("apk download sucess".equalsIgnoreCase(s)){
Toast.makeText(MainActivity.this,"apk 下载成功",Toast.LENGTH_LONG).show();
installAPK();
}else {
Toast.makeText(MainActivity.this,"apk下载失败"+s,Toast.LENGTH_LONG).show();
} } /**
* 在主线程中执行
* 当异步任务被取消的时候调用
*
* */
@Override
protected void onCancelled() {
super.onCancelled();
Log.e("123456:", "onCancelled is called:");
if(dialog.isShowing()){
dialog.dismiss();
}
}
} /**
* 启动安装APK
*/
private void installAPK() {
Intent intent = new Intent("android.intent.action.INSTALL_PACKAGE");
intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
startActivity(intent);
} }

我们来看程序的打印:

07-26 17:18:50.100 7094-7094/im.weiyuan.com.myasynctask E/123456:: onPreExecute is called:
07-26 17:18:50.162 7094-7537/im.weiyuan.com.myasynctask E/123456:: doInBackground is called:http://10.12.8.8:8080/EncryptCardManager.apk
07-26 17:18:57.253 7094-7132/im.weiyuan.com.myasynctask D/123456: TimeoutException
07-26 17:18:57.265 7094-7537/im.weiyuan.com.myasynctask E/123456 doInBack exce:: thread interrupted
07-26 17:18:57.266 7094-7094/im.weiyuan.com.myasynctask E/123456:: onCancelled is called:

点击界面开始下载apk,首先在主线程中执行onPreExecute 函数,为了避免主线程被阻塞,我们开启了一个线程执行asyntask的get方法,设置的时间是10秒

然后在子线程中开始执行doInBackground 下载apk,当下载apk的任务超过10秒后,get方法抛出一个TimeoutException异常,我们此时调用asyntask的cancle方法取消doInBackground 的任务,doInBackground 的正在执行的任务被取消,抛出异常thread interrupted

当异步任务被取消的时候 onCancelled方法被调用打印onCancelled is called,这个时候

onPostExecute方法是不会被调用的。
相当的经典。

android异步任务asyncTask详细分析的更多相关文章

  1. Android备注26.Android异步任务(AsyncTask)

    转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空) 一.引言     我们知道Android的UI线程主要负责处理用户的按键事件.用户触屏事件及屏幕画 ...

  2. [Android Pro] Android签名与认证详细分析之二(CERT.RSA剖析)

    转载自: http://www.thinksaas.cn/group/topic/335449/ http://blog.csdn.net/u010571535/article/details/899 ...

  3. Android异步任务AsyncTask

    package com.example.asynctask; import java.net.MalformedURLException; import java.net.URL; import an ...

  4. android关于AndroidManifest.xml详细分析

    http://my.eoe.cn/1087692/archive/5927.html 一.关于AndroidManifest.xmlAndroidManifest.xml 是每个android程序中必 ...

  5. Android 异步任务——AsyncTask (附使用AsyncTask下载图片Demo)

    我们编程的时候经常需要处理同步任务和异步任务,在Android里面存在一个特性,就是UI线程是不安全的线程.所谓UI线程不安全也就是我们的主线程(进程启动的第一个线程)不能在线程外操作主线程的资源.因 ...

  6. android:异步任务asyncTask介绍及异步任务下载图片(带进度条)

    为什么要用异步任务? 在android中仅仅有在主线程才干对ui进行更新操作.而其他线程不能直接对ui进行操作 android本身是一个多线程的操作系统,我们不能把全部的操作都放在主线程中操作 .比方 ...

  7. 031 Android 异步任务(AsyncTask)

    1.介绍 AsyncTask(了解即可),重点掌握Handler+Thread 2.实现方法 3.执行步骤 4.java后台 package com.lucky.test36asynctask; im ...

  8. [Android Pro] Android签名与认证详细分析之一(CERT.RSA剖析)

    转载自:http://www.thinksaas.cn/group/topic/335450/ 一.Android签名概述 我们已经知道的是:Android对每一个Apk文件都会进行签名,在Apk文件 ...

  9. Android Scroller类的详细分析

    尊重原创作者,转载请注明出处: http://blog.csdn.net/gemmem/article/details/7321910 Scroller这个类理解起来有一定的困难,刚开始接触Scrol ...

随机推荐

  1. Java IO(七)ByteArrayInputStream 和 ByteArrayOutputStream

    Java IO(七)ByteArrayInputStream 和 ByteArrayOutputStream 一.介绍 ByteArrayInputStream 和 ByteArrayOutputSt ...

  2. 看了这篇,我确定你已经彻底搞懂Java的继承了

    遇到认真的读者是作者的一种幸运,真的,上一篇接口推送后,有好几个读者留言说,"二哥,你有一处内容需要修正,应该是接口中不能有 private 和 protected 修饰的方法." ...

  3. debug PHP程序(xdebug、IntelliJ IDEA)

    之前写PHP程序的都是echo调试,今天感觉太麻烦了就想起研究一下IntelliJ IDEA如何调试PHP程序. 从网上查找了很多资料,大部分都提到在IDE里开启服务,一下就懵了,怎么启这么多服务呢. ...

  4. 最小生成树——Prim算法理解

    背景:本文是在小甲鱼数据结构教学视频中的代码的基础上,添加详细注释而完成的.该段代码并不完整,仅摘录了核心算法部分,结合自己的思考,谈谈理解. Prim算法理解: 如图(摘录自小甲鱼教学视频中的图片) ...

  5. Rocket - util - Repeater

    https://mp.weixin.qq.com/s/xyEq3DgYuf2QuNjssv8pkA   简单介绍Repeater的实现.   ​​   1. 基本功能   A Repeater pas ...

  6. Rocket - util - AsyncQueue

    https://mp.weixin.qq.com/s/6McbqOKM4fu4J5vdpZvxKw   简单介绍异步队列(AsyncQueue)的实现.   ​​ 0. 异步队列   异步队列的两端分 ...

  7. Java实现 LeetCode 810 黑板异或游戏 (分析)

    810. 黑板异或游戏 一个黑板上写着一个非负整数数组 nums[i] .小红和小明轮流从黑板上擦掉一个数字,小红先手.如果擦除一个数字后,剩余的所有数字按位异或运算得出的结果等于 0 的话,当前玩家 ...

  8. Java实现 LeetCode 766 托普利茨矩阵(暴力)

    766. 托普利茨矩阵 如果一个矩阵的每一方向由左上到右下的对角线上具有相同元素,那么这个矩阵是托普利茨矩阵. 给定一个 M x N 的矩阵,当且仅当它是托普利茨矩阵时返回 True. 示例 1: 输 ...

  9. Java实现蓝桥杯历届真题国王的遗产

    国王的遗产 题目描述 X国是个小国.国王K有6个儿子.在临终前,K国王立下遗嘱:国王的一批牛作为遗产要分给他的6个儿子. 其中,大儿子分1/4,二儿子1/5,三儿子1/6,- 直到小儿子分1/9. 牛 ...

  10. Java实现第八届蓝桥杯取数位

    取数位 求1个整数的第k位数字有很多种方法. 以下的方法就是一种. 还有一个答案:f(x/10,k--) public class Main { static int len(int x){ // 返 ...