AsyncTask下载网络文件,并显示下载进度

本文提供了一个使用AsyncTask在Android应用中下载网络文件并实时显示下载进度的示例代码。通过重写AsyncTask的onPreExecute(), doInBackgroun(), onProgressUpdate(), 和onPostExecute()方法来实现这一功能,同时确保耗时操作在子线程中执行,而UI更新在主线程中进行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一些说明


ProgressBar.setProgress():

刷新UI操作必须运行在UI线程中,但是setProgress()方法里面已经做了同步操作,所以可以在非UI线程中调用

webView.loadUrl():

耗时操作不能运行在UI线程中,但是loadUrl()方法进过特殊处理,所以可以在UI线程中调用



异步任务demo


> AsyncTask下载网络文件,并显示下载进度


test_AsyncTask.java

package com.example.testasynctask;

import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

public class test_AsyncTask extends Activity {

	private ProgressBar pb_down;
	private TextView tv_downProgress;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.test_async_task);
		Button btn_down = (Button) findViewById(R.id.btn_down);

		btn_down.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				String downloadUrl = "http://501xm.cache.cheerpic.com/source/chizi/201508/32283-20150804.apk";
				String saveDir = Environment.getExternalStorageDirectory()
						.getAbsolutePath() + "/test/download";
				Log.d("pointwall", saveDir);
				DownTask downTask = new DownTask();
				downTask.execute(downloadUrl, saveDir);
			}
		});
	}

	class DownTask extends AsyncTask<String, // Params,启动任务时传入的参数类型
			Integer, // Progress,后台任务执行中返回值的类型
			String// Result,后台任务执行完成返回结果的类型
			> {

		/**
		 * 执行后台耗时操作前被调用,通常完成一些初始化操作,运行在主线程
		 */
		@Override
		protected void onPreExecute() {
			tv_downProgress = (TextView) findViewById(R.id.tv_downProgress);
			pb_down = (ProgressBar) findViewById(R.id.pb_down);
			pb_down.setMax(100);
		}

		/**
		 * 必须重写,异步执行后台将要完成的任务,运行在子线程
		 */
		@Override
		protected String doInBackground(String... params) {
			String downloadUrl = params[0];
			String saveDir = params[1];

			try {
				int currentProgress = 0;// 当前已下载文件长度
				URL url = new URL(downloadUrl);
				HttpURLConnection conn = (HttpURLConnection) url
						.openConnection();
				conn.setRequestMethod("GET");
				conn.setConnectTimeout(8000);
				conn.setReadTimeout(8000);
				if (conn.getResponseCode() == 200) {
					int length = conn.getContentLength();
					InputStream is = conn.getInputStream();

					byte[] b = new byte[1024];
					int len;

					File file2 = new File(saveDir);
					if (!file2.exists()) {
						file2.mkdirs();
					}
					File file = new File(saveDir, getFileName(downloadUrl));
					RandomAccessFile raf = new RandomAccessFile(file, "rwd");

					while ((len = is.read(b)) != -1) {
						raf.write(b, 0, len);

						currentProgress += len;
						// TODO 下载len个长度的字节
						int downRate = (int) ((long) currentProgress * 100 / length);
						publishProgress(downRate);
					}
					raf.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}

			return saveDir + getFileName(downloadUrl);
		}

		/**
		 * 在doInBackgroung()方法中调用publishProgress()方法 更新任务的执行进度后,就会触发该方法,运行在主线程
		 */
		@Override
		protected void onProgressUpdate(Integer... values) {
			int downRate = values[0];
			Log.d("ziru", downRate + "");
			pb_down.setProgress(downRate);
			tv_downProgress.setText("下载了:" + downRate + "%");
		}

		/**
		 * 当doInBackground()完成后,系统会自动调用,运行在主线程
		 */
		@Override
		protected void onPostExecute(String result) {
			tv_downProgress.setText("下载完成");
		}

		/**
		 * 根据下载地址获取app名字
		 * @param downloadDir 下载地址
		 * @return app名字,如:32283-20150804.apk
		 */
		private String getFileName(String downloadDir) {
			int index = downloadDir.lastIndexOf("/");
			return downloadDir.substring(index + 1);
		}

	}

}

test_asynctask.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:padding="5dp" >

    <ProgressBar
        android:id="@+id/pb_down"
        style="@android:style/Widget.ProgressBar.Horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp" />

    <TextView
        android:id="@+id/tv_downProgress"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="等待下载"
        android:textSize="20sp" />

    <Button
        android:id="@+id/btn_down"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="下载" />

</LinearLayout>

权限

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



AsyncTask注意事项


  • 必须在UI线程中创建AsyncTask实例
  • 必须在UI线程中调用AsyncTask.execute()方法
  • 重写的四个方法onPreExecute(), doInBackground(), onProgressUpdate(), onPostExecute()是系统调用的,不应手动调用
  • 每个AsyncTask只能被执行一次,多次调用会引发异常
  • 只有doInBackground()运行在其他线程,onPreExecute(), onProgressUpdate(), onPostExecute()三个方法都运行在UI线程


如何取消AsyncTask


1. 在Activity的onPause()方法中將AsyncTask标记为cancel状态

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


2. 在doInBackground()和onProgressUpdate()方法里做取消异步任务处理

@Override
protected String doInBackground(String... params) {
	if(isCancelled()){
		break;
	}
	
	return null;
}

@Override
protected void onProgressUpdate(Integer... values) {
	if(isCancelled()){
		break;
	}
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值