app离线下载

前段时间做了一个离线下载的模块,需求如下:

1、后台独立进程运行,可以脱离主程序运行

2、可以暂停、继续下载

3、可以判断网络状况和SD卡

4、显示下载进度

4、多个个任务在一个队列中

5、定时下载

一、选择离线下载的核心方法

后台独立运行,我们很容易想到服务(Service),但是有以下几种问题

(1)如果服务的进程和应用一致,那么在应用退出后,服务会重启一次

(2)如果服务的进程和应用不一致,进程间的通信就会麻烦一点

(3)如果服务的进程和应用一致,选择IntentService,可以避免重启问题

而且我们不需要多个任务同时下载,用IntentService完全可以,而且IntentService还有其他优势

参考这篇文章:Android中IntentService与Service的比较

二、下载管理

由于用IntentService,一个任务就是一个intent,服务处理一个Intent就是下载一个任务

(1)当前任务的暂停,可以设置一个下载状态的变量

 1 public static final int CANCEL_STATE = 1 ;
 2
 3 private state int state ;
 4
 5 ...
 6
 7 //download
 8
 9
10
11 while ( ... ) {
12
13 ...
14
15 if ( state == CANCEL_STATE ) {
16
17 break ;
18
19 }
20
21 }

暂停就相当于取消了当前任务,服务去处理下一个intent。

如果要继续这个任务,就要重新发送一个Intent,为了可以从刚刚下载的地方接着下载,我们要坐下处理:

1 File file = new File ( path ) ;
2
3 file.getParentFile().mkdirs () ;
4
5 RandomAccessFile rdFile = new RandomAccessFile ( file, "rwd" ) ;

//获得刚刚下载的文件的大小

1 int mCurrentSize = ( int ) rdFile.length () ;
2
3 HttpURLConnection conn = ( HttpURLConnection ) new URL ( url ).openConnection () ;
4
5 conn.setConnectTimeout ( 5000 ) ;
6
7 conn.setRequestMethod ( "get" ) ;

//从mCurrentSize后开始下载

conn.setRequestProperty ( "Range", "bytes=" + mCurrentSize + "-" ) ;

rdFile.seek ( mCurrentSize ) ;

(2)取消队列中等待下载的任务

发现IntentService不可以取消还未处理的Intent,看IntentService的源码,发现只需略作修改就可以了

//下面自定义一个可以删除intent的服务,只显示新增的代码和覆盖的部分,其他和IntentService一样

 1 public abstract class BaseIntentService extends Service {
 2
 3 private final int MESSAGE_TYPE = 12 ; //消息类型
 4
 5
 6
 7 @Override
 8
 9 public void onStart ( Intent intent, int startId ) {
10
11 Message msg = mServiceHandler.obtainMessage () ;
12
13 msg.arg1 = startId ;
14
15 msg.obj = intent ;
16
17 msg.what = MESSAGE_TYPE ;
18
19 mServiceHandler.sendMessage ( msg ) ;
20
21 }
22
23
24
25 protected boolean hasIntent ( Intent intent ) {
26
27 return mServiceHandler.hasMessages ( MESSAGE_TYPE, intent ) ;
28
29 }
30
31
32
33 protected void removeIntent ( Intent intent ) {
34
35 if ( mServiceHandler.hasMessages ( MESSAGE_TYPE, intent ) ) {
36
37 mServiceHandler.removeMessages ( MESSAGE_TYPE, intent ) ;
38
39 }
40
41 }
42
43
44
45 protected void removeAllIntent () {
46
47 mServiceHandler.removeMessages ( MESSAGE_TYPE ) ;
48
49 }
50
51 }

这边还有另外一个需要注意的地方:在测试中发现删除不了,后来才知道是个低级错误,默认Intent的equals方法是判断两个引用是否指向一个对象,所以我们要重载Intent的 hashCode 和 equals 方法。

三、判断网络状态和SD卡

获得当前的网络状态,如果不是wifi就停止下载,如果SD卡没有挂载,也停止下载

 1 public class NetworkUtils {
 2
 3 public static boolean existWifi ( Context context ) {
 4
 5 ConnectivityManager connManager = ( ConnectivityManager ) context.getSystemService ( Context.CONNECTIVITY_SERVICE ) ;
 6
 7 NetworkInfo info = connManager.getActiveNetworkInfo () ;
 8
 9 return ( null != info && ConnectivityManager.TYPE_WIFI == info.getType () ) ;
10
11 }
12
13 }
 1 public class SDUtils {
 2
 3 public static boolean existSDCard () {
 4
 5 return ( android.os.Environment.getExternalStorageStage().
 6
 7 equals( android.os.Environment.MEDIA_MOUNTED ) ) ;
 8
 9 }
10
11 }

四、显示下载进度

(1)应用程序中显示下载进度,利用ResultReceiver

 1 public class MainActivity extends Activity {
 2
 3 ...
 4
 5
 6
 7 public void startDownload () {
 8
 9 Intent intent = new ...
10
11 intent.putExtra ( "receiver", new DownloadReceiver() ) ;
12
13 ...
14
15 startService ( intent ) ;
16
17 }
18
19
20
21 public class DownloadReceiver extends ResultReceiver {
22
23 ...
24
25 }
26
27
28
29 }

//在IntentService中的onHandleIntent中,获得ResultReceiver

ResultReceiver receiver = intent.getParcelableExtra ( "receiver" ) ;

//在循环下载处理中,发送下载进度

1 Bundle resultData = new Bundle () ;
2
3 resultData.putString ( "progress", percent ) ;
4
5 receiver.send ( UPDATE_PROGRESS, resultData ) ;

(2)在通知栏中,更新下载进度,利用Notifications

五、定时下载

 

这个和闹钟的原理相类似,定义一个定时器和广播接收器,利用AlarmManager

 1 public static void startAlarm ( Context context, long time ) {
 2
 3 AlarmManager am = (AlarmManager) context.getSystemService ( Context.ALARM_SERVICE ) ;
 4
 5 Intent intent = new Intent ( context, AlarmReceiver.class ) ;
 6
 7 PendingIntent pIntent = PendingIntent.getBroadcast ( context, 0, intent, 0 ) ;
 8
 9 am.cancel ( pIntent ) ;
10
11 am.setRepeating ( AlarmManager.RTC_WAKEUP, time, AlarmManager.INTERVAL_DAY, pIntent ) ;
12
13 }
14
15
16
17 public class AlarmReceiver extends BroadcastReceiver {
18
19 @Override
20
21 public void onReceive ( Context context, Intent intent ) {
22
23 //启动下载服务
24
25 。。。
26
27 }
28
29 }

我们在下载的时候可以唤醒手机,下载后可以回到休眠状态,利用PowerManager

 1 public class WakeLockUtils {
 2
 3 public static WakeLock wl ;
 4
 5 public static String tag ; // 服务的包名
 6
 7
 8
 9 public static void acquirePratialWakeLock ( Context context ) {
10
11 if ( null != wl ) return ;
12
13 PowerManager pm = ( PoweerManager ) ( context.getSystemService ( Context.POWER_SERVICE ) ) ;
14
15 wl = pm.newWakeLock ( PowerManager.PARTIAL_WAKE_LOCK, tag ) ;
16
17 wl.acquire () ;
18
19 }
20
21
22
23 public static void releaseWakeLock () {
24
25 if ( null != wl && wl.isHeld () ) {
26
27 wl.release () ;
28
29 wl = null ;
30
31 }
32
33 }
34
35 }
36
37  

六、自启动

为了让我们的闹钟可以在开机后自动startAlarm

 1 public AutoRunReceiver extends BroadcastReceiver {
 2
 3 public void onReceive ( Context context, Intent intent ) {
 4
 5 //启动定时器
 6
 7
 8
 9 。。。startAlram () ;
10
11 }
12
13 }

在AndroidManifest.xml注册此接收器:

 1 <receiver android:name="包名">
 2
 3 <intent-filter>
 4
 5 <action android:name="android.intent.action.BOOT_COMPLETED"/>
 6
 7 <category android:name="android.intent.category.HOME"/>
 8
 9 </intent-filter>
10
11 </receiver>
时间: 2024-08-27 16:20:20

app离线下载的相关文章

Xcode5.1离线下载安装及使用iOS5模拟器进行开发调试的方法

Xcode5.1默认不支持iOS5版本的模拟器开发调试,在OS X Mavericks(10.9.x)下默认只能支持iOS6.1及以上版本的模拟器,在OS X Mountain Lion(10.8.x)下默认只能支持iOS6.0及以上版本的模拟器进行开发和调试,在此条件之下的版本只能使用硬件设备进行开发调试.虽然现在低版本的iOS设备越来越少了,但是有时客户的需求可能会要求我们一定要兼容iOS5(或更低版本)及以上版本,如果我们手头找不到低版本硬件设备用于调试或者完全使用硬件设备而没有对应的模拟

Visual Studio for Mac Preview离线下载安装

Visual Studio for Mac离线下载安装. 环境:OS X EI Caption 10.11.2 .NET Core SDK 1.1 需预先安装 .NET Core 1.1 SDK macOS版下载地址:https://go.microsoft.com/fwlink/?LinkID=835011 安装SDK需先安装openssl. brew update brew install openssl mkdir -p /usr/local/lib ln -s /usr/local/op

[转]App离线本地存储方案

App离线本地存储方案 原文地址:http://ask.dcloud.net.cn/article/166 HTML5+的离线本地存储有如下多种方案:HTML5标准方案:cookie.localstorage.sessionstorage.websql.indexedDBHTML5Plus扩展方案:plus.navigator.setCookie.plus.storage.plus.io cookie体量最小,可以设置过期时间.不能跨域. localstorage适合key.value键值对的存

用Hopper搞定Mac迅雷的会员以及离线下载功能

转自 用Hopper搞定Mac迅雷的会员以及离线下载功能 先定位Mac迅雷的可执行文件 snakeninnys-iMac:~ snakeninny$ ls /Applications/Thunder.app/Contents/MacOS Thunder libetm.dylib libiniparser.dylib 如果你的迅雷也是放在了/Applications下,那么可执行文件的位置应该跟上面一样?? 用Hopper分析可执行文件 定位要修改的函数 可执行文件尺寸不大,Hopper很快就可以

Visual Studio 2017各版本安装包离线下载、安装全解析

转自 寂靜·櫻花雨 Visual Studio 2017各版本安装包离线下载.安装全解析 感谢IT之家网友 寂靜·櫻花雨 的投稿 关于Visual Studio 2017各版本安装包离线下载.更新和安装的方法以及通过已下载版本减少下载量的办法 微软最近发布了正式版Visual Studio 2017并公开了其下载方式,不过由于VS2017采用了新的模块化安装方案,所以微软官方并未提供ISO镜像,但是官方提供了如何进行离线下载的方案给需要进行离线安装的用户,只不过都是英文.本文将对官方指南中的一部

解决app store下载反复报错“下载失败,请到下载栏重试”

google了一下,大家的解决办法有: 通过显示出debug栏,重置app store(点击reset application) (Refer to: http://daluo.com/article/15135/) 找个其他的下载源进行下载,例如百度网盘,soft.macx.cn 通过thunder的thunder store下载 将DNS修改为8.8.8.8 最后,我通过下面的方法解决了: 将DNS修改为8.8.8.8 解决app store下载反复报错"下载失败,请到下载栏重试"

路由器OpenWrt如何脱机(离线)下载BT文件

路由器OpenWrt如何脱机(离线)下载BT文件 1.首先到如下网址下载OpenWrt固件(确保为路由器正确型号). http://downloads.openwrt.org/snapshots/trunk/ar71xx/openwrt-ar71xx-generic-wzr-hp-g450h-squashfs-sysupgrade.bin 2.路由器升级完毕后用telnet输入192.168.1.1(默认地址)连接到路由器,默认没有密码,输入“passwd”修改密码,修改成功后输入“exit”退

百度云离线下载含有违规内容检测方法分析

最近国家开始一轮净网行动,清除网上的淫秽***信息.各大互联网厂家纷纷开始行动,比如当年很好用的百度云离线下载就一度关闭.后来再次开启后,就出现了这句经典词,因含有违规内容被屏蔽无法下载. 其实被屏蔽的不一定都是不健康视频,有些仅仅是因为文件名含有一些字眼而已,比如一些美国大片的枪版就几乎都不能通过百度云的离线下载检测.据说这种方法还在迅雷等地方都有检测,因此我们来分析一下,这个检测到底是如何进行的. 首先上传了一个BT文件,BT文件里面的内容为大闹天宫的电影,但是我把文件名改成了含有敏感词汇的

Android SDK离线下载安装

鉴于国内的网络环境,离线下载Android SDK可能更为方便 方法一.将离线下载包通过迅雷下载,然后解压缩,分别放在相应的SDK文件夹下面,文件夹可参考 http://www.caoqq.net/android-sdk-offine-download.htmland 方法二.也是离线下载包后,将压缩包放在sdk目录的temp目录下,然后打开SDK Manager来安装,但是我没有成功.temp目录是SDK Manager下载安装的临时目录,安装完后会将文件删除. 可参考http://www.o