Android-AsyncTask的使用
转载https://blog.csdn.net/acm_th/article/details/51160468AsyncTask是安卓执行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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
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);
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
运行:
记得在配置文件里面设置访问网络权限:
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
- 1
模拟下载进度条
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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
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;
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
运行:
但是如果中途退出的话,就会出现线程池堵塞的问题:
可以看到,当第二次点击的时候,要等一下才出现进度条的更新,这是因为,异步任务
是以线程池的方式进行的,如果上一个线程没有更新完毕,下一个就只可以等待上一个完成,才可以开始。
为了解决这个问题,我们需要在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);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
然后在doInBackground方法里面的for循环加上一个if条件
if (task.isCancelled()) {
break;
}
- 1
- 2
- 3
运行:
可以看到第二次中途退出,再次进入依然可以重新开始。
进度条更新完整代码
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
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
注意事项
1.必须在UI线程中创建实例,比如在onCreate方法。
2.必须在UI线程中调用execute方法,比如onCreate
3.不能再doInBackground里面进行UI的更新,此方法只可以进行耗时操作,其他三个方法都运行在UI线程中,也就说其他三个方法都可以进行UI的更新操作.
4.每个AsyncTask只可以被执行一次,多次调用会出现异常。
5. AsyncTask被重写的四个方法是系统自动调用的,不应手动调用.