一、简单理解Demo
import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); /* * 运行TestAsyncTask */ new TestAsyncTask().execute(); } private class TestAsyncTask extends AsyncTask{ //一般用于初始化,首先运行 @Override protected void onPreExecute() { // TODO Auto-generated method stub super.onPreExecute(); } //一般处理耗时操作,第二运行,不要在这里面运行与ui控件有关的操作 @Override protected Object doInBackground(Object... params) { return null; } /* * 一般用于处理UI界面变化,最后运行 * result是上面doInBackground返回值 */ @Override protected void onPostExecute(Object result) { // TODO Auto-generated method stub super.onPostExecute(result); } } }
二、实践熟悉Demo
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Hello , Welcome to Andy's Blog!"/> <Button android:id="@+id/download" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Download"/> <TextView android:id="@+id/tv" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="当前进度显示"/> <ProgressBar android:id="@+id/pb" android:layout_width="fill_parent" android:layout_height="wrap_content" style="?android:attr/progressBarStyleHorizontal"/> </LinearLayout>
MainActivity.java
import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; public class MainActivity extends Activity { Button download; ProgressBar pb; TextView tv; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); pb=(ProgressBar)findViewById(R.id.pb); tv=(TextView)findViewById(R.id.tv); download = (Button)findViewById(R.id.download); download.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { DownloadTask dTask = new DownloadTask(); dTask.execute(100); } }); } class DownloadTask extends AsyncTask<Integer, Integer, String>{ //后面尖括号内分别是参数(例子里是线程休息时间),进度(publishProgress用到),返回值 类型 @Override protected void onPreExecute() { //第一个执行方法 super.onPreExecute(); } @Override protected String doInBackground(Integer... params) { //第二个执行方法,onPreExecute()执行完后执行 for(int i=0;i<=100;i++){ pb.setProgress(i); publishProgress(i); try { Thread.sleep(params[0]); } catch (InterruptedException e) { e.printStackTrace(); } } return "执行完毕"; } @Override protected void onProgressUpdate(Integer... progress) { //这个函数在doInBackground调用publishProgress时触发,虽然调用时只有一个参数 //但是这里取到的是一个数组,所以要用progesss[0]来取值 //第n个参数就用progress[n]来取值 tv.setText(progress[0]+"%"); super.onProgressUpdate(progress); } @Override protected void onPostExecute(String result) { //doInBackground返回时触发,换句话说,就是doInBackground执行完后触发 //这里的result就是上面doInBackground执行后的返回值,所以这里是"执行完毕" setTitle(result); super.onPostExecute(result); } } }
三、简单学习Demo
activity.xml使用系统默认即可,
Java学习代码如下
MainActivity.java
package com.administrator.asynctaskdemo; import android.os.AsyncTask; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity";//键盘在空白处输入logt,AndroidStudio会快速生成这行代码 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // new DownloadAsyncTask().execute("XueXi","KanShu"); new DownloadAsyncTask().execute("XueXi"); } public class DownloadAsyncTask extends AsyncTask<String,Integer,Boolean>{ /** * 在异步任务之前,在主线程中 */ @Override protected void onPreExecute() { super.onPreExecute(); //可操作UI } /** * 在另外一个线程中处理事件 * @param params 入参 * @return 结果 */ @Override protected Boolean doInBackground(String... params) {//String... strings表示长度是可变参数, // 比如外部调用时,doInBackground("a");doInBackground("a","b"); // doInBackground("a","b","c");等,参数的数量是可变的 for (int i = 0;i<10000;i++){ Log.i(TAG,"doInBackground:"+params[0]); //抛出进度 publishProgress(i); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } return true; } @Override protected void onPostExecute(Boolean aBoolean) { super.onPostExecute(aBoolean); //也是在主线程中,执行结果处理 } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); //收到上面抛出的进度,然后处理:也是在UI线程中 } // @Override // protected void onCancelled() { // super.onCancelled(); // } // // @Override // protected void onCancelled(Boolean aBoolean) { // super.onCancelled(aBoolean); // } } }
四、AsyncTask实现异步下载
步骤
1.网络上请求数据:申请网络权限 读写存储权限
2.布局我们的layout
3.下载之前我们要做什么? UI
4.下载中我们要做什么? 数据
5.下载后我们要做什么? UI
在MainManifest.xml中申请网络权限和读写权限
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
activity_main
<?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:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="10dp" android:orientation="vertical" tools:context="com.administrator.asynctaskdemo.MainActivity"> <ProgressBar style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="15dp" android:id="@+id/progressBar"/> <Button android:text="点击下载" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/button"/> <TextView android:text="Hello world! imooc." android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/textView"/> </LinearLayout>
MainActivity.java
package com.administrator.asynctaskdemo; import android.os.AsyncTask; import android.os.Environment; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; import org.w3c.dom.Text; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.net.URLConnection; /** * 1.网络上请求数据:申请网络权限 读写存储权限 * 2.布局我们的layout * 3.下载之前我们要做什么? UI * 4.下载中我们要做什么? 数据 * 5.下载后我们要做什么? UI */ public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity";//键盘在空白处输入logt,AndroidStudio会快速生成这行代码 public static final String APK_URL = "http://download.sj.qq.com/upload/connAssitantDownload/upload/MobileAssistant_1.apk"; private ProgressBar mProgressBar; private Button mDownloadButton; private TextView mResultTextView; private int INIT_PROGRESSBAR; private String FILE_NAME = "XueXi.apk"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //初始化视图 initView(); //设置点击监听 setListener(); //初始化UI数据 setData(); } private void setListener() { mDownloadButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //TODO 18/5/10 下载任务 DownloadAsyncTask asyncTask = new DownloadAsyncTask(); asyncTask.execute(APK_URL); } }); } private void setData() { mProgressBar.setProgress(INIT_PROGRESSBAR); mDownloadButton.setText("点击下载"); mResultTextView.setText("准备下载"); } /** * 初始化视图 */ private void initView() { mProgressBar = (ProgressBar) findViewById(R.id.progressBar); mDownloadButton = (Button) findViewById(R.id.button); mResultTextView = (TextView) findViewById(R.id.textView); } /** * String 入参 * Integer 进度 * Boolean 返回值 */ public class DownloadAsyncTask extends AsyncTask<String, Integer, Boolean> { String mFilePath; /** * 在异步任务之前,在主线程中 */ @Override protected void onPreExecute() { super.onPreExecute(); //可操作UI 类似淘米,之前的准备工作 mDownloadButton.setText("下载中"); mResultTextView.setText("下载中"); mProgressBar.setProgress(INIT_PROGRESSBAR); } /** * 在另外一个线程中处理事件 * * @param params 入参 煮米 * @return 结果 */ @Override protected Boolean doInBackground(String... params) {//String... strings表示长度是可变参数, if(params != null&¶ms.length>0){ String apkUrl = params[0]; try { //构造URL URL url = new URL(apkUrl); //构造连接,并打开 URLConnection urlConnection = url.openConnection(); InputStream inputStream =urlConnection.getInputStream(); //获取下载内容的总长度 int contentlength = urlConnection.getContentLength(); //下载地址准备 mFilePath = Environment.getExternalStorageDirectory() // File.separator是字符串/ + File.separator + FILE_NAME; //对下载地址进行处理 File apkFile = new File(mFilePath); if(apkFile.exists()){ boolean result = apkFile.delete(); if(!result){ //如果失败了 return false; } } //已下载的大小 已下载大小/总长度*100等于下载进度 int downloadSize = 0; //byte数组 byte[] bytes = new byte[1024]; int length; //创建一个输入管道 OutputStream outputStream = new FileOutputStream(mFilePath); length = inputStream.read(bytes); //不断的一车一车挖土,直到挖不倒为止 while ((length = inputStream.read(bytes))!= -1){ //挖到的放到我们的文件管道里 outputStream.write(bytes,0,length); //累加我们的大小 downloadSize += length; //发送进度 publishProgress(downloadSize*100/contentlength); } inputStream.close(); outputStream.close(); } catch (IOException e) { e.printStackTrace(); return false; } }else{ return false; } return true; } @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); //也是在主线程中,执行结果处理 mDownloadButton.setText(result?"下载完成"+ mFilePath:"下载失败"); mResultTextView.setText(result?"下载完成"+ mFilePath:"下载失败"); } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); //收到进度,然后处理:也是在UI线程中 if(values!=null&&values.length>0){} mProgressBar.setProgress(values[0]); } } }
五、封装成工具类
xml布局如上不变
创建下载工具类
DownloadHelper.java
package com.administrator.asynctaskdemo; import android.os.AsyncTask; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.net.URLConnection; /** * 1.download方法 url localPath listener * 2.listener :start success fail progress * 3.用asynctask封装 * Created by Administrator on 2018/5/10. */ public class DownloadHelper { public static void download(String url,String localPath,OnDownloadListener listener) { DownloadAsyncTask task = new DownloadAsyncTask(url,localPath,listener); task.execute(); } /** * String 入参 * Integer 进度 * Boolean 返回值 */ public static class DownloadAsyncTask extends AsyncTask<String, Integer, Boolean> { String mUrl; String mFilePath; OnDownloadListener mListener; public DownloadAsyncTask(String mUrl, String mFilePath, OnDownloadListener mListener) { this.mUrl = mUrl; this.mFilePath = mFilePath; this.mListener = mListener; } /** * 在异步任务之前,在主线程中 */ @Override protected void onPreExecute() { super.onPreExecute(); //可操作UI 类似淘米,之前的准备工作 if(mListener != null){ mListener.onStart(); } } /** * 在另外一个线程中处理事件 * * @param params 入参 煮米 * @return 结果 */ @Override protected Boolean doInBackground(String... params) {//String... strings表示长度是可变参数, String apkUrl = mUrl; try { //构造URL URL url = new URL(apkUrl); //构造连接,并打开 URLConnection urlConnection = url.openConnection(); InputStream inputStream =urlConnection.getInputStream(); //获取下载内容的总长度 int contentlength = urlConnection.getContentLength(); //对下载地址进行处理 File apkFile = new File(mFilePath); if(apkFile.exists()){ boolean result = apkFile.delete(); if(!result){ //如果失败了 if(mListener != null){ mListener.onFail(-1,apkFile,"文件删除失败"); } return false; } } //已下载的大小 已下载大小/总长度*100等于下载进度 int downloadSize = 0; //byte数组 byte[] bytes = new byte[1024]; int length; //创建一个输入管道 OutputStream outputStream = new FileOutputStream(mFilePath); length = inputStream.read(bytes); //不断的一车一车挖土,直到挖不倒为止 while ((length = inputStream.read(bytes))!= -1){ //挖到的放到我们的文件管道里 outputStream.write(bytes,0,length); //累加我们的大小 downloadSize += length; //发送进度 publishProgress(downloadSize*100/contentlength); } inputStream.close(); outputStream.close(); } catch (IOException e) { e.printStackTrace(); if(mListener != null){ mListener.onFail(-2,new File(mFilePath),e.getMessage()); } return false; } if(mListener != null){ mListener.onSuccess(0,new File(mFilePath)); } return true; } @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); //也是在主线程中,执行结果处理 if (mListener != null){ if(result){ mListener.onSuccess(0,new File(mFilePath)); }else { mListener.onFail(-1,new File(mFilePath),"下载失败"); } } } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); //收到进度,然后处理:也是在UI线程中 if(values!=null&&values.length>0){ if(mListener != null){ mListener.onProgress(values[0]); } } } } public interface OnDownloadListener{ void onStart(); void onSuccess(int code,File file); void onFail(int code,File file,String message); void onProgress(int progress); /** * 如果加写下面这个子类实现了OnDownloadListener的抽象方法,则外部创建该接口时,如通过 * new DownloadHelper.OnDownloadListener.SimpleDownloadListener()调用该方法时, * 不需要每次都重写已在SimpleDownloadListener类中实现的onStart()和onProgress()这两个方法 */ abstract class SimpleDownloadListener implements OnDownloadListener{ @Override public void onStart() { } @Override public void onProgress(int progress) { } } } }
外部调用
MainActivity.java
package com.administrator.asynctaskdemo; import android.os.AsyncTask; import android.os.Environment; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; import org.w3c.dom.Text; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.net.URLConnection; import java.time.LocalDate; /** * 1.网络上请求数据:申请网络权限 读写存储权限 * 2.布局我们的layout * 3.下载之前我们要做什么? UI * 4.下载中我们要做什么? 数据 * 5.下载后我们要做什么? UI */ public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity";//键盘在空白处输入logt,AndroidStudio会快速生成这行代码 public static final String APK_URL = "http://download.sj.qq.com/upload/connAssitantDownload/upload/MobileAssistant_1.apk"; private ProgressBar mProgressBar; private Button mDownloadButton; private TextView mResultTextView; private int INIT_PROGRESSBAR; private String FILE_NAME = "XueXi.apk"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //初始化视图 initView(); //设置点击监听 setListener(); //初始化UI数据 setData(); } private void setListener() { mDownloadButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //TODO 18/5/10 下载任务 DownloadHelper.download(APK_URL," ", new DownloadHelper.OnDownloadListener.SimpleDownloadListener() { @Override public void onSuccess(int code, File file) { Log.e("TAG",String.valueOf(code)); } @Override public void onFail(int code, File file, String message) { Log.e("TAG",String.valueOf(code)); Log.e("TAG",message); } }); } }); } private void setData() { mProgressBar.setProgress(INIT_PROGRESSBAR); mDownloadButton.setText("点击下载"); mResultTextView.setText("准备下载"); } /** * 初始化视图 */ private void initView() { mProgressBar = (ProgressBar) findViewById(R.id.progressBar); mDownloadButton = (Button) findViewById(R.id.button); mResultTextView = (TextView) findViewById(R.id.textView); } }