AsyncTask基础

 

AsyncTask的基本构成

 

1-1 AsyncTask概述

 

为什么需要使用异步任务?

——Android单线程模式

——耗时操作放在非线程中执行

  我们知道,Android中只有UI线程,也就是主线程才能进行对UI的更新操作,而其他线程是不能直接操作UI的.这样的好处是保证了UI的稳定性和准确性,避免多个线程同时对UI进行操作而造成UI的混乱.但Android是一个多线程的操作系统,我们总不能把所有的任务都放在主线程中进行实现,比如网络操作,文件读取等耗时操作,如果全部放到主线程去执行,就可能会造成后面任务的阻塞.Android会去检测这种阻塞,当阻塞时间太长的时候,就会抛出Application Not Responsed(ANR)错误.所以我们需要将这些耗时操作放在非主线程中去执行.这样既避免了Android的单线程模型,又避免了ANR.

AsyncTask为何而生?

——子线程中更新UI

——封装、简化异步操作

提到异步任务,我们能想到用线程,线程池去实现.确实,Android给我们提供了主线程与其他线程通讯的机制.但同时,Android也给我们提供了一个封装好的组件--AsyncTask.利用AsyncTask,我们可以很方便的实现异步任务处理.AsyncTask可以在子线程中更新UI,也封装简化了异步操作.使用线程,线程池处理异步任务涉及到了线程的同步,管理等问题.而且当线程结束的时候还需要使用Handler去通知主线程来更新UI.而AsyncTask封装了这一切,使得我们可以很方便的在子线程中更新UI.

1-2 AsyncTask基本结构介绍

1. 用处:
将耗时操作放在非主线程中执行,既保证了Android单线程模型,也保证了程序的响应(不出现ANR)
AsyncTask在子线程中更新UI,封装、简化异步操作

2. AsyncTask<Params, Progress, Result>
是一个抽象类,通常用于被继承,继承AsyncTask需要指定如下三个泛型参数:
——Params:启动任务时输入参数的类型
——Progress:后台任务执行中返回进度值的类型
——Result:后台执行任务完成后返回结果的类型
注意:参数不是一定要使用, private class MyTask extends AsyncTask<Void, Void, Void> { ... }

3. 在继承AsyncTask的子类中需要重写的回调方法
onPreExecute()->doInBackground(Params...)->调用publishProgress(Progress...)->onProgressUpdate(Progress...)->doInBackground(Params...)执行结束->onPostExecute(Result)

 

 

MainActivity.java

package com.example.android3_asynctask;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

public class MainActivity extends Activity
{

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MyAsyncTask task = new MyAsyncTask();
        task.execute();
    }

}

MyAsyncTask.java

package com.example.android3_asynctask;

import android.os.AsyncTask;
import android.util.Log;

class MyAsyncTask extends AsyncTask<Void, Void, Void>
{

    @Override
    protected Void doInBackground(Void... arg0)
    {
        // TODO Auto-generated method stub
        Log.i("yzx", "doInBackground");
        publishProgress();
        return null;
    }

    @Override
    protected void onPreExecute()
    {
        // TODO Auto-generated method stub
        Log.i("yzx", "onPreExecute");
        super.onPreExecute();
    }

    @Override
    protected void onPostExecute(Void result)
    {
        // TODO Auto-generated method stub
        Log.i("yzx", "onPostExecute");
        super.onPostExecute(result);
    }

    @Override
    protected void onProgressUpdate(Void... values)
    {
        // TODO Auto-generated method stub
        Log.i("yzx", "onProgressUpdate");
        super.onProgressUpdate(values);
    }
}

在没有加publishProcess();

加publishProcess();

 

AsyncTask的使用示例

onPreExecute() 显示进度条
onPostExcute()隐藏进度条 都可以访问UI线程
mytask.execute(args)中传入的参数就是doInBackground中的参数

在onPreExecute()方法中
mProgressBar.setVisibility(View.VISIBLE);//显示进度条

在onPostExectute(Bitmap bitmap)方法中,参数是doInBackground()方法返回的参数
mProgressBar.setVisibility(View.GONE);//将进度条隐藏
mImageView.setImageBitmap(bitmap);//将图片设置为解析出来的网络图片

然后在onCreate方法中
new MyAsyncTask().execute(URL);//开启AsyncTask的异步线程操作,设置传递进去的

 

网络操作作为不稳定的废时操作,从android 4.0开始就被严禁放入主线程中
通常采用在异步线程处理→下载图像  在UI线程→设置图像

ProgressBar XML属性 visibility="gone"可设置为默认状态下为隐藏

Image.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:padding="16dp"
    android:layout_height="match_parent">
<ImageView
    android:id="@+id/image_a"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
    <ProgressBar
        android:id="@+id/progress_a"
        android:visibility="gone"
        android:layout_centerInParent="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.yzx.android_asynctask.MainActivity">

<Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Image Test"
    android:onClick="loadImage"
    />
</LinearLayout>
Image.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:padding="16dp"
    android:layout_height="match_parent">
<ImageView
    android:id="@+id/image_a"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
    <ProgressBar
        android:id="@+id/progress_a"
        android:visibility="gone"
        android:layout_centerInParent="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>

ImageTest

package com.example.yzx.android_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.net.URL;//导入URL的包
import java.io.InputStream;
import java.net.URLConnection;

/**
 * Created by yangzixing on 2016/3/14.
 */
public class ImageTest  extends Activity {

    private ImageView mImageView;
    private ProgressBar mProgressBar;
    private static String URL="//img-my.csdn.net/uploads/201504/12/1428806103_9476.png";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.image);

        mImageView=(ImageView)findViewById(R.id.image_a);
        mProgressBar= (ProgressBar) findViewById(R.id.progress_a);
        //设置传递进去的参数
        new MyAsyncTask().execute(URL);
    }
    class MyAsyncTask extends AsyncTask<String,Void,Bitmap>{

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            mProgressBar.setVisibility(View.VISIBLE);//显示进度条
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {//操作UI,设置图片
            super.onPostExecute(bitmap);
            mProgressBar.setVisibility(View.GONE);//隐藏进度条
            mImageView.setImageBitmap(bitmap);
        }

        /*
                        String...params------可变长的数组,可以传递不止一个参数进来
                         */
        @Override
        protected Bitmap doInBackground(String... params) {
            //获取传递进来的参数
            String url=params[0];//取出对应url
            Bitmap bitmap=null;
            URLConnection connection;//定义网络连接对象
            InputStream inputStream;//用于获取数据的输入流
            try {
                //获取connection的对象。
                connection=new URL(url).openConnection();
                        //获取输入流
                inputStream=connection.getInputStream();
                BufferedInputStream bis=new BufferedInputStream(inputStream);
                //通过decodeStream将输入流解析成Bitmap
                bitmap= BitmapFactory.decodeStream(bis);
                inputStream.close();
                bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            //将bitmap作为返回值
            return bitmap ;
        }
    }
}

MainActivity

package com.example.yzx.android_asynctask;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

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();
    }

    public void loadImage(View view){
        startActivity(new Intent(this,ImageTest.class));
    }

}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.yzx.android_asynctask">

    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".ImageTest"></activity>
    </application>

</manifest>

 AsyncTask模拟进度条

ProgressBarTest

package com.example.yzx.android_asynctask;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.ProgressBar;

/**
 * Created by yangzixing on 2016/3/14.
 */
public class ProgressBarTest extends Activity {
    private ProgressBar progressBar;
    private MyAsyncTask mTask;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.progressbar);
        progressBar= (ProgressBar) findViewById(R.id.pgb);
        mTask=new MyAsyncTask();
        mTask.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.setProgress(values[0]);
       }
   }

Progressbar.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:padding="16dp"
    android:layout_height="match_parent">


    <ProgressBar
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/pgb"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true" />
</RelativeLayout>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:layout_height="match_parent"
    tools:context="com.example.yzx.android_asynctask.MainActivity">

<Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Image Test"
    android:onClick="loadImage"
    />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="ProgressBar Test"
        android:onClick="loadProgress"
        />
</LinearLayout>

MainActivity

package com.example.yzx.android_asynctask;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

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();
    }

    public void loadImage(View view){
        startActivity(new Intent(this, ImageTest.class));
    }
    public void loadProgress(View view){
        startActivity(new Intent(this,ProgressBarTest.class));
    }

}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.yzx.android_asynctask">

    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".ImageTest"></activity>
        <activity android:name=".ProgressBarTest"></activity>
    </application>

</manifest>

 

如何取消AsyncTask

当在上一次进度条没有完全满的时候返回,再次点击Progress Test没有反应,因为上一次返回的进度条得满的时候才开始进度。

解决方法:让AsyncTask的生命周期与Activity的生命周期保持一致

AsyncTask.cancel(true)只是使该异步线程标识cancle,用户在任何地方都不能粗暴地直接结束一个线程,因此需要在线程的执行过程中去检测isCancled()标识

package com.example.yzx.android_asynctask;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.ProgressBar;

/**
 * Created by yangzixing on 2016/3/14.
 */
public class ProgressBarTest extends Activity {
    private ProgressBar progressBar;
    private MyAsyncTask mTask;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.progressbar);
        progressBar= (ProgressBar) findViewById(R.id.pgb);
        mTask=new MyAsyncTask();
        mTask.execute();
    }

    @Override
    protected void onPause() {
        super.onPause();
        //mTask不为空且是running的状态,这仅是发送请求
        if(mTask!=null && mTask.getStatus()==AsyncTask.Status.RUNNING){
            //cancel方法只是将对应的AsyncTask标记为cancel状态,并不是真正的取消
            mTask.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);
           if(isCancelled()){
               return;
           }
           progressBar.setProgress(values[0]);
       }
   }
}
总结

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

只有doInbackground的方法是在其他线程执行,不能执行UI操作,
其他方法可以对UI执行操作更新UI.

 

posted @ 2016-03-14 16:55  沉默的羊癫疯  阅读(110)  评论(0编辑  收藏  举报