android 下载管理器

简介:

android  自带了下载管理器,我们可以获取到下载的进度大小以及下载完成等等的状态,但是android自带的DownLoadManager却没有实现比如暂停,继续等功能也就是不能断点续传,这几天在总下载管理器,写了以后总是 感觉还是不是太好,因为下载要考虑的情况是比较多的


  1、我们要考虑下载的时候要有下载情况的回调,

  2、下载的文件是否已经下载

  3、是否已经下载完成

  4、下载速度

  5、下载的进度

  6、下载的过程中暂停,继续,取消等操作

  7、可能有些人还要把下载的列表分为a 已经下载完成  b 正在下载  

  8、还有要加下载完成的通知,或是提示

  9、还有listView经常遇到的进度条显示错乱

   等等。。。。上网查找了很多的资料,网上有现成的第三方DownloadProvider这个,功能相当的齐全,但是我还是希望自己能写一个

下边是我自己的实现思路

    首先 1 、要有一个service   来进行后台下载

            2、需要有一个存放下载信息的一个实体类downLoadInfo  包含下载的文件大小,每次下载的大小,下载的速度等

 private long id;

@Transient

private HttpHandler<File> handler;

    private HttpHandler.State state
    private String downloadUrl;
    private String fileName;
    private String fileSavePath;
    private long progress;
    private long fileLength;
    private boolean autoResume;
    private boolean autoRename;
    private float speed;

           3、一个下载管理器;进行下载的管理,已经下载进度的回调

   下载我使用的是第三方的xutils


 4 、一个DownLoadAdapter用来给listView填充数据

        整体来讲就是这么多。


下载管理器代码如下

package cn.com.huahuawifi.android.guest.download;

import android.content.Context;
import android.database.Cursor;
import android.util.Log;

import cn.com.huahuawifi.android.guest.util.Utils;
import cn.com.huahuawifi.android.guest.util.XUtilsHttpUtil;

import com.lidroid.xutils.DbUtils;
import com.lidroid.xutils.HttpUtils;
import com.lidroid.xutils.db.converter.ColumnConverter;
import com.lidroid.xutils.db.converter.ColumnConverterFactory;
import com.lidroid.xutils.db.sqlite.ColumnDbType;
import com.lidroid.xutils.db.sqlite.Selector;
import com.lidroid.xutils.exception.DbException;
import com.lidroid.xutils.exception.HttpException;
import com.lidroid.xutils.http.HttpHandler;
import com.lidroid.xutils.http.HttpHandler.State;
import com.lidroid.xutils.http.ResponseInfo;
import com.lidroid.xutils.http.callback.RequestCallBack;
import com.lidroid.xutils.util.LogUtils;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * 下载管理器
 */
public class DownloadManager {

	private List<DownloadInfo> downloadInfoList; // 下载列表
	private List<DownloadInfo> alreadyDownLoadList; // 已经下载完成的
	private List<DownloadInfo> downLoadingList; // 正在下载
	private int maxDownloadThread = 3; // 最大下载线程数

	private Context mContext;
	private DbUtils db;

	private long mLastTime;
	private long mLastFileSize;

	/* package */DownloadManager(Context appContext) {
		ColumnConverterFactory.registerColumnConverter(HttpHandler.State.class,
				new HttpHandlerStateConverter());
		mContext = appContext;
		db = DbUtils.create(mContext);
		alreadyDownLoadList = new ArrayList<DownloadInfo>();
		downLoadingList = new ArrayList<DownloadInfo>();
		try {
			downloadInfoList = db.findAll(Selector.from(DownloadInfo.class)); // 查询所有的下载
		} catch (DbException e) {
			LogUtils.e(e.getMessage(), e);
		}
		if (downloadInfoList == null) {
			downloadInfoList = new ArrayList<DownloadInfo>();

		} else {
			for (int i = 0; i < downloadInfoList.size(); i++) {
				if (downloadInfoList
						.get(i)
						.getState()
						.equals(com.lidroid.xutils.http.HttpHandler.State.SUCCESS)) {
					alreadyDownLoadList.add(downloadInfoList.get(i));
				} else {
					downLoadingList.add(downloadInfoList.get(i));
				}
			}
		}

	}

	public int getDownloadInfoListCount() {
		return downloadInfoList.size();
	}

	public DownloadInfo getDownloadInfo(int index) {
		return downloadInfoList.get(index);
	}

	public int getDownloadInfoLoadingCount() {
		return downLoadingList.size();

	}

	public List<DownloadInfo> getDownLoadingList() {

		return downLoadingList;
	}

	public DownloadInfo getDownLoadinginfo(int index) {
		downLoadingList.get(index);
		return downLoadingList.get(index);
	}

	public int getAlreadyDownLoadCount() {
		return alreadyDownLoadList.size();

	}
	
	public List<DownloadInfo> getAlreadyDownLoadList() {

		return alreadyDownLoadList;
	}
	public DownloadInfo getAlreadyDownLoadInfo(int index) {
		alreadyDownLoadList.get(index);
		return alreadyDownLoadList.get(index);
	}
/**
 * 获取当前url的文件是否在下载列表里,或去的时候想确保把改下载添加到了下载列表中
 * @param downloadUrl
 * @return
 */
	public DownloadInfo  getDownLoadInfo(String  downloadUrl){
	DownloadInfo downloadInfo =null;
		for (DownloadInfo doInfo : downloadInfoList) {
			if (doInfo.getDownloadUrl().equals(downloadUrl)) {
				downloadInfo  =doInfo;
				return downloadInfo;
			}
		}
		return downloadInfo;
	}
	/**
	 * 添加下载任务
	 * 
	 * @param url
	 *            下载链接
	 * @param fileName
	 *            文件名
	 * @param target
	 *            文件存放路径
	 * @param autoResume
	 * @param autoRename
	 * @param callback
	 *            回调
	 * @throws DbException
	 */
	public void addNewDownload(String url, String fileName, String target,
			boolean autoResume, boolean autoRename,
			final RequestCallBack<File> callback) throws DbException {
		if (Utils.fileIsExists(target)) {// 下载文件已经存在不在添加下载任务

		} else {

			final DownloadInfo downloadInfo = new DownloadInfo();
			downloadInfo.setDownloadUrl(url);
			downloadInfo.setAutoRename(autoRename);
			downloadInfo.setAutoResume(autoResume);
			downloadInfo.setFileName(fileName);
			downloadInfo.setFileSavePath(target);
			HttpUtils http = new HttpUtils();
			http.configRequestThreadPoolSize(maxDownloadThread);
			HttpHandler<File> handler = http.download(url, target, autoResume,
					autoRename, new ManagerCallBack(downloadInfo, callback));
			downloadInfo.setHandler(handler);
			downloadInfo.setState(handler.getState());
			downloadInfoList.add(downloadInfo);
			db.saveBindingId(downloadInfo);
		}
	}

	public void resumeDownload(int index, final RequestCallBack<File> callback)
			throws DbException {
		final DownloadInfo downloadInfo = downloadInfoList.get(index);
		resumeDownload(downloadInfo, callback);
	}

	/**
	 * 重新下载
	 * 
	 * @param downloadInfo
	 *            downLoadinfo信息
	 * @param callback
	 *            回调
	 * @throws DbException
	 */
	public void resumeDownload(DownloadInfo downloadInfo,
			final RequestCallBack<File> callback) throws DbException {
		HttpUtils http = new HttpUtils();
		http.configRequestThreadPoolSize(maxDownloadThread);
		HttpHandler<File> handler = http.download(
				downloadInfo.getDownloadUrl(), downloadInfo.getFileSavePath(),
				downloadInfo.isAutoResume(), downloadInfo.isAutoRename(),
				new ManagerCallBack(downloadInfo, callback));
		downloadInfo.setHandler(handler);
		downloadInfo.setState(handler.getState());
		db.saveOrUpdate(downloadInfo);
	}

	/**
	 * 移除下载任务
	 * 
	 * @param index
	 *            要移除的下表
	 * @throws DbException
	 */
	public void removeDownload(int index) throws DbException {
		DownloadInfo downloadInfo = downloadInfoList.get(index);
		removeDownload(downloadInfo);
	}

	/**
	 * 移除下载任务
	 * 
	 * @param downloadInfo
	 *            下载的downloadInfo对象
	 * @throws DbException
	 */
	public void removeDownload(DownloadInfo downloadInfo) throws DbException {
		HttpHandler<File> handler = downloadInfo.getHandler();
		if (handler != null && !handler.isCancelled()) {
			handler.cancel();
		}
		downloadInfoList.remove(downloadInfo);
		downLoadingList.remove(downloadInfo);
		alreadyDownLoadList.remove(downloadInfo);
		db.delete(downloadInfo);
	}

	public void removeAlreadyDownLoad(DownloadInfo downloadInfo) throws DbException{
		HttpHandler<File> handler = downloadInfo.getHandler();
		if (handler != null && !handler.isCancelled()) {
			handler.cancel();
		}
		
		alreadyDownLoadList.remove(downloadInfo);
		Utils.deleteFile(downloadInfo.getFileSavePath());
		db.delete(downloadInfo);
	}
	/**
	 * 停止下载
	 * 
	 * @param index
	 *            下载的下表
	 * @throws DbException
	 */
	public void stopDownload(int index) throws DbException {
		DownloadInfo downloadInfo = downloadInfoList.get(index);
		stopDownload(downloadInfo);
	}

	/**
	 * 停止下载
	 * 
	 * @param downloadInfo
	 *            下载的downloadInfo对象
	 * @throws DbException
	 */
	public void stopDownload(DownloadInfo downloadInfo) throws DbException {
		HttpHandler<File> handler = downloadInfo.getHandler();
		if (handler != null && !handler.isCancelled()) {
			handler.cancel();
		} else {
			downloadInfo.setState(HttpHandler.State.CANCELLED);
		}
		db.saveOrUpdate(downloadInfo);
	}

	/**
	 * 停止所有的下载任务
	 * 
	 * @throws DbException
	 */
	public void stopAllDownload() throws DbException {
		for (DownloadInfo downloadInfo : downloadInfoList) {
			HttpHandler<File> handler = downloadInfo.getHandler();
			if (handler != null && !handler.isCancelled()) {
				handler.cancel();
			} else {
				downloadInfo.setState(HttpHandler.State.CANCELLED);
			}
		}
		db.saveOrUpdateAll(downloadInfoList);
	}

	/**
	 * 改变数据库中下载状态
	 * 
	 * @throws DbException
	 */
	public void backupDownloadInfoList() throws DbException {
		for (DownloadInfo downloadInfo : downloadInfoList) {
			HttpHandler<File> handler = downloadInfo.getHandler();
			if (handler != null) {
				switch (handler.getState()) {
				case WAITING:
					downloadInfo.setState(State.CANCELLED);
					break;
				case SUCCESS:

					break;
				case FAILURE:
					break;
				case LOADING:
					downloadInfo.setState(State.CANCELLED);
					break;
				case CANCELLED:
					downloadInfo.setState(State.CANCELLED);
					break;
				case STARTED:
					downloadInfo.setState(State.CANCELLED);
					break;
				default:
					break;
				}
				
			}
		}
		db.saveOrUpdateAll(downloadInfoList);
	}

	public int getMaxDownloadThread() {
		return maxDownloadThread;
	}

	/**
	 * 设置最大下载线程
	 * 
	 * @param maxDownloadThread
	 */
	public void setMaxDownloadThread(int maxDownloadThread) {
		this.maxDownloadThread = maxDownloadThread;
	}

	public class ManagerCallBack extends RequestCallBack<File> {
		private DownloadInfo downloadInfo;
		private RequestCallBack<File> baseCallBack;

		public RequestCallBack<File> getBaseCallBack() {
			return baseCallBack;
		}

		public void setBaseCallBack(RequestCallBack<File> baseCallBack) {
			this.baseCallBack = baseCallBack;
		}

		private ManagerCallBack(DownloadInfo downloadInfo,
				RequestCallBack<File> baseCallBack) {
			this.baseCallBack = baseCallBack;
			this.downloadInfo = downloadInfo;
		}

		@Override
		public Object getUserTag() {
			if (baseCallBack == null)
				return null;
			return baseCallBack.getUserTag();
		}

		@Override
		public void setUserTag(Object userTag) {
			if (baseCallBack == null)
				return;
			baseCallBack.setUserTag(userTag);
		}

		@Override
		public void onStart() {
			HttpHandler<File> handler = downloadInfo.getHandler();
			if (handler != null) {
				downloadInfo.setState(handler.getState());
			}
			try {
				db.saveOrUpdate(downloadInfo);
				if (downLoadingList.size() == 0) {
					downLoadingList.add(downloadInfo);
				}
			} catch (DbException e) {
				LogUtils.e(e.getMessage(), e);
			}
			if (baseCallBack != null) {
				baseCallBack.onStart();
			}
		}

		@Override
		public void onCancelled() {
			HttpHandler<File> handler = downloadInfo.getHandler();
			if (handler != null) {
				downloadInfo.setState(handler.getState());
			}
			try {
				db.saveOrUpdate(downloadInfo);
			} catch (DbException e) {
				LogUtils.e(e.getMessage(), e);
			}
			if (baseCallBack != null) {
				baseCallBack.onCancelled();
			}
		}

		@Override
		public void onLoading(long total, long current, boolean isUploading) {
			HttpHandler<File> handler = downloadInfo.getHandler();
			if (handler != null) {
				downloadInfo.setState(handler.getState());
			}
			long nowTime = System.currentTimeMillis();
			Log.e("SPEED1", nowTime + "");
			Log.e("SPEED2", mLastTime + "");
			Log.e("SPEED1_file", current + "");
			Log.e("SPEED2_file", mLastFileSize + "");
			float speed = 0;
			float speedContent = current - mLastFileSize;
			float speedTimer = nowTime - mLastTime;
			if (mLastTime > 0 && current != 0) {

				if (speedContent >= 1024) {
					speedContent = (float) ((speedContent) / (1024 + 0.0));
					speedContent = (float) (((int) (speedContent * 10) % 10 + 0.0) / 10 + (int) speedContent);
					speedTimer = (float) ((speedTimer) / (1000 + 0.0));
					speed = speedContent / speedTimer;
				}
				Log.e("SPEED", speed + "");
			}

			mLastTime = nowTime;
			mLastFileSize = current;
			downloadInfo.setSpeed(speed);
			downloadInfo.setFileLength(total);

			downloadInfo.setFileAllSize(((float) total) / ((float) 1048576));
			;
			downloadInfo.setProgress(current);
			try {
				db.saveOrUpdate(downloadInfo);
			} catch (DbException e) {
				LogUtils.e(e.getMessage(), e);
			}
			if (baseCallBack != null) {
				baseCallBack.onLoading(total, current, isUploading);
			}
		}

		@Override
		public void onSuccess(ResponseInfo<File> responseInfo) {
			HttpHandler<File> handler = downloadInfo.getHandler();
			if (handler != null) {
				downloadInfo.setState(handler.getState());
				downLoadingList.remove(downloadInfo);
				alreadyDownLoadList.add(downloadInfo);
			}
			try {
				db.saveOrUpdate(downloadInfo);
			} catch (DbException e) {
				LogUtils.e(e.getMessage(), e);
			}
			if (baseCallBack != null) {
				baseCallBack.onSuccess(responseInfo);
			}
		}

		@Override
		public void onFailure(HttpException error, String msg) {
			HttpHandler<File> handler = downloadInfo.getHandler();
			if (handler != null) {
				downloadInfo.setState(handler.getState());
			}
			try {
				db.saveOrUpdate(downloadInfo);
			} catch (DbException e) {
				LogUtils.e(e.getMessage(), e);
			}
			if (baseCallBack != null) {
				baseCallBack.onFailure(error, msg);
			}
		}
	}

	private class HttpHandlerStateConverter implements
			ColumnConverter<HttpHandler.State> {

		@Override
		public HttpHandler.State getFieldValue(Cursor cursor, int index) {
			return HttpHandler.State.valueOf(cursor.getInt(index));
		}

		@Override
		public HttpHandler.State getFieldValue(String fieldStringValue) {
			if (fieldStringValue == null)
				return null;
			return HttpHandler.State.valueOf(fieldStringValue);
		}

		@Override
		public Object fieldValue2ColumnValue(HttpHandler.State fieldValue) {
			return fieldValue.value();
		}

		@Override
		public ColumnDbType getColumnDbType() {
			return ColumnDbType.INTEGER;
		}
	}
}

DownLoadInfo

<span style="font-size:10px;">package cn.com.huahuawifi.android.guest.download;

import com.lidroid.xutils.db.annotation.Transient;
import com.lidroid.xutils.http.HttpHandler;

import java.io.File;


public class DownloadInfo {

    public DownloadInfo() {
    }

    private long id;

    @Transient
    private HttpHandler<File> handler;

    private HttpHandler.State state;

    private String downloadUrl;

    private String fileName;

    private String fileSavePath;

    private long progress;      //下载的长度

    private long fileLength;   //文件的总长度

    private boolean autoResume;

    private boolean autoRename;     

    private float speed;
    
    private float fileAllSize;
    
    public float getFileAllSize() {
		return fileAllSize;
	}

	public void setFileAllSize(float fileAllSize) {
		this.fileAllSize = fileAllSize;
	}

	public float getSpeed() {
		return speed;
	}

	public void setSpeed(float speed) {
		this.speed = speed;
	}

	public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public HttpHandler<File> getHandler() {
        return handler;
    }

    public void setHandler(HttpHandler<File> handler) {
        this.handler = handler;
    }

    public HttpHandler.State getState() {
        return state;
    }

    public void setState(HttpHandler.State state) {
        this.state = state;
    }

    public String getDownloadUrl() {
        return downloadUrl;
    }

    public void setDownloadUrl(String downloadUrl) {
        this.downloadUrl = downloadUrl;
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public String getFileSavePath() {
        return fileSavePath;
    }

    public void setFileSavePath(String fileSavePath) {
        this.fileSavePath = fileSavePath;
    }

    public long getProgress() {
        return progress;
    }

    public void setProgress(long progress) {
        this.progress = progress;
    }

    public long getFileLength() {
        return fileLength;
    }

    public void setFileLength(long fileLength) {
        this.fileLength = fileLength;
    }

    public boolean isAutoResume() {
        return autoResume;
    }

    public void setAutoResume(boolean autoResume) {
        this.autoResume = autoResume;
    }

    public boolean isAutoRename() {
        return autoRename;
    }

    public void setAutoRename(boolean autoRename) {
        this.autoRename = autoRename;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof DownloadInfo)) return false;

        DownloadInfo that = (DownloadInfo) o;

        if (id != that.id) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return (int) (id ^ (id >>> 32));
    }
}</span><span style="font-size:18px;font-weight: bold;">
</span>


下载的service

<span style="font-size:10px;">package cn.com.huahuawifi.android.guest.download;

import android.app.ActivityManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import com.lidroid.xutils.exception.DbException;
import com.lidroid.xutils.util.LogUtils;

import java.util.List;

public class DownloadService extends Service {

    private static DownloadManager DOWNLOAD_MANAGER;

    public static DownloadManager getDownloadManager(Context appContext) {
        if (!DownloadService.isServiceRunning(appContext)) {
            Intent downloadSvr = new Intent("download.service.action");
            appContext.startService(downloadSvr);
        }
        if (DownloadService.DOWNLOAD_MANAGER == null) {
            DownloadService.DOWNLOAD_MANAGER = new DownloadManager(appContext);
        }
        return DOWNLOAD_MANAGER;
    }

    public DownloadService() {
        super();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
    }

    @Override
    public void onDestroy() {
        if (DOWNLOAD_MANAGER != null) {
            try {
                DOWNLOAD_MANAGER.stopAllDownload();
                DOWNLOAD_MANAGER.backupDownloadInfoList();
            } catch (DbException e) {
                LogUtils.e(e.getMessage(), e);
            }
        }
        super.onDestroy();
    }

    public static boolean isServiceRunning(Context context) {
        boolean isRunning = false;

        ActivityManager activityManager =
                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningServiceInfo> serviceList
                = activityManager.getRunningServices(Integer.MAX_VALUE);

        if (serviceList == null || serviceList.size() == 0) {
            return false;
        }

        for (int i = 0; i < serviceList.size(); i++) {
            if (serviceList.get(i).service.getClassName().equals(DownloadService.class.getName())) {
                isRunning = true;
                break;
            }
        }
        return isRunning;
    }
}</span><span style="font-size:18px;font-weight: bold;">
</span>




相关文章
|
5月前
|
存储 缓存 Android开发
安卓Jetpack Compose+Kotlin, 使用ExoPlayer播放多个【远程url】音频,搭配Okhttp库进行下载和缓存,播放完随机播放下一首
这是一个Kotlin项目,使用Jetpack Compose和ExoPlayer框架开发Android应用,功能是播放远程URL音频列表。应用会检查本地缓存,如果文件存在且大小与远程文件一致则使用缓存,否则下载文件并播放。播放完成后或遇到异常,会随机播放下一首音频,并在播放前随机设置播放速度(0.9到1.2倍速)。代码包括ViewModel,负责音频管理和播放逻辑,以及UI层,包含播放和停止按钮。
|
6月前
|
开发工具 Android开发 git
Windows下载android2.2完整源码(转)
Windows下载android2.2完整源码(转)
82 3
|
6月前
|
敏捷开发 Java 机器人
云效产品使用常见问题之打包后的Android应用获取下载地址失败如何解决
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
3月前
|
Ubuntu 开发工具 Android开发
Repo下载AOSP源码:基于ubuntu22.04 环境配置,android-12.0.0_r32
本文介绍了在基于Ubuntu 22.04的环境下配置Python 3.9、安装repo工具、下载和同步AOSP源码包以及处理repo同步错误的详细步骤。
202 0
Repo下载AOSP源码:基于ubuntu22.04 环境配置,android-12.0.0_r32
|
10天前
|
Java 程序员 开发工具
Android|修复阿里云播放器下载不回调的问题
虽然 GC 带来了很多便利,但在实际编码时,我们也需要注意对象的生命周期管理,该存活的存活,该释放的释放,避免因为 GC 导致的问题。
20 2
|
6月前
|
Java Android开发
android 下载图片的问题
android 下载图片的问题
44 3
|
3月前
|
开发工具 uml git
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82
本文分享了下载AOSP源码的方法,包括如何使用repo工具和处理常见的repo sync错误,以及配置Python环境以确保顺利同步特定版本的AOSP代码。
357 0
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82
|
3月前
|
API 开发工具 Android开发
Android源码下载
Android源码下载
414 0
|
3月前
|
存储 监控 数据库
Android经典实战之OkDownload的文件分段下载及合成原理
本文介绍了 OkDownload,一个高效的 Android 下载引擎,支持多线程下载、断点续传等功能。文章详细描述了文件分段下载及合成原理,包括任务创建、断点续传、并行下载等步骤,并展示了如何通过多种机制保证下载的稳定性和完整性。
85 0