Android-AsyncTask的使用

Android-AsyncTask的使用


AsyncTask是安卓执行UI更新所需要的,因为安卓禁止UI更新在主线程中进行。

处理异步任务

为什么要把UI更新放在子线程中,如果像网络处理,文件读取等这样的耗时操作都放在主线程中进行的话,
那么就会极易造成堵塞,当堵塞时间太长的话,就会抛出异常,也就是我们常见的,XXX无响应,是否关闭XXX?所以我们把这样的操作放在子线程里面,防止堵塞。


三个参数类型

Params:启动任务时的类型,比如String等。。
Progress:任务更新返回的进度值类型。
Result:返回最终结果的对象类型,比如Bitmap。获取网络图片等。


四个方法

doInBackground(Object….object):
必须重写的方法,处理异步任务时的业务逻辑操作,返回一个结果给onPostExecute(Object object)即是此方法接收的参数。

onPreExecute():
首次执行的方法,一般用于初始化,比如进度条的显示。

onPostExecute(Object object):
参数是doInBackground方法返回的结果对象类型,然后再进行UI更新,比如设置图片。

onProgressUpdate(Object….object):
当在doInBackground方法中调用publishProgress方法更新任务执行进度后,将调用此方法.通过此方法我们可以知晓任务的完成进度。


获取网络图片

activity_main.xml

<RelativeLayout 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"
                android:paddingBottom="@dimen/activity_vertical_margin"
                android:paddingLeft="@dimen/activity_horizontal_margin"
                android:paddingRight="@dimen/activity_horizontal_margin"
                android:paddingTop="@dimen/activity_vertical_margin"
                tools:context=".MainActivity"
    >

    <ImageView
        android:id="@+id/id_img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        />

    <ProgressBar
        android:id="@+id/id_progressBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:visibility="gone"
        />

</RelativeLayout>

MainActivity.java

package com.xieth.as.blogasynctaskdemo;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
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;

public class MainActivity extends AppCompatActivity {

    private ProgressBar progressBar = null;
    private ImageView imageView = null;
    private static String URL = "https://img-my.csdn.net/uploads/201504/12/1428806103_9476.png";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initViews();
        new MyAsyncTask().execute(URL);
    }

    private void initViews() {
        progressBar = (ProgressBar) findViewById(R.id.id_progressBar);
        imageView = (ImageView) findViewById(R.id.id_img);
    }

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

        @Override
        protected Bitmap doInBackground(String... params) {
            String url = params[0];
            Bitmap bitmap = null;
            InputStream is = null;
            URLConnection connection = null;
            try {
                connection = new URL(url).openConnection();
                is = connection.getInputStream();
                BufferedInputStream bis = new BufferedInputStream(is);
                Thread.sleep(3000);
                bitmap = BitmapFactory.decodeStream(bis);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return bitmap;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            progressBar.setVisibility(View.VISIBLE);
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            progressBar.setVisibility(View.GONE);
            imageView.setImageBitmap(bitmap);
        }

        @Override
        protected void onProgressUpdate(Void... values) {
            super.onProgressUpdate(values);
        }
    }

}

运行:
这里写图片描述

记得在配置文件里面设置访问网络权限:

 <uses-permission android:name="android.permission.INTERNET"></uses-permission>

模拟下载进度条

activity_main.xml

<RelativeLayout 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"
                android:paddingBottom="@dimen/activity_vertical_margin"
                android:paddingLeft="@dimen/activity_horizontal_margin"
                android:paddingRight="@dimen/activity_horizontal_margin"
                android:paddingTop="@dimen/activity_vertical_margin"
                tools:context=".MainActivity"
    >

    <ProgressBar
        android:id="@+id/id_progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:max="100"
        />

    <TextView
        android:id="@+id/id_tip"
        android:textSize="16sp"
        android:textColor="@android:color/background_dark"
        android:layout_below="@id/id_progressBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

</RelativeLayout>

MainActivity.java

package com.xieth.as.blogasynctaskdemo;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ProgressBar;
import android.widget.TextView;

import java.text.NumberFormat;

public class MainActivity extends AppCompatActivity {

    public ProgressBar progressBar = null;

    private TextView tip = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initViews();
        new MyAsyncTask().execute();
    }

    private void initViews() {
        progressBar = (ProgressBar) findViewById(R.id.id_progressBar);
        tip = (TextView) findViewById(R.id.id_tip);
    }

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

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
        }

        // 进行进度条的更新
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            progressBar.setProgress(values[0]);
            NumberFormat numberFormat = NumberFormat.getNumberInstance();
            int k = progressBar.getProgress();
            int max = progressBar.getMax();
            tip.setText(numberFormat.format(100*((k*1.0)/max)) + "%");
        }

        @Override
        protected Void doInBackground(Void... params) {
            for (int i = 1; i <= 100;) {
               publishProgress(i);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                i+=1;
            }
            return null;
        }
    }

}

运行:
这里写图片描述
但是如果中途退出的话,就会出现线程池堵塞的问题:
这里写图片描述
可以看到,当第二次点击的时候,要等一下才出现进度条的更新,这是因为,异步任务
是以线程池的方式进行的,如果上一个线程没有更新完毕,下一个就只可以等待上一个完成,才可以开始。
为了解决这个问题,我们需要在Activity的onPause()方法中将正在执行的task标记为cancel状态,在doInBackground方法中进行异步处理时判断是否是cancel状态来决定是否取消之前的task.
如何取消正在运行子线程

 @Override
    protected void onPause() {
        super.onPause();

        // 当task不为空并且是处于正在运行的状态
        if (task != null && task.getStatus() == AsyncTask.Status.RUNNING) {
            task.cancel(true);
        }

    }

然后在doInBackground方法里面的for循环加上一个if条件

if (task.isCancelled()) {
   break;
}

运行:
这里写图片描述
可以看到第二次中途退出,再次进入依然可以重新开始。


进度条更新完整代码

package com.xieth.as.blogasynctaskdemo;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ProgressBar;
import android.widget.TextView;

import java.text.NumberFormat;

public class MainActivity extends AppCompatActivity {

    public ProgressBar progressBar = null;

    private TextView tip = null;

    private MyAsyncTask task = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initViews();
        task = new MyAsyncTask();
        task.execute();
    }

    private void initViews() {
        progressBar = (ProgressBar) findViewById(R.id.id_progressBar);
        tip = (TextView) findViewById(R.id.id_tip);
    }

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

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
        }

        // 进行进度条的更新
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            progressBar.setProgress(values[0]);
            NumberFormat numberFormat = NumberFormat.getNumberInstance();
            int k = progressBar.getProgress();
            int max = progressBar.getMax();
            tip.setText(numberFormat.format(100*((k*1.0)/max)) + "%");
        }

        @Override
        protected Void doInBackground(Void... params) {
            for (int i = 1; i <= 100;) {
               publishProgress(i);
                if (task.isCancelled()) {
                    break;
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                i+=1;
            }
            return null;
        }
    }

    @Override
    protected void onPause() {
        super.onPause();

        // 当task不为空并且是处于正在运行的状态
        if (task != null && task.getStatus() == AsyncTask.Status.RUNNING) {
            task.cancel(true);
        }

    }
}

注意事项

1.必须在UI线程中创建实例,比如在onCreate方法。
2.必须在UI线程中调用execute方法,比如onCreate
3.不能再doInBackground里面进行UI的更新,此方法只可以进行耗时操作,其他三个方法都运行在UI线程中,也就说其他三个方法都可以进行UI的更新操作.
4.每个AsyncTask只可以被执行一次,多次调用会出现异常。
5. AsyncTask被重写的四个方法是系统自动调用的,不应手动调用.


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值