zoukankan      html  css  js  c++  java
  • android异步任务asyncTask详细分析

    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-x64apache-tomcat-6.0.45-windows-x64apache-tomcat-6.0.45webappsROOT

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

    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方法是不会被调用的。
    相当的经典。
  • 相关阅读:
    数组的typedef 和函数的typedef
    函数返回值当左值的问题
    C++中虚析构函数的作用
    word2013密钥
    子类父类步长问题
    函数重定义——重写———重载
    C++的成员初始化列表和构造函数体(以前未知)
    常引用
    项目开发中的字符串模型
    指针函数的++(极易犯错误)
  • 原文地址:https://www.cnblogs.com/kebibuluan/p/7240858.html
Copyright © 2011-2022 走看看