博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
android异步任务asyncTask详细分析
阅读量:7114 次
发布时间:2019-06-28

本文共 13002 字,大约阅读时间需要 43 分钟。

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
{ /** * 在主线程中进行初始化视图的操作 * */ @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
{ /** * 在主线程中进行初始化视图的操作 * */ @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方法是不会被调用的。 相当的经典。

 

 

转载于:https://www.cnblogs.com/kebibuluan/p/7240858.html

你可能感兴趣的文章
NAS数据迁移初探
查看>>
打破医院围墙 数字化平台之上的想象力
查看>>
Teradata首席分析官Bill Franks:数据分析变革犹如一场工业革命
查看>>
Linux下安装并使用Java开发opencv的配置
查看>>
AdTime: DMC量身定制的企业数据分析师
查看>>
《数字逻辑设计与计算机组成》一2.3 规范表达式
查看>>
借道大数据 互联网基金再探“蓝海”
查看>>
浙江医疗综合体获批 医疗资源也可共享
查看>>
3G/4G调制解调器曝漏洞:可致设备被完全控制
查看>>
你知道你的Mac摄像头正在偷窥你吗?这款工具或许能帮你
查看>>
超干货!一套完整的设计分析思路应该是怎样的?
查看>>
关于视频流的各种问题,后续整理
查看>>
从零开始,我的上云路
查看>>
MySQL修改密码和加密
查看>>
批处理文件之间的相互调用问题
查看>>
Servlet的Listener的使用
查看>>
Handler学习小结
查看>>
Kettle定时执行
查看>>
泛函编程(14)-try to map them all
查看>>
使用meta实现页面的定时刷新或跳转
查看>>