Android中为了保证UI的准确性和稳定性避免多线程同时对UI进行操作而造成UI混乱,在Android中只有UI(主线程)可以对UI进行更新操作,而其他的WorkThread不能直接操作UI,即Android单线程模型。然而Android是一个多线程系统,不可能把所有的操作放在主线程中进行,比如网络操作和读取文件等耗时操作,如果都放在主线程中操作就会造成后面任务的阻塞,Android系统会检测这样的阻塞,当阻塞时间太长系统就会抛出ANR。所以我们把这个耗时操作放在非主线程中执行。对于异步任务我们首先想到的就是通过线程和线程池去实现。幸运的是Android给我们提供了一个封装好的组件AsycTask使用它可以很方便的实现异步任务处理,AsycTask的主要作用就是在子线程中更新UI和封装简化了异步操作。

AsyncTask是一个抽象类,通常用于被继承,继承时需要指定三个泛型参数

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

Progress:  后台任务执行中返回进度值的类型。

Result:  后台执行任务结束后返回结果的类型。

AsyncTasK子类的回调方法

doInBackground:  必须重写异步执行后台线程中将要完成的任务。
onPreExecute:  执行后台耗时操作前被调用,通常用户完成一些初始化操作。
onPostExecute:  当doInBackground()完成后系统会自动调用onPostExecute()方法,并将doInBackground方法返回的值传给该方法。
onProgressUpdate:  在doInBackground()方法中调用publishProgress()方法更新任务的执行进度后就会触发该方法。

实战演练一:查看AsyncTask中回调方法调用的顺序

新建一个MyAsyncTask继承自AsyncTask

package com.davebobo.asynctask;import android.os.AsyncTask;import android.util.Log;/** * Created by DaveBobo on 2016/9/25. */public class MyAsyncTask extends AsyncTask {    @Override    protected Void doInBackground(Void... params) {        Log.d("AsyTask","doInBackground");        publishProgress();        return null;    }    @Override    protected void onPreExecute() {        super.onPreExecute();        Log.d("AsyTask", "onPreExecute");    }    @Override    protected void onPostExecute(Void aVoid) {        super.onPostExecute(aVoid);        Log.d("AsyTask", "onPostExecute");    }    @Override    protected void onProgressUpdate(Void... values) {        super.onProgressUpdate(values);        Log.d("AsyTask", "onProgressUpdate");    }}

MainActivity中调用AsyncTask

package com.davebobo.asynctask;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        MyAsyncTask task = new  MyAsyncTask();        task.execute();    }}
运行模拟器筛选查看
【Android实战之旅 001】AsyncTask异步操作网络请求_第1张图片

AsyncTask中回调方法调用的顺序

onPreExecute-->doInBackground-->onProgressUpdate-->onPostExecute

实战演练二:异步任务处理加载一张网络图片和模拟进度条

过程:异步处理下载图像 ,UI线程设置图像

创建一个ImageTest继承Activity

package com.davebobo.asynctask;import android.app.Activity;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.AsyncTask;import android.os.Bundle;import android.view.View;import android.widget.ImageView;import android.widget.ProgressBar;import java.io.BufferedInputStream;import java.io.IOException;import java.io.InputStream;import java.net.URL;import java.net.URLConnection;/** * Created by DaveBobo on 2016/9/25. */public class ImageTest  extends Activity{    private ImageView mImageView;    private ProgressBar mProgressBar;    private  static String URL =            "http://avatar.csdn.net/3/B/3/1_davebobo.jpg";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.image);        mImageView = (ImageView)findViewById(R.id.image);        mProgressBar = (ProgressBar)findViewById(R.id.progressbar);        new  MyAsyncTask().execute(URL);//设置传递进去的参数    }    class  MyAsyncTask extends AsyncTask{        @Override        protected void onPreExecute() {            super.onPreExecute();            mProgressBar.setVisibility(View.VISIBLE);        }        @Override        protected void onPostExecute(Bitmap bitmap) {            super.onPostExecute(bitmap);            mProgressBar.setVisibility(View.GONE);            mImageView.setImageBitmap(bitmap);        }        @Override        protected Bitmap doInBackground(String... params) {            String url = params[0];//获取传递进来的参数值            Bitmap bitmap = null;            URLConnection connection;//定义网络连接对象            InputStream is;//定义用于获取数据的输入流            try {                connection = new URL(url).openConnection();//获取网络连接对象                is= connection.getInputStream();//获得输入流                BufferedInputStream bis = new BufferedInputStream(is);//封装输入流                Thread.sleep(3000);                bitmap = BitmapFactory.decodeStream(bis);                is.close();                bis.close();//关闭输入流            }catch (IOException e){                e.printStackTrace();            }catch(InterruptedException e){                 e.printStackTrace();            }            return bitmap;        }    }}
MainActivity中调用ImageTest
public void loadImage(View view){        startActivity(new Intent(this, ImageTest.class));    }
运行效果

【Android实战之旅 001】AsyncTask异步操作网络请求_第2张图片


创建一个ProgressBarTest模拟进度条

package com.davebobo.asynctask;import android.app.Activity;import android.os.AsyncTask;import android.os.Bundle;import android.widget.ProgressBar;/** * Created by DaveBobo on 2016/9/25. */public class ProgressBarTest extends Activity{    private ProgressBar mProgressBar;    private MyAsyncTask mTask;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.progressbar);        mProgressBar = (ProgressBar)findViewById(R.id.pg );        mTask = new MyAsyncTask();        mTask.execute();    }    @Override    protected void onPause() {        super.onPause();        if (mTask!=null&&mTask.getStatus() ==AsyncTask.Status.RUNNING){            //cansel方法只是将对应的AsyncTask标记为cancel状态,并不是真正取消线程的执行            //在java中没有办法直接粗暴地停止一个线程,必须等待线程结束            mTask.cancel(true);        }    }    class MyAsyncTask extends AsyncTask{        @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);            if (isCancelled())return;            mProgressBar.setProgress(values[0]);//获取进度更新值        }    }}
运行效果

【Android实战之旅 001】AsyncTask异步操作网络请求_第3张图片

一些总结:

(1)必须在UI线程中创建AsyncTask的实例,必须在UI线程中调用AsyncTask的execute()方法,四个方法是系统自动调用,我们不应手动调用。每个AsyncTask只能被执行一次,多次调用会引发异常。

(2)注意doInBackground()是运行在其他线程,其他方法都是运行在主线程,即其他三个方法可以更新UI,而doInBackground()需要通过onPostExecute()和onProgressUpdate做异步处理。

更多相关文章

  1. 【读书笔记】【Android 开发艺术探索】第11章Android 的线程和线
  2. 〖Android〗简单隐藏Android虚拟键盘的方法
  3. Java Android 线程池
  4. android 引入jni 的so库的方法
  5. Android中自定义SeekBar来控制音量,并与系统音量键的操作保持同步

随机推荐

  1. Android——XML解析
  2. Android中的常见FC及解决方式整理
  3. android 分享 api
  4. Android消息机制 Handler
  5. android 实现由下至上弹出并位于屏幕底部
  6. Android(安卓)GPS状态改变与监听
  7. android 设置静态wifi地址
  8. Android(安卓)软键盘小知识点
  9. android短信发送器源代码
  10. android 客户端 smtp 协议发送数据