AsyncTask异步任务
AsyncTask异步任务概述
异步任务:可理解为同时进行的事情,相当于有多个线程。【边看电视边吃饭】
实质:Handler异步消息处理机制
AsyncTask was intended to enable proper and easy use of the UI thread. AsyncTask旨在启用和轻松使用UI线程。
多线程
ANR (Application Not Responding): 应用程序无响应
UI线程被卡住,比如你在做请求网络、下载音乐等,会引起ANR,这是就要新建一个线程里处理这些耗时的操作。
AsyncTask中常用方法
onPreExecute(): 执行前
/**
* 在异步任务之前,在主线程中:可操作UI
* */
@Override
protected void onPreExecute() {
super.onPreExecute();
//可操作UI
}
doInBackground(): 执行中
/**
* 在另一个线程中处理事件,耗时操作
* @param strings 入参
* @return 结果
* */
@Override
protected Boolean doInBackground(String... strings) {
return null;
}
onPostExecute(): 执行后
//会将doInBackground()的结果返回给onPostExecute(),然后对该结果进行处理
//在主线程中,处理执行结果
@Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
}
onProgressUpdate(): 进度变化
//进度在变化的时候 会执行这个方法
//参数为泛型中的第二个Integer
//在doInBackground()可调用 publishProgress()方法来抛出进度
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
//处理收到的进度,在UI线程,主线程中
}
onCancelled(): 取消操作
//带参数的取消方法参数为 doInBackground()中的result
@Override
protected void onCancelled(Boolean aBoolean) {
super.onCancelled(aBoolean);
}
@Override
protected void onCancelled() {
super.onCancelled();
}
AsyncTask实例——下载任务
Step 1 网络请求数据:申请网络权限,读写存储权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Step 2 创建布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".DownloadHandlerActivity">
<ProgressBar
android:id="@+id/progressBar_async"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="100"
tools:layout_editor_absoluteX="208dp"
tools:layout_editor_absoluteY="201dp" />
<Button
android:id="@+id/button_async"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="点击下载"
android:layout_marginBottom="10dp"
tools:layout_editor_absoluteX="179dp"
tools:layout_editor_absoluteY="96dp" />
<TextView
android:id="@+id/textView_async"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="26sp"
/>
</LinearLayout>
Step 3 准备事件:初始化数据
public static final int INIT_PROGRESS = 0;
private Button mDownloadButton ;
private TextView mResultTextView;
private ProgressBar mProgressBar;
private static final String TAG = "AsyncActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_async);
//初始化视图
initViews();
//设置监听器
setListeners();
//初始化UI数据
setData();
}
/**
* 初始化视图
* */
private void initViews() {
mDownloadButton = findViewById(R.id.button_async);
mProgressBar = findViewById(R.id.progressBar_async);
mResultTextView = findViewById(R.id.textView_async);
}
/**
* 设置监听器
* */
private void setListeners() {
mDownloadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO: 2020/5/17 下载任务
}
});
}
/**
* 初始化UI数据
* */
private void setData() {
mProgressBar.setProgress(INIT_PROGRESS);
mDownloadButton.setText(R.string.click_download_btn);
mResultTextView.setText(R.string.prepare_download_txt);
}
...
}
Step 4 下载之前要做的事情【UI线程 主线程】
/**
* 在异步任务之前,在主线程中:可操作UI
* */
@Override
protected void onPreExecute() {
super.onPreExecute();
//可操作UI, 类似淘米,准备工作
mDownloadButton.setText(R.string.downloading);
mResultTextView.setText(R.string.downloading);
mProgressBar.setProgress(INIT_PROGRESS);
}
Step 5 下载中要做的事情 【子线程 处理耗时任务】
/**
* 在另一个线程中处理事件,耗时操作
* @param strings 入参 煮米
* String...表示可变的String, 可以有1个String 2个String ...多个String
* @return 结果
* */
@Override
protected Boolean doInBackground(String... strings) {
// TODO: 2020/5/17 下载过程
if(strings!=null && strings.length > 0){
String apkUrl = strings[0];
try {
//构造URL
URL url = new URL(apkUrl);
//构造链接
URLConnection urlConnection = url.openConnection();
//创建输入流
InputStream inputStream = urlConnection.getInputStream();
//获取文件的总长度
int contentLength = urlConnection.getContentLength();
//下载地址准备 File.separator表示 : /
downloadFileName = getExternalFilesDir(null)
+ File.separator + "imooc" +File.separator+ FILE_NAME ;
Log.d(TAG,downloadFileName);
//对下载地址进行处理
File apkFile = new File(downloadFileName);
if(!apkFile.exists()){
boolean result = apkFile.delete();
if(!result){
return false;
}
// file.mkdir();
}
//获取下载时的长度
int downloadSize = 0;
//创建字节数组
byte[] bytes = new byte[1024];
int length = 0;
//创建输出流:一个输出管道
OutputStream outputStream = new FileOutputStream(downloadFileName);
//不断地一车一车挖土,直到挖不到为止
while (( length = inputStream.read(bytes))!= -1){
//挖到地放到我们的文件管道里
outputStream.write(bytes,0,length);
//累加下载时的大小
downloadSize += length;
// TODO: 2020/5/17 抛出进度
publishProgress(downloadSize*100 /contentLength);
}
inputStream.close();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
return false;
}
}else {
return false;
}
return true;
}
Step 6 下载后以及进度条的处理
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
// TODO: 2020/5/17 下载后的处理
mDownloadButton.setText(result?getString(R.string.download_success):getString(R.string.download_fail));
mResultTextView.setText(result? getString(R.string.download_success)+ ":" +downloadFileName :getString(R.string.download_fail));
}
//进度在变化的时候 会执行这个方法
//参数为泛型中的第二个Integer
//在doInBackground()可调用 publishProgress()方法来抛出进度
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
//处理收到的进度,在UI线程,主线程中
if(values!=null && values.length>0){
mProgressBar.setProgress(values[0]);
}
}