Android多线程下载 仿下载帮手-Android-优质IT资源分享社区

admin
管理员
管理员
  • UID1
  • 粉丝29
  • 关注4
  • 发帖数581
  • 社区居民
  • 忠实会员
  • 原创写手
阅读:214回复:0

  Android多线程下载 仿下载帮手

楼主#
更多 发布于:2016-05-19 16:02


今天带来一个多线程下载的 比方。先看一下作用,点击 下载 开端下载,一同显现下载进展,下载完结,成为程 装置,点击装置 提示 装置运用。



界面作用










线程池 ThreadPoolExecutor






在下面介绍完成下载原理的时分,我想测验倒着来说,这么是不是好了解一点?
咱们都知道,下载帮手,比方360, baidu的 手机帮手,下载APP 的时分 ,都可以一同下载多个,所以,下载必定是多线程的,所以咱们就需求一个线程东西类 来办理咱们的线程,这个东西类的核心,即是 线程池。
线程池ThreadPoolExecutor ,先简略学习下这个线程池的运用






/**
* Parameters:
corePoolSize
the number of threads to keep in the pool, even if they are idle, unless allowCoreThreadTimeOut is set
maximumPoolSize
the maximum number of threads to allow in the pool
keepAliveTime
when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.
unit
the time unit for the keepAliveTime argument
workQueue
the queue to use for holding tasks before they are executed. This queue will hold only the Runnable tasks submitted                   by the execute method.
handler
the handler to use when execution is blocked because the thread bounds and queue capacities are reached
Throws:
IllegalArgumentException - if one of the following holds:
corePoolSize < 0
keepAliveTime < 0
maximumPoolSize <= 0
maximumPoolSize < corePoolSize
NullPointerException - if workQueue or handler is null
*/
ThreadPoolExecutor threadpool=new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler)




上面是 ThreadPoolExecutor的参数介绍,


第一个参数 corePoolSize : 闲暇时 存在的线程数目、


第二个参数 maximumPoolSize :答应一同存在的最大线程数、


第三个参数 keepAliveTime: 这个参数是 答应闲暇线程存活的时刻、


第四个参数 unit : 是 时刻的单位 、


第五个参数 workQueue :这个是一个容器,它里边寄存的是、 threadpool.execute(new Runnable()) 履行的线程.new Runnable()、


第六个参数 handler:当履行被堵塞时,该处理程序将被堵塞,由于线程的鸿沟和行列容量达到了 。



东西类 ThreadManager






介绍完了 线程池参数,那咱们就先创立一个线程办理的东西类 ThreadManager






public class ThreadManager {
public static final String DEFAULT_SINGLE_POOL_NAME = "DEFAULT_SINGLE_POOL_NAME";
private static ThreadPoolProxy mLongPool = null;
private static Object mLongLock = new Object();
private static ThreadPoolProxy mShortPool = null;
private static Object mShortLock = new Object();
private static ThreadPoolProxy mDownloadPool = null;
private static Object mDownloadLock = new Object();
private static Map mMap = new HashMap();
private static Object mSingleLock = new Object();
/** 获取下载线程 */
public static ThreadPoolProxy getDownloadPool() {
synchronized (mDownloadLock) {
if (mDownloadPool == null) {
mDownloadPool = new ThreadPoolProxy(3, 3, 5L);
}
return mDownloadPool;
}
}
/** 获取一个用于履行长耗时使命的线程池,防止和短耗时使命处在同一个行列而堵塞了首要的短耗时使命,一般用来联网操作 */
public static ThreadPoolProxy getLongPool() {
synchronized (mLongLock) {
if (mLongPool == null) {
mLongPool = new ThreadPoolProxy(5, 5, 5L);
}
return mLongPool;
}
}
/** 获取一个用于履行短耗时使命的线程池,防止由于和耗时长的使命处在同一个行列而长时刻得不到履行,一般用来履行本地的IO/SQL */
public static ThreadPoolProxy getShortPool() {
synchronized (mShortLock) {
if (mShortPool == null) {
mShortPool = new ThreadPoolProxy(2, 2, 5L);
}
return mShortPool;
}
}
/** 获取一个单线程池,一切使命将会被依照参加的次序履行,免除了同步开支的疑问 */
public static ThreadPoolProxy getSinglePool() {
return getSinglePool(DEFAULT_SINGLE_POOL_NAME);
}
/** 获取一个单线程池,一切使命将会被依照参加的次序履行,免除了同步开支的疑问 */
public static ThreadPoolProxy getSinglePool(String name) {
synchronized (mSingleLock) {
ThreadPoolProxy singlePool = mMap.get(name);
if (singlePool == null) {
singlePool = new ThreadPoolProxy(1, 1, 5L);
mMap.put(name, singlePool);
}
return singlePool;
}
}
public static class ThreadPoolProxy {
private ThreadPoolExecutor mPool;
private int mCorePoolSize;
private int mMaximumPoolSize;
private long mKeepAliveTime;
private ThreadPoolProxy(int corePoolSize, int maximumPoolSize, long keepAliveTime) {
mCorePoolSize = corePoolSize;
mMaximumPoolSize = maximumPoolSize;
mKeepAliveTime = keepAliveTime;
}
/** 履行使命,当线程池处于封闭,将会从头创立新的线程池 */
public synchronized void execute(Runnable run) {
if (run == null) {
return;
}
if (mPool == null || mPool.isShutdown()) {
mPool = new ThreadPoolExecutor(mCorePoolSize, mMaximumPoolSize, mKeepAliveTime, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), Executors.defaultThreadFactory(), new AbortPolicy());
}
mPool.execute(run);
}
/** 撤销线程池中某个还未履行的使命 */
public synchronized void cancel(Runnable run) {
if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) {
mPool.getQueue().remove(run);
}
}
/** 撤销线程池中某个还未履行的使命 */
public synchronized boolean contains(Runnable run) {
if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) {
return mPool.getQueue().contains(run);
} else {
return false;
}
}
/** 立刻封闭线程池,而且正在履行的使命也将会被中止 */
public void stop() {
if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) {
mPool.shutdownNow();
}
}
/** 陡峭封闭单使命线程池,可是会确保一切现已参加的使命都将会被履行结束才封闭 */
public synchronized void shutdown() {
if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) {
mPool.shutdownNow();
}
}
}
}




这个线程池东西类 首要即是 生成一个线程池, 以及 撤销线程池中的使命,查询线程池中是不是包括某一使命。



下载使命 DownloadTask






咱们的现在线程 DownloadTask 就 经过 ThreadManager .getDownloadPool().execute() 办法 交给线程池去办理。


有了线程池办理咱们的线程, 那咱们下一步 即是 DownloadTask 这个类去下载了。






/** 下载使命 */
public class DownloadTask implements Runnable {
private DownloadInfo info;
public DownloadTask(DownloadInfo info) {
this.info = info;
}
[email protected]
public void run() {
info.setDownloadState(STATE_DOWNLOADING);// 先改动下载状况
notifyDownloadStateChanged(info);
File file = new File(info.getPath());// 获取下载文件
HttpResult httpResult = null;
InputStream stream = null;
if (info.getCurrentSize() == 0 || !file.exists()
|| file.length() != info.getCurrentSize()) {
// 假如文件不存在,或许进展为0,或许进展和文件长度不相符,就需求从头下载
info.setCurrentSize(0);
file.delete();
}
httpResult = HttpHelper.download(info.getUrl());
// else {
// // //文件存在且长度和进展持平,选用断点下载
// httpResult = HttpHelper.download(info.getUrl() + "&range=" +
// info.getCurrentSize());
// }
if (httpResult == null
|| (stream = httpResult.getInputStream()) == null) {
info.setDownloadState(STATE_ERROR);// 没有下载内容回来,修正为过错状况
notifyDownloadStateChanged(info);
} else {
try {
skipBytesFromStream(stream, info.getCurrentSize());
} catch (Exception e1) {
e1.printStackTrace();
}
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file, true);
int count = -1;
byte[] buffer = new byte[1024];
while (((count = stream.read(buffer)) != -1)
&& info.getDownloadState() == STATE_DOWNLOADING) {
// 每次读取到数据后,都需求判别是不是为下载状况,假如不是,下载需求停止,假如是,则改写进展
fos.write(buffer, 0, count);
fos.flush();
info.setCurrentSize(info.getCurrentSize() + count);
notifyDownloadProgressed(info);// 改写进展
}
} catch (Exception e) {
info.setDownloadState(STATE_ERROR);
notifyDownloadStateChanged(info);
info.setCurrentSize(0);
file.delete();
} finally {
IOUtils.close(fos);
if (httpResult != null) {
httpResult.close();
}
}
// 判别进展是不是和app总长度持平
if (info.getCurrentSize() == info.getAppSize()) {
info.setDownloadState(STATE_DOWNLOADED);
notifyDownloadStateChanged(info);
} else if (info.getDownloadState() == STATE_PAUSED) {// 判别状况
notifyDownloadStateChanged(info);
} else {
info.setDownloadState(STATE_ERROR);
notifyDownloadStateChanged(info);
info.setCurrentSize(0);// 过错状况需求删去文件
file.delete();
}
}
mTaskMap.remove(info.getId());
}
}




下载的原理 很简略,即是 经过 方针的URL 拿到流,然后写到本地。


由于下载在 run() 里边履行,这个DownloadTask 类 咱们就看run() 办法的完成,所以 要害代码 即是下面一点点






fos = new FileOutputStream(file, true);
int count = -1;
byte[] buffer = new byte[1024];
while (((count = stream.read(buffer)) != -1)
&& info.getDownloadState() == STATE_DOWNLOADING) {
// 每次读取到数据后,都需求判别是不是为下载状况,假如不是,下载需求停止,假如是,则改写进展
fos.write(buffer, 0, count);
fos.flush();
info.setCurrentSize(info.getCurrentSize() + count);
notifyDownloadProgressed(info);// 改写进展
}






这个在咱们刚触摸Java 的时分 必定都写过了。 这即是往本地写数据的代码。所以run()办法中的 前面 即是拿到 stream 输入流, 以及 把file 创立出来。



改写进展,状况






对于操控 button中text 显现 暂停 ,下载,仍是进展,就靠 notifyDownloadProgressed(info);和 notifyDownloadStateChanged(info)两个办法, 这两个办法 实践上调用的是两个接口,只需咱们在咱们需求改动界面的类里 完成这两个接口,就可以接收到 包括最新信息的info目标。而咱们在哪个类里改动button 上面 显现的文字呢? 当然是在 咱们的adapter 里边了,咱们都知道 是在 adapter 的getView() 办法里边 加载的每一条数据的规划。


那就一同看下是不是这么子呢?






public class RecommendAdapter extends BaseAdapter implements
DownloadManager.DownloadObserver {
ArrayListlist;
private ListmDisplayedHolders;
private FinalBitmap finalBitmap;
private Context context;
public RecommendAdapter(ArrayListlist, FinalBitmap finalBitmap,
Context context) {
this.list = list;
this.context = context;
this.finalBitmap = finalBitmap;
mDisplayedHolders = new ArrayList();
}
public void startObserver() {
DownloadManager.getInstance().registerObserver(this);
}
public void stopObserver() {
DownloadManager.getInstance().unRegisterObserver(this);
}
public int getCount() {
return list.size();
}
public Object getItem(int position) {
return list.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
final AppInfo appInfo = list.get(position);
final ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder(context);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.setData(appInfo);
mDisplayedHolders.add(holder);
return holder.getRootView();
}
public void onDownloadStateChanged(DownloadInfo info) {
refreshHolder(info);
}
public void onDownloadProgressed(DownloadInfo info) {
refreshHolder(info);
}
public ListgetDisplayedHolders() {
synchronized (mDisplayedHolders) {
return new ArrayList(mDisplayedHolders);
}
}
public void clearAllItem() {
if (list != null){
list.clear();
}
if (mDisplayedHolders != null) {
mDisplayedHolders.clear();
}
}
public void addItems(ArrayListinfos) {
list.addAll(infos);
}
private void refreshHolder(final DownloadInfo info) {
ListdisplayedHolders = getDisplayedHolders();
for (int i = 0; i < displayedHolders.size(); i++) {
final ViewHolder holder = displayedHolders.get(i);
AppInfo appInfo = holder.getData();
if (appInfo.getId() == info.getId()) {
AppUtil.post(new Runnable() {
public void run() {
holder.refreshState(info.getDownloadState(),
info.getProgress());
}
});
}
}
}
public class ViewHolder {
public TextView textView01;
public TextView textView02;
public TextView textView03;
public TextView textView04;
public ImageView imageView_icon;
public Button button;
public LinearLayout linearLayout;
public AppInfo mData;
private DownloadManager mDownloadManager;
private int mState;
private float mProgress;
protected View mRootView;
private Context context;
private boolean hasAttached;
public ViewHolder(Context context) {
mRootView = initView();
mRootView.setTag(this);
this.context = context;
}
public View getRootView() {
return mRootView;
}
public View initView() {
View view = AppUtil.inflate(R.layout.item_recommend_award);
imageView_icon = (ImageView) view
.findViewById(R.id.imageview_task_app_cion);
textView01 = (TextView) view
.findViewById(R.id.textview_task_app_name);
textView02 = (TextView) view
.findViewById(R.id.textview_task_app_size);
textView03 = (TextView) view
.findViewById(R.id.textview_task_app_desc);
textView04 = (TextView) view
.findViewById(R.id.textview_task_app_love);
button = (Button) view.findViewById(R.id.button_task_download);
linearLayout = (LinearLayout) view
.findViewById(R.id.linearlayout_task);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
System.out.println("mState:173    "+mState);
if (mState == DownloadManager.STATE_NONE
|| mState == DownloadManager.STATE_PAUSED
|| mState == DownloadManager.STATE_ERROR) {
mDownloadManager.download(mData);
} else if (mState == DownloadManager.STATE_WAITING
|| mState == DownloadManager.STATE_DOWNLOADING) {
mDownloadManager.pause(mData);
} else if (mState == DownloadManager.STATE_DOWNLOADED) {
//                      tell2Server();
mDownloadManager.install(mData);
}
}
});
return view;
}
public void setData(AppInfo data) {
if (mDownloadManager == null) {
mDownloadManager = DownloadManager.getInstance();
}
String filepath= FileUtil.getDownloadDir(AppUtil.getContext()) + File.separator + data.getName() + ".apk";
boolean existsFile = FileUtil.isExistsFile(filepath);
if(existsFile){
int fileSize = FileUtil.getFileSize(filepath);
if(data.getSize()==fileSize){
DownloadInfo downloadInfo = DownloadInfo.clone(data);
downloadInfo.setCurrentSize(data.getSize());
downloadInfo.setHasFinished(true);
mDownloadManager.setDownloadInfo(data.getId(),downloadInfo );
}
//                  else if(fileSize>0){
//                      DownloadInfo downloadInfo = DownloadInfo.clone(data);
//                      downloadInfo.setCurrentSize(data.getSize());
//                      downloadInfo.setHasFinished(false);
//                      mDownloadManager.setDownloadInfo(data.getId(),downloadInfo );
//                  }
}
DownloadInfo downloadInfo = mDownloadManager.getDownloadInfo(data
.getId());
if (downloadInfo != null) {
mState = downloadInfo.getDownloadState();
mProgress = downloadInfo.getProgress();
} else {
mState = DownloadManager.STATE_NONE;
mProgress = 0;
}
this.mData = data;
refreshView();
}
public AppInfo getData() {
return mData;
}
public void refreshView() {
linearLayout.removeAllViews();
AppInfo info = getData();
textView01.setText(info.getName());
textView02.setText(FileUtil.FormetFileSize(info.getSize()));
textView03.setText(info.getDes());
textView04.setText(info.getDownloadNum() + "下载量);
finalBitmap.display(imageView_icon, info.getIconUrl());
if (info.getType().equals("0")) {
//              mState = DownloadManager.STATE_READ;
textView02.setVisibility(View.GONE);
}else{
String  path=FileUtil.getDownloadDir(AppUtil.getContext()) + File.separator + info.getName() + ".apk";
hasAttached = FileUtil.isValidAttach(path, false);
DownloadInfo downloadInfo = mDownloadManager.getDownloadInfo(info
.getId());
if (downloadInfo != null && hasAttached) {
if(downloadInfo.isHasFinished()){
mState = DownloadManager.STATE_DOWNLOADED;
}else{
mState = DownloadManager.STATE_PAUSED;
}
} else {
mState = DownloadManager.STATE_NONE;
if(downloadInfo !=null){
downloadInfo.setDownloadState(mState);
}
}
}
refreshState(mState, mProgress);
}
public void refreshState(int state, float progress) {
mState = state;
mProgress = progress;
switch (mState) {
case DownloadManager.STATE_NONE:
button.setText(R.string.app_state_download);
break;
case DownloadManager.STATE_PAUSED:
button.setText(R.string.app_state_paused);
break;
case DownloadManager.STATE_ERROR:
button.setText(R.string.app_state_error);
break;
case DownloadManager.STATE_WAITING:
button.setText(R.string.app_state_waiting);
break;
case DownloadManager.STATE_DOWNLOADING:
button.setText((int) (mProgress * 100) + "%");
break;
case DownloadManager.STATE_DOWNLOADED:
button.setText(R.string.app_state_downloaded);
break;
//          case DownloadManager.STATE_READ:
//              button.setText(R.string.app_state_read);
//              break;
default:
break;
}
}
}
}





何时 注册 监听observer






里边代码有点多,那就看startObserver()办法做了啥。






public void startObserver() {
DownloadManager.getInstance().registerObserver(this);
}




这儿 是 注册了observer, Observer 是啥东西?在DownloadManager 中咱们定义了






public interface DownloadObserver {
public void onDownloadStateChanged(DownloadInfo info);
public void onDownloadProgressed(DownloadInfo info);
}




一个接口,里边有两个笼统办法 一个是 进展,另一个是下载状况。
那回过头来,屡一下, 咱们在 下载的要害代码里边调用了 DownloadObserver onDownloadProgressed() DownloadObserver.onDownloadStateChanged()两个笼统办法,而咱们在 adapter






public void onDownloadStateChanged(DownloadInfo info) {
refreshHolder(info);
}
public void onDownloadProgressed(DownloadInfo info) {
refreshHolder(info);
}




中完成了 这两个办法 就可以轻松的操控 去 改写 和改动 下载状况了。


仔细的兄弟 或许 发现疑问了,对,咱们还没有注册Observer,就在 DownloadManager 中去调用了。
这儿 在看下DownloadManager 中 调用的办法






/** 当下载状况发送改动的时分回调 */
public void notifyDownloadStateChanged(DownloadInfo info) {
synchronized (mObservers) {
for (DownloadObserver observer : mObservers) {
observer.onDownloadStateChanged(info);
}
}
}
/** 当下载进展发送改动的时分回调 */
public void notifyDownloadProgressed(DownloadInfo info) {
synchronized (mObservers) {
for (DownloadObserver observer : mObservers) {
observer.onDownloadProgressed(info);
}
}
}




是的,这儿咱们遍历一个observer 容器,然后去改写 ,所以咱们还需求 把 Observer 目标 添加到 调集 mObservers 中,


所以必定有这么一个办法 讲 observer 添加到调集中 。






/* 注册观察者 /
public void registerObserver(DownloadObserver observer) {
synchronized (mObservers) {
if (!mObservers.contains(observer)) {
mObservers.add(observer);
}
}
}
/** 反注册观察者 */
public void unRegisterObserver(DownloadObserver observer) {
synchronized (mObservers) {
if (mObservers.contains(observer)) {
mObservers.remove(observer);
}
}
}




所以最终一步,由于 adapter 办法中有 startObserver, 所以 咱们在 主界面 MainActivity 的类中调用 adapter.startObser() 将 完成了 接口的adapter 目标 添加到 Observer 容器中 就可以了。


OK。功德圆满!


=============================================



DownloadManager 代码






这儿 贴一下DownloadManager 代码






public class DownloadManager {
public static final int STATE_NONE = 0;
/** 等待中 */
public static final int STATE_WAITING = 1;
/** 下载中 */
public static final int STATE_DOWNLOADING = 2;
/** 暂停 */
public static final int STATE_PAUSED = 3;
/** 下载结束 */
public static final int STATE_DOWNLOADED = 4;
/** 下载失利 */
public static final int STATE_ERROR = 5;
// public static final int STATE_READ = 6;
private static DownloadManager instance;
private DownloadManager() {
}
/** 用于记载下载信息,假如是正式项目,需求持久化保留 */
private Map mDownloadMap = new ConcurrentHashMap();
/** 用于记载观察者,当信息发送了改动,需求通知他们 */
private ListmObservers = new ArrayList();
/** 用于记载一切下载的使命,方便在撤销下载时,经过id能找到该使命进行删去 */
private Map mTaskMap = new ConcurrentHashMap();
public static synchronized DownloadManager getInstance() {
if (instance == null) {
instance = new DownloadManager();
}
return instance;
}
/** 注册观察者 */
public void registerObserver(DownloadObserver observer) {
synchronized (mObservers) {
if (!mObservers.contains(observer)) {
mObservers.add(observer);
}
}
}
/** 反注册观察者 */
public void unRegisterObserver(DownloadObserver observer) {
synchronized (mObservers) {
if (mObservers.contains(observer)) {
mObservers.remove(observer);
}
}
}
/** 当下载状况发送改动的时分回调 */
public void notifyDownloadStateChanged(DownloadInfo info) {
synchronized (mObservers) {
for (DownloadObserver observer : mObservers) {
observer.onDownloadStateChanged(info);
}
}
}
/** 当下载进展发送改动的时分回调 */
public void notifyDownloadProgressed(DownloadInfo info) {
synchronized (mObservers) {
for (DownloadObserver observer : mObservers) {
observer.onDownloadProgressed(info);
}
}
}
/** 下载,需求传入一个appInfo目标 */
public synchronized void download(AppInfo appInfo) {
// 先判别是不是有这个app的下载信息
DownloadInfo info = mDownloadMap.get(appInfo.getId());
if (info == null) {// 假如没有,则依据appInfo创立一个新的下载信息
info = DownloadInfo.clone(appInfo);
mDownloadMap.put(appInfo.getId(), info);
}
// 判别状况是不是为STATE_NONE、STATE_PAUSED、STATE_ERROR。只有这3种状况才干进行下载,别的状况不予处理
if (info.getDownloadState() == STATE_NONE
|| info.getDownloadState() == STATE_PAUSED
|| info.getDownloadState() == STATE_ERROR) {
// 下载之前,把状况设置为STATE_WAITING,由于此刻并没有产开端下载,仅仅把使命放入了线程池中,当使命真实开端履行时,才会改为STATE_DOWNLOADING
info.setDownloadState(STATE_WAITING);
notifyDownloadStateChanged(info);// 每次状况发作改动,都需求回调该办法通知一切观察者
DownloadTask task = new DownloadTask(info);// 创立一个下载使命,放入线程池
mTaskMap.put(info.getId(), task);
ThreadManager.getDownloadPool().execute(task);
}
}
/** 暂停下载 */
public synchronized void pause(AppInfo appInfo) {
stopDownload(appInfo);
DownloadInfo info = mDownloadMap.get(appInfo.getId());// 找出下载信息
if (info != null) {// 修正下载状况
info.setDownloadState(STATE_PAUSED);
notifyDownloadStateChanged(info);
}
}
/** 撤销下载,逻辑和暂停相似,仅仅需求删去已下载的文件 */
public synchronized void cancel(AppInfo appInfo) {
stopDownload(appInfo);
DownloadInfo info = mDownloadMap.get(appInfo.getId());// 找出下载信息
if (info != null) {// 修正下载状况并删去文件
info.setDownloadState(STATE_NONE);
notifyDownloadStateChanged(info);
info.setCurrentSize(0);
File file = new File(info.getPath());
file.delete();
}
}
/** 装置运用 */
public synchronized void install(AppInfo appInfo) {
stopDownload(appInfo);
DownloadInfo info = mDownloadMap.get(appInfo.getId());// 找出下载信息
if (info != null) {// 发送装置的目的
Intent installIntent = new Intent(Intent.ACTION_VIEW);
installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
installIntent.setDataAndType(Uri.parse("file://" + info.getPath()),
"application/vnd.android.package-archive");
AppUtil.getContext().startActivity(installIntent);
}
notifyDownloadStateChanged(info);
}
/** 发动运用,发动运用是最终一个 */
public synchronized void open(AppInfo appInfo) {
try {
Context context = AppUtil.getContext();
// 获取发动Intent
Intent intent = context.getPackageManager()
.getLaunchIntentForPackage(appInfo.getPackageName());
context.startActivity(intent);
} catch (Exception e) {
}
}
/** 假如该下载使命还处于线程池中,且没有履行,先从线程池中移除 */
private void stopDownload(AppInfo appInfo) {
DownloadTask task = mTaskMap.remove(appInfo.getId());// 先从调集中找出下载使命
if (task != null) {
ThreadManager.getDownloadPool().cancel(task);// 然后从线程池中移除
}
}
/** 获取下载信息 */
public synchronized DownloadInfo getDownloadInfo(long id) {
return mDownloadMap.get(id);
}
public synchronized void setDownloadInfo(long id, DownloadInfo info) {
mDownloadMap.put(id, info);
}
/** 下载使命 */
public class DownloadTask implements Runnable {
private DownloadInfo info;
public DownloadTask(DownloadInfo info) {
this.info = info;
}
[email protected]
public void run() {
info.setDownloadState(STATE_DOWNLOADING);// 先改动下载状况
notifyDownloadStateChanged(info);
File file = new File(info.getPath());// 获取下载文件
HttpResult httpResult = null;
InputStream stream = null;
if (info.getCurrentSize() == 0 || !file.exists()
|| file.length() != info.getCurrentSize()) {
// 假如文件不存在,或许进展为0,或许进展和文件长度不相符,就需求从头下载
info.setCurrentSize(0);
file.delete();
}
httpResult = HttpHelper.download(info.getUrl());
// else {
// // //文件存在且长度和进展持平,选用断点下载
// httpResult = HttpHelper.download(info.getUrl() + "&range=" +
// info.getCurrentSize());
// }
if (httpResult == null
|| (stream = httpResult.getInputStream()) == null) {
info.setDownloadState(STATE_ERROR);// 没有下载内容回来,修正为过错状况
notifyDownloadStateChanged(info);
} else {
try {
skipBytesFromStream(stream, info.getCurrentSize());
} catch (Exception e1) {
e1.printStackTrace();
}
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file, true);
int count = -1;
byte[] buffer = new byte[1024];
while (((count = stream.read(buffer)) != -1)
&& info.getDownloadState() == STATE_DOWNLOADING) {
// 每次读取到数据后,都需求判别是不是为下载状况,假如不是,下载需求停止,假如是,则改写进展
fos.write(buffer, 0, count);
fos.flush();
info.setCurrentSize(info.getCurrentSize() + count);
notifyDownloadProgressed(info);// 改写进展
}
} catch (Exception e) {
info.setDownloadState(STATE_ERROR);
notifyDownloadStateChanged(info);
info.setCurrentSize(0);
file.delete();
} finally {
IOUtils.close(fos);
if (httpResult != null) {
httpResult.close();
}
}
// 判别进展是不是和app总长度持平
if (info.getCurrentSize() == info.getAppSize()) {
info.setDownloadState(STATE_DOWNLOADED);
notifyDownloadStateChanged(info);
} else if (info.getDownloadState() == STATE_PAUSED) {// 判别状况
notifyDownloadStateChanged(info);
} else {
info.setDownloadState(STATE_ERROR);
notifyDownloadStateChanged(info);
info.setCurrentSize(0);// 过错状况需求删去文件
file.delete();
}
}
mTaskMap.remove(info.getId());
}
}
public interface DownloadObserver {
public abstract void onDownloadStateChanged(DownloadInfo info);
public abstract void onDownloadProgressed(DownloadInfo info);
}
/* 重写了Inpustream 中的skip(long n) 办法,将数据流中开始的n 个字节越过 */
private long skipBytesFromStream(InputStream inputStream, long n) {
long remaining = n;
// SKIP_BUFFER_SIZE is used to determine the size of skipBuffer
int SKIP_BUFFER_SIZE = 10000;
// skipBuffer is initialized in skip(long), if needed.
byte[] skipBuffer = null;
int nr = 0;
if (skipBuffer == null) {
skipBuffer = new byte[SKIP_BUFFER_SIZE];
}
byte[] localSkipBuffer = skipBuffer;
if (n <= 0) {
return 0;
}
while (remaining > 0) {
try {
long skip = inputStream.skip(10000);
nr = inputStream.read(localSkipBuffer, 0,
(int) Math.min(SKIP_BUFFER_SIZE, remaining));
} catch (IOException e) {
e.printStackTrace();
}
if (nr < 0) {
break;
}
remaining -= nr;
}
return n - remaining;
}
}




有两点 需求阐明,对于 点击暂停后,再持续下载 有两种办法可以完成


第一种 点击暂停的时分 记载下载了 多少,然后 再点击 持续下载 时,通知服务器, 让服务器接着 前次的数据 往本地传递,


代码 即是 咱们 DownloadTask 下载时分,判别一下






// //文件存在且长度和进展持平,选用断点下载
httpResult = HttpHelper.download(info.getUrl() + "&range=" + info.getCurrentSize());




经过 range 来区分 当时的下载size.


服务器 处理的代码 也很简略 即是一句话


String range = req.getParameter(“range”); 拿到 range 判别 range 存在不存在。
假如不存在






FileInputStream stream = new FileInputStream(file);
int count = -1;
byte[] buffer = new byte[1024];
while ((count = stream.read(buffer)) != -1) {
SystemClock.sleep(20);
out.write(buffer, 0, count);
out.flush();
}
stream.close();
out.close();




假如存在 那么越过range 个字节






RandomAccessFile raf = new RandomAccessFile(file, "r");
raf.seek(Long.valueOf(range));
int count = -1;
byte[] buffer = new byte[1024];
while ((count = raf.read(buffer)) != -1) {
SystemClock.sleep(10);
out.write(buffer, 0, count);
out.flush();
}
raf.close();
out.close();




另一种办法是本地处理,这个demo 中即是本地处理的, 可是有一个疑问, 由于 Java api的因素 ,inputStream.skip() 办法 并不能精确的 越过多少个字节,


而是 小于你想要越过的字节,所以 你要去遍历 一直到 满意你要越过的字节 在持续写, 由于 这么的办法有一个缺点,即是在下载很大的文件,


比方文件巨细20M ,当现已下载了15M 此刻你去暂停,在持续下载,那么要越过前面的15M 将会话费许多时刻。


所以这个仅限于学习。实践中 假如要下载大的文件,不能用这种办法。




优质IT资源分享社区为你提供此文。
本站有大量优质android教程视频,资料等资源,包含android基础教程,高级进阶教程等等,教程视频资源涵盖传智播客,极客学院,达内,北大青鸟,猎豹网校等等IT职业培训机构的培训教学视频,价值巨大。欢迎点击下方链接查看。

android教程视频
优质IT资源分享社区(www.itziyuan.top)
一个免费,自由,开放,共享,平等,互助的优质IT资源分享网站。
专注免费分享各大IT培训机构最新培训教学视频,为你的IT学习助力!

!!!回帖受限制请看点击这里!!!
!!!资源失效请在此版块发帖说明!!!

[PS:按 CTRL+D收藏本站网址~]

——“优质IT资源分享社区”管理员专用签名~

本版相似帖子

游客