浅析android中AsyncTask

作用

android是单线程模型。如果在UI主线程中执行耗时操作。可能导致ANR(应用无响应)。系统就会弹出一个ANR对话框。用户选择等待或者离开应用
注意:ANR出现场景:


  1. 主线程被IO操作(4.0以后主线程中不允许进行网络IO操作)阻塞。
  2. 主线程中进行耗时的操作。
  3. 主线程中进行错的操作,如Thread.wait Thread.sleep
    Android系统会监视应用响应情况:如果应用在5秒内没有响应用户输入事件(如按键或者触摸)或者Broadcase Receiver在10秒内未完成相关的处理都会弹出ANR。

如何避免:
  • 基本的思路就是将IO操作在工作线程来处理,减少其他耗时操作和错误操作
  • 使用AsyncTask处理耗时IO操作。
  • 使用Thread或者HandlerThread时,调用Process.setThreadPriority
    (Process.THREAD_PRIORITY_BACKGROUND)设置优先级,否则仍然会降低程序响应,因为默认Thread的优先级和主线程相同。
  • 使用Handler处理工作线程结果,而不是使用Thread.wait()或者Thread.sleep()来阻塞主线程。
  • Activity的onCreate和onResume回调中尽量避免耗时的代码
  • BroadcastReceiver中onReceive代码也要尽量减少耗时,建议使用IntentService处理。

AsyncTask

android中可以使用Handler和AsyncTask来实现异步机制。
Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更新
AsyncTask是抽象类。开发者需要继承后使用。
继承AsyncTask 时需要给AsyncTask指定三个类型。

  • params 任务启动时候传递的参数。即调用execute()时,传递的参数。
  • progress 该参数是在doInbackground()函数中调用publishProgress()将进程执行的值传递给doProgressUpdate()函数做参数。
  • result 是doInbackground()返回的值得类型。该函数返回的值会传递给doPostExecute()函数。进行任务完成后的处理。

继承AsyncTask必须要重写doInbackground()。在该函数中具体执行异步任务。
- doPreExecute()(在函数doInbackground()执行之前调用做一些准备工作)
- doPostExecute()(在函数doInbackground()执行之后进行相关的处理。并且doInbackground()的返回值会传递给该函数做参数)
- doProgressUpdate()()(在doInbackground()函数中调用publishProgress()后该函数被调用,将进程执行的值通过publishProgress()传递给doProgressUpdate()函数做参数)

public class MainActivity extends Activity {
   private ImageView imageView;
    private ProgressBar progressBar;
    public static String        url="https://img3.doubanio.com/lpic/s28385426.jpg";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView=(ImageView)findViewById(R.id.iamgeview);
        progressBar=(ProgressBar)findViewById(R.id.progress);
        new MyAsyncTask().execute(url);
    }
    //注意三个参数,分别是execute(url)函数传入参数的类型,progress的返回值,protected Bitmap doInBackground的返回值
    class MyAsyncTask extends AsyncTask<String,Void,Bitmap>{
        @Override
        protected Bitmap doInBackground(String... params) {
            //取出参数
            String url=params[0];
            Bitmap bitmap=null;
            InputStream is=null;
            try {
                URLConnection urlc=new URL(url).openConnection();
                is=urlc.getInputStream();
                BufferedInputStream bis=new BufferedInputStream(is);
                bitmap= BitmapFactory.decodeStream(bis)
                is.close();
                bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            return bitmap;
        }
        @Override
        protected void onProgressUpdate(Void... values) {
            super.onProgressUpdate(values);
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            //任务执行前进度条设为visible。
            progressBar.setVisibility(View.VISIBLE);

        }
        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            //任务执行完返回下载的图片,进度条隐藏,在子线程中更新界面
            progressBar.setVisibility(View.GONE);
            imageView.setImageBitmap(bitmap);
        }
    }

}

AsyncTask取消

public class MainActivity extends Activity {
    private ProgressBar progressBar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        progressBar=(ProgressBar)findViewById(R.id.progress);
        new MyAsyncTask().execute();
    }
    class MyAsyncTask extends AsyncTask<Void,Integer,Void>{
        @Override
        protected Void doInBackground(Void... params) {
            for(int i=0;i<100;i++)
            {
                publishProgress(i);
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            //更新progressbar
            progressBar.setMax(100);
            progressBar.setProgress(values[0]);
        }
    }

}

该代码段运行会出现这种问题:第一次打开应用正常执行。progressbar未更新完然后按返回键。再次打开应用时,应用会等上一个线程执行完然后才会执行下一个任务。所以看到,等一会progressbar才开始更新(等上一次执行时打开的线程执行完成)
所以避免这种情况可以让任务执行的生命周期和activity相关联

public class MainActivity extends Activity {
    private ProgressBar progressBar;
    private MyAsyncTask myAsyncTask;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        progressBar=(ProgressBar)findViewById(R.id.progress);
        myAsyncTask=new MyAsyncTask();
        myAsyncTask.execute();
    }

    @Override
    protected void onStop() {
        super.onStop();
        if(myAsyncTask!=null&&myAsyncTask.getStatus()==AsyncTask.Status.RUNNING)
        //cancel()方法只是设置AsyncTask为cancel状态,并没有停止线程的执行。所在doInbackground()中判断如果AsyncTask为cancel状态就停止循环
        {
            myAsyncTask.cancel(true);
        }
    }

    class MyAsyncTask extends AsyncTask<Void,Integer,Void>{
        @Override
        protected Void doInBackground(Void... params) {
            for(int i=0;i<100;i++)
            {
                if(isCancelled())
                {
                    break;
                }
                publishProgress(i);

                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            progressBar.setMax(100);
            progressBar.setProgress(values[0]);
        }
    }

}

总结

  • AsyncTask只能在UI线程中创建和执行execute()
  • 重写的AsycTask只能由系统自动调用,不可手动调用
  • 一个AsynTask只能被执行一次,多次执行可能会出现问题。如上面的例子。
  • AsyncTask的本质是一个静态的线程池,AsyncTask派生出的子类可以实现不同的异步任务,这些任务都是提交到静态的线程池中执行。
  • 当任务状态改变之后,工作线程会向UI线程发送消息,AsyncTask内部的InternalHandler响应这些消息,并调用相关的回调函数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值