异步任务处理---AsyncTask

今天学习了AsyncTask的基本用法,现在进行一个总结:
首先要知道为什么异步任务:

1、Android单线程模型
2、 耗时的操作要放在非主线程中进行,避免主线程堵塞

其次要知道AsyncTask的作用:

1、在子线程中更新UI
2、封装、简化异步操作

接下来看下AsyncTask的基本用法:
由于AsyncTask是一个抽象类,所以如果我们想使用它,就必须创建一个子类去继承它,在继承时我们必须为AsyncTask类指定三个泛型参数,如果传入Void,则表示不传入参数

1、Params:在执行时传入要传入的参数,可用于在后台任务中使用
2、Progress:后台任务执行时,如果需要在界面上显示当前的进度,则使用指定的泛型作为进度单位
3、当任务执行执行完毕后,如果需要对结果进行返回,使用这里指定的泛型作为返回值类型

然后我们需要构建AsyncTask子类的回调方法:

  1. onPrexecute()执行后台操作前调用,一般执行初始化操作,在doInBackground方法前执行
  2. doInBackground(Params…)必须重写,在这里执行异步任务;耗时操作写在这里,可调用publishProgress(Progress…)方法返回当前的执行进度
  3. onProgressUpdate(Progress…)当在doInBackground调用doInBackground()后很快被调用对UI操作,这个可以不写(没有在doInBackground中调用)
  4. onPostExecute(Result):当doInBackground方法结束执行,系统自动调用该方法,接收的值就是doInBackground最后返回的值;

说下使用AsyncTask的注意事项

1、必须在UI线程中创建AsyncTask实例
2、必须在UI线程中调用AsyncTask的execute()方法
3、重写的四个方法是系统自动调用的,不要手动去调用
4、每个AsyncTask只能被执行一次,多次调用将会引发异常

下面开始实例:使用AsyncTask加载图片
首选我们创建布局:image.xml用于显示图片IMageView和加载进度ProgressBar

<?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"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <ProgressBar
        android:id="@+id/progrssBar"
        android:visibility="gone"
        android:layout_centerInParent="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>

新建活动ImageTest

package com.asynctask.css.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;//手动导入
import java.io.InputStream;
import java.net.URLConnection;

/**
 * Created by css on 2016/3/28.
 */
public class ImageTest extends Activity {

    private ImageView mImageView;
    private ProgressBar mProgressBar;
    MyAsynvTask mtask;

    //定义静态的String类型的URL用于存储要加载图片的地址
    private static String URL = "http://pic.mmfile.net/2013/08/1315595G7-2.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.progrssBar);

        //当调用execute之后,进行异步操作
        mtask = new MyAsynvTask();
        mtask.execute(URL);

    }
//    新建内部类MyAsynvTask继承AsyncTask,设置传递进去的参数,
//    1、第一个参数表示加载图片的地址,所以传入String,
//    2、第二个参数表示不需要显示返回进度,使用Void,
//    3、第三个参数表示最后返回Bitmap
    class MyAsynvTask extends AsyncTask<String,Void,Bitmap>
    {
//      1、系统调用该方法,对异步操作进行初始化操作,这里显示ProgressBar
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            mProgressBar.setVisibility(View.VISIBLE);
        }

//      2、开始真正的异步操作处理,都在子线程中处理,放置任意的耗时操作,最后返回指定的类型
        @Override
        protected Bitmap doInBackground(String... params) {
            String url = params[0];//可以传递不止一个参数进来,以数组的形式存在,取出对应的URL
            Bitmap bitmap = null;

            URLConnection connection ;  //定义网络连接对象
            InputStream is;             //用于获取数据的输入流
            //访问网络的费时操作
            try {
                connection = new URL(url).openConnection(); //此处需要手动导入URL包,获取网络连接对象
                is = connection.getInputStream();           //获取输入流
                BufferedInputStream bis = new BufferedInputStream(is);
                //加入睡眠时间,晚点执行
//                try {
//                    Thread.sleep(3000);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
                //使用BitmapFactory的decodeStream方法可以很方便的把bis输入流转换为Bitmap
                bitmap = BitmapFactory.decodeStream(bis);
                is.close();//关闭输入流
                bis.close();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            //将bitmap作为返回值传递到onPostExecute中,在onPostExecute进行UI更新
            return bitmap;
        }



//      3、运行在主线程,任意进行UI操作onPostExecute在本方法中操作UI,把图像设置到ImageView
        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            mProgressBar.setVisibility(View.GONE);  //隐藏ProgressBar
            mImageView.setImageBitmap(bitmap);      //显示图片
        }
    }
}

写完活动之后立马注册活动,养成好习惯;

<activity android:name=".ImageTest"></activity>

最后在主活动里面点击Button实现加载图片,剩下的点击Button就省略了,很简单。
看下运行效果:
1、MainActivity主界面

主界面

2、加载过程中ProgressBar显示界面

加载界面

3、加载成功图片显示界面

这里写图片描述

最后说下AsyncTask的取消:
AsyncTaskc是通过线程池执行的,如果前面的线程没有执行完,再去点击开启一个新的线程的时候就会出现空白,即新线程并没有执行,而是等待上一个线程执行完之后才开始执行的;那么怎么解决这个问题呢?
需要通过让AsyncTask的声明周期和activity的声明周期保持一致,在activity的onpause方法中加入如下代码:

  @Override
    protected void onPause() {
        super.onPause();
        if (mTask != null && mTask.getStatus() == AsyncTask.Status.RUNNING)
        {
            //cancel方法只是将AsyncTask标记为cancel状态,并不是真正的取消线程的执行
            mTask.cancel(true);
        }
    }

仅仅写这些事不够的,因为.cancel方法只是对该线程进行标示,并没有取消该线程,还要加上下面的代码

 if(isCancelled())
 {
     break;
 }

具体的参考代码,下载地址:AsyncTask小例子

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值