您的位置:首页 > 其它

异步消息与AsyncTask机制

2015-05-31 19:10 183 查看
AsyncTask是一个抽象类,主要是对线程间的通信进行了一些包装,提供简易的编程方式使后台线程和UI线程进行通讯,后台线程执行异步任务,并把操作结果通知UO线程
在开发Android移动客户端的时候往往要使用多线程来进行操作,我们通常会将耗时的操作放在单独的线程执行,避免其占用主线程而给用户带来不好的用户体验。但是在子线程中无法去操作主线程(UI 线程),在子线程中操作UI线程会出现错误。因此android提供了一个类Handler来在子线程中来更新UI线程,用发消息的机制更新UI界面,呈现给用户。这样就解决了子线程更新UI的问题。但是费时的任务操作总会启动一些匿名的子线程,太多的子线程给系统带来巨大的负担,随之带来一些性能问题。
因此android提供了一个工具类AsyncTask,顾名思义异步执行任务。这个AsyncTask生来就是处理一些后台的比较耗时的任务,给用户带来良好用户体验的,从编程的语法上显得优雅了许多,不再需要子线程和Handler就可以完成异步操作并且刷新用户界面。
AsyncTask一般被用在短时间的操作中(几秒钟),如果需要让线程保持长时间的运行,推荐使用
java.util.concurrent
pacakge
such as
Executor
,
ThreadPoolExecutor
and
FutureTask
.
AsyncTask定义了3个泛型called
Params
,
Progress
and
Result
和4个步骤called
onPreExecute
,
doInBackground
,
onProgressUpdate
and
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等方法来承接异步消息处理机制
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: