异步消息与AsyncTask机制
2015-05-31 19:10
183 查看
AsyncTask是一个抽象类,主要是对线程间的通信进行了一些包装,提供简易的编程方式使后台线程和UI线程进行通讯,后台线程执行异步任务,并把操作结果通知UO线程
在开发Android移动客户端的时候往往要使用多线程来进行操作,我们通常会将耗时的操作放在单独的线程执行,避免其占用主线程而给用户带来不好的用户体验。但是在子线程中无法去操作主线程(UI 线程),在子线程中操作UI线程会出现错误。因此android提供了一个类Handler来在子线程中来更新UI线程,用发消息的机制更新UI界面,呈现给用户。这样就解决了子线程更新UI的问题。但是费时的任务操作总会启动一些匿名的子线程,太多的子线程给系统带来巨大的负担,随之带来一些性能问题。
因此android提供了一个工具类AsyncTask,顾名思义异步执行任务。这个AsyncTask生来就是处理一些后台的比较耗时的任务,给用户带来良好用户体验的,从编程的语法上显得优雅了许多,不再需要子线程和Handler就可以完成异步操作并且刷新用户界面。
AsyncTask一般被用在短时间的操作中(几秒钟),如果需要让线程保持长时间的运行,推荐使用
such as
AsyncTask定义了3个泛型called
三个泛型参数:
1,Params
执行AsyncTask需要传入的参数,可在后台任务中使用
2,Progress
后台任务执行的时候,若需要在当前界面显示执行的进度,则使用这里的泛型作为进度单位
3,Result
任务执行完,如需要对结果进行返回,则使用这里的泛型作为返回值类型
class DownloadTask extends AsyncTask<Void, Integer, Boolean> {
……
}
四个步骤:
1,onPreExecute
在后台任务开始之前调用,进行一些界面上的初始化操作
2,doInBackground(Params.......)
必须重写,异步执行后台线程将要完成的任务
此方法的所有代码都会在子线程中执行,所以应在此处去处理所有的耗时任务。
任务一旦完成会通过return语句返回任务的执行结果,若AsyncTask的第三个参数是void,则不需要返回
注意此方法中是不可以进行UI操作的,如果需要更新UI元素,如反馈当前任务的执行进度,可以调用publishProgress(Progress...)完成
这些值都会发布在主UI线程上,在下面的onProgressUpdate(Progress....)
3,onProgressUpdate(Progress.....)
在后台调用publishProgress(Progress...)方法后,该方法很快就会被调用,
其携带的参数就是在后台任务中传递过来的
此方法中可以对UI进行操作,利用参数中的数值对界面进行更新
4,onPostExecute(Result)
doInBackground完成后,此方法被调用onPostExecute()方法,并将doInBackground方法返回的值传给该方法
可以利用返回的数据进行一些UI操作
实例1:
需要注意的是Void是一个占位符类,区别于void
实例2:下载网络图片
实例3:模拟进度条显示
但是上面的问题在于如果点了进度条再返回再点击进度条,会发现进度条在处于等待的状态,这是因为程序中是以多线程方式运行,线程池的数量有限,只有等到前面的线程运行完毕后面的才能运行
解决办法就是将进度条的生命周期绑定为和activity的生命周期一致
注意:
-》必须在UI线程中穿件AsyncTask的实例
->必须在UI线程中调用AsyncTask的execute方法
->重写的四个方法是系统调用的,不能手动调用
-》每个AsyncTask只能被执行一次,多次的话就会运行时异常
-》四个方法中doInBackground方法运行在其他线程,而他三个都是在主线程;
其他三个方法都可以更新UI,只有此方法要异步处理
所以doInBackground用onPostExecute和publishProgress等方法来承接异步消息处理机制
在开发Android移动客户端的时候往往要使用多线程来进行操作,我们通常会将耗时的操作放在单独的线程执行,避免其占用主线程而给用户带来不好的用户体验。但是在子线程中无法去操作主线程(UI 线程),在子线程中操作UI线程会出现错误。因此android提供了一个类Handler来在子线程中来更新UI线程,用发消息的机制更新UI界面,呈现给用户。这样就解决了子线程更新UI的问题。但是费时的任务操作总会启动一些匿名的子线程,太多的子线程给系统带来巨大的负担,随之带来一些性能问题。
因此android提供了一个工具类AsyncTask,顾名思义异步执行任务。这个AsyncTask生来就是处理一些后台的比较耗时的任务,给用户带来良好用户体验的,从编程的语法上显得优雅了许多,不再需要子线程和Handler就可以完成异步操作并且刷新用户界面。
AsyncTask一般被用在短时间的操作中(几秒钟),如果需要让线程保持长时间的运行,推荐使用
java.util.concurrentpacakge
such as
Executor,
ThreadPoolExecutorand
FutureTask.
AsyncTask定义了3个泛型called
Params,
Progressand
Result和4个步骤called
onPreExecute,
doInBackground,
onProgressUpdateand
onPostExecute
三个泛型参数:
1,Params
执行AsyncTask需要传入的参数,可在后台任务中使用
2,Progress
后台任务执行的时候,若需要在当前界面显示执行的进度,则使用这里的泛型作为进度单位
3,Result
任务执行完,如需要对结果进行返回,则使用这里的泛型作为返回值类型
class DownloadTask extends AsyncTask<Void, Integer, Boolean> {
……
}
四个步骤:
1,onPreExecute
在后台任务开始之前调用,进行一些界面上的初始化操作
2,doInBackground(Params.......)
必须重写,异步执行后台线程将要完成的任务
此方法的所有代码都会在子线程中执行,所以应在此处去处理所有的耗时任务。
任务一旦完成会通过return语句返回任务的执行结果,若AsyncTask的第三个参数是void,则不需要返回
注意此方法中是不可以进行UI操作的,如果需要更新UI元素,如反馈当前任务的执行进度,可以调用publishProgress(Progress...)完成
这些值都会发布在主UI线程上,在下面的onProgressUpdate(Progress....)
3,onProgressUpdate(Progress.....)
在后台调用publishProgress(Progress...)方法后,该方法很快就会被调用,
其携带的参数就是在后台任务中传递过来的
此方法中可以对UI进行操作,利用参数中的数值对界面进行更新
4,onPostExecute(Result)
doInBackground完成后,此方法被调用onPostExecute()方法,并将doInBackground方法返回的值传给该方法
可以利用返回的数据进行一些UI操作
实例1:
需要注意的是Void是一个占位符类,区别于void
public class MyAsyncTask extends AsyncTask<Void ,Void, Void> { @Override protected Void doInBackground(Void... params) { // TODO Auto-generated method stub Log. d("xys" , "doInBackground" ); //只有这样手动调用该方法才会调用onProgressUpdate方法 //发布一个或者多个进度单位 publishProgress(); return null; } @Override protected void onPreExecute() { // TODO Auto-generated method stub super.onPreExecute(); Log. d("xys" , "onPreExecute" ); } @Override //上面的publishProgress被调用了,所以此法才回被调用 // 该方法由UI线程在publishProgress()方法调用完后被调用,一般用于动态地显示一个进度条 protected void onProgressUpdate(Void... values) { // TODO Auto-generated method stub super.onProgressUpdate( values); Log. d("xys" , "onProgressUpdate" ); } @Override //这里的参数是doInBackground的返回值,此处是void所以就没有 // 后台任务执行完之后被调用,在UI线程执行。 protected void onPostExecute(Void result) { // TODO Auto-generated method stub super.onPostExecute( result); Log. d("xys" , "onPostExecute" ); }
实例2:下载网络图片
public class ImageTest extends Activity { private ImageView mImageView; private ProgressBar mProgressBar; private static String URL = "http://y1.ifengimg.com/a/2015_09/1d8401937113fd3.gif" ; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate( savedInstanceState); setContentView(R.layout. image); mImageView = (ImageView) findViewById(R.id. image); mProgressBar = (ProgressBar) findViewById(R.id.ProgressBar ); new MyAsyncTask1().execute( URL); } class MyAsyncTask1 extends AsyncTask<String, Void, Bitmap>{ //线程开始之前 @Override protected void onPreExecute() { // TODO Auto-generated method stub super.onPreExecute(); mProgressBar.setVisibility(View. VISIBLE); } @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(5000); bitmap=BitmapFactory. decodeStream(bis); is.close(); bis.close(); } catch (IOException | InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return bitmap; } @Override protected void onPostExecute(Bitmap result) { // TODO Auto-generated method stub super.onPostExecute( result); mProgressBar.setVisibility(View. GONE); mImageView.setImageBitmap( result); } }
实例3:模拟进度条显示
<ProgressBar android:id= "@+id/progressBar1" style= "?android:attr/progressBarStyleHorizontal" android:layout_width= "match_parent" android:layout_height= "wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" /> public class ProgressBarTest extends Activity { private ProgressBar mprogressBar; private MyAsyncTask2 myAsynctask; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate( savedInstanceState); setContentView(R.layout. progressbar); mprogressBar = (ProgressBar) findViewById(R.id.progressBar1 ); myAsynctask = new MyAsyncTask2(); // 启动 myAsynctask.execute(); } class MyAsyncTask2 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) { // TODO Auto-generated catch block e.printStackTrace(); } } return null; } @Override // i直接作用在values数组上 protected void onProgressUpdate(Integer... values) { // TODO Auto-generated method stub super.onProgressUpdate( values); // 获取进度更新值,只传来一个值 mprogressBar.setProgress( values[0]); } }
但是上面的问题在于如果点了进度条再返回再点击进度条,会发现进度条在处于等待的状态,这是因为程序中是以多线程方式运行,线程池的数量有限,只有等到前面的线程运行完毕后面的才能运行
解决办法就是将进度条的生命周期绑定为和activity的生命周期一致
@Override protected void onPause() { // TODO Auto-generated method stub super.onPause(); if( myAsynctask!= null&& myAsynctask.getStatus()==AsyncTask.Status. RUNNING){ //cancel方法只是将对应的 asynctask标志为cancel状态,并不是真正的取消线程的执行 myAsynctask.cancel( true); } } 然后在下面进行判断 // 模拟进度更新 for ( int i = 0; i < 100; i++) { if(isCancelled()) break; ......... ------------------------------------- @Override // i直接作用在values数组上 protected void onProgressUpdate(Integer... values) { // TODO Auto-generated method stub super.onProgressUpdate( values); if(isCancelled()) return;
注意:
-》必须在UI线程中穿件AsyncTask的实例
->必须在UI线程中调用AsyncTask的execute方法
->重写的四个方法是系统调用的,不能手动调用
-》每个AsyncTask只能被执行一次,多次的话就会运行时异常
-》四个方法中doInBackground方法运行在其他线程,而他三个都是在主线程;
其他三个方法都可以更新UI,只有此方法要异步处理
所以doInBackground用onPostExecute和publishProgress等方法来承接异步消息处理机制
相关文章推荐
- 百度之星 2015 初赛(2) 1005 序列变换
- poj-1947 Rebuilding Roads
- 加密简单原理
- Tip:如果AD用户被删除了,exchange邮箱还存不存在
- 提交spark应用程序spark-submit
- linux下stc89c52及其他国产芯片烧写方案
- ajax_基础
- linux下安装oracle11g详解
- Java NIO 02=====Channel
- 团队飞机大战分配任务——制定软件测试计划
- 将正整数N转换成m(2-16)进制数
- php利用接口实现类的多重继承
- 关于中国产品的质量问题-一个暖水袋引发的思考
- 百度之星 2015 初赛(2) 1003 棋盘占领
- js-定时任务setInterval,setTimeout,clearInterval,clearTimeout
- (转)CSS字体大小: em与px、pt、百分比之间的对比
- 第七课,分支结构程序体验|三个整数输出最大值
- qq聊天机器人 群发工具 (java版) (二)
- MooTools
- 启动Eclipse 弹出Failed to load the JNI shared library 的解决方法