android离线下载的相关知识
离线下载的功能点如下:
1.下载管理(开始、取消下载)。
2.网络判断(Wi-Fi,3G)。
3.独立进程。
4.定时和手机催醒。
5.自启动。
1.下载管理
这里不便关注下载的细节方法,网络下载的方法很多,大概如下:

1 /**
2 * 下载文件
3 * @param url 下载地址
4 * @param dest 下载存放的本地文件
5 * @param append 断点续传
6 * @return
7 * @throws Exception
8 */
9 public long download(String url, File dest, boolean append) throws Exception{
10 //初始化变量
11 //准备工作
12 // ... ...
13
14 try {
15 // ... ...
16 while((readSize = is.read(buffer)) > 0){
17 //网络判断
18
19 os.write(buffer, 0, readSize);
20 os.flush();
21
22 //如果需要停止下载,如取消,跳出当前下载
23 }
24 }
25 } finally {
26 // ... ...
27 }
28 // ... ...
29 }

这里要注意几点:
(1).在下载的时候,我们希望能及时检测到网络状况,比如由Wi-Fi切换到3G网络下,我们应该能及时停止下载。
(2).当用户选择取消下载的时候,我们也能停止当前下载。
2.网络判断
获取当前网络状态,主要分为Wi-Fi和Mobile(包括3G,GPRS)两种,我们写一个工具类如下:

1 public class NetworkUtils {
2
3 public final static int NONE = 0;//无网络
4 public final static int WIFI = 1;//Wi-Fi
5 public final static int MOBILE = 2;//3G,GPRS
6
7 /**
8 * 获取当前网络状态
9 * @param context
10 * @return
11 */
12 public static int getNetworkState(Context context){
13 ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
14
15 //手机网络判断
16 State state = connManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState();
17 if(state == State.CONNECTED||state == State.CONNECTING){
18 return MOBILE;
19 }
20
21 //Wifi网络判断
22 state = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState();
23 if(state == State.CONNECTED||state == State.CONNECTING){
24 return WIFI;
25 }
26 return NONE;
27 }
28 }

根据网络状态,我们能够控制下载方式:
(1).下载量很大的情况下,我们不大可能在3G情况下进行下载,容易引起用户的反感和担忧。
(2).当客户十分确认可以在3G情况下进行下载,那么也是允许的。
所以,这里提出一个需求,我们要为下载方式设置一个灵活的等级,结合离线下载的特点,我们给出3中方案由用户选择:
(1).移动数据情况下自动下载
(2).只允许Wi-Fi情况下自动下载
(3).关闭下载
这里只列出了自动下载,是因为如果不是自动下载,手动下载用户可以随意控制,无需设置,当然设计到丢流量情况下,如3G下手动下载,提示用户会消耗较大的数据流量,慎用即可。

1 public class Constant {
2 //离线下载网络设置
3 public final static int OFFLINE_MOBILE = 0;
4 public final static int OFFLINE_WIFI = 1;
5 public final static int OFFLINE_OFF = 3;
6 }
7
8 public class Global {
9 //设置默认关闭状态,
10 //为了应用程序下次启动能够记住用户选择,在第一次启动应用的时候,这个值最终应该存放到数据库中,
11 public static int OfflineNetworkSetting = Constant.OFFLINE_OFF;
12 }

现在可以根据规则比较当前网络和离线网络设置,判定离线下载服务的开启。
3.独立进程
离线下载,无论何时何地,只要适宜进行,则当进行,目前主流的做法是建立后台服务。
1 public class OfflineSerivice extends Service {
2 // ... ...
3 }
(1).OfflineService的进程如果默认和应用程序一致,则在应用进程kill的时候,会重启一次(网易新闻在离线下载的时候,退出应用,下载会停顿一小会儿就是这个原因),如果影响不大,这个方案也是可选的。
(2).OfflineService的进程和应用程序分开,如应用程序进程为"cn.cnblogs.tianxia.download",则离线下载服务的进程设置为"cn.cnblogs.tianxia.download.offline",撇清和应用程序的进程的关系。当然,这个会带来一个新的问题,进程间通信,当然因为离线下载和应用程序间的模块比较独立,这个问题还算比较好规避。
(3).OfflineService的进程如果默认和应用程序一致,但是OfflineService继承IntentService,可避免重启的问题,这个是《Pro Android 3》书中提到的方法,非常的好用,但是非常遗憾,本人最近才看到,暂时没有亲手测验,不敢在工作中试用。
按理说,方案3是最佳方案, 但是个人原因,选择了方案2.

1 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2 package="com.cnblogs.download">
3 <application android:icon="@drawable/icon" android:label="@string/app_name">
4
5 <service android:name="cn.cnblogs.download.OfflineService" android:process="cn.cnblogs.download.offline"/>
6 </application>
7 </manifest>

4.定时下载和手机催醒
根据用户设置,在wifi的情况下自动下载,但是自动下载的方案有很多种,频繁的更新下载,定点下载(早上8点,下午4点),间隔下载(每隔6小时)。
这里,我们选择每隔6个小时下载。
(1).这里介绍一种错误的方案。一看到每隔6小时,很容易想到开启一个子线程计时,累计到6个小时,子线程通知下载服务开始新一轮下载。这个方案的思路是没有错的,但是却忽略了手机处于休眠状态,这个子线程其实是停止执行的,那么所谓的6个小时的效果就又可能永远达不到,而且必然不正确或者不准确。
(2).所以,需要使用到一种不休眠的办法:定时器和广播接收器。每隔6小时我们发送一个广播,广播接收器通知开始离线下载。(可参考newsrob源码和书籍《Pro Android 3》):

1 public class OfflineSerivice extends Service {
2
3 //上次成功下载的时间
4 private long lastDownloadTime;
5 // 省略代码... ...
6
7 public static void startAlarm(Context context){
8 AlarmManager alarmManager = (AlarmManager) context.getSystemService("alarm");
9
10 //每隔6个小时发送广播到OfflineAlarmReceiver
11 //也可以设置为10分钟检测一下下载条件,而在OfflineAlarmRecrive中判断开始下载,避免6小时下载失败需再等待6小时过长时间的问题
12 Intent intent = new Intent(context,OfflineAlarmReceiver.class);
13
14 PendingIntent pendingIntent = PendingIntent.getBroadcast(context.getApplicationContext(), 0, intent, 0);
15 alarmManager.cancel(pendingIntent);
16 alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis(), 3600000*6, pendingIntent);
17 }
18 }

OfflineAlarmRecriver中处理开始下载条件,并通知开始下载

1 public class OfflineAlarmReceiver extends BroadcastReceiver {
2 @Override
3 public void onReceive(Context context, Intent arg1) {
4
5 // 省略代码...,初始化变量,准备工作...
6
7 if(System.currentTimeMillis()-OfflineService.lastDownloadTime>3600000*60&&其他条件){
8 //打开离线下载服务
9 Intent alarmIntent = new Intent(context, OfflineService.class);
10 context.startService(alarmIntent);
11 }
12 }
13
14 }

前面我们提到了线程休眠的问题,需要在下载的时候能够唤醒手机,下载完成后能回到休眠状态,下面是两个工具方法:

1 public static PowerManager.WakeLock wakeLock;
2 /**
3 * 唤醒服务
4 */
5 public static void acquireWakeLock(Context context){
6
7 if(wakeLock!=null){
8 return;
9 }
10 PowerManager powerManager = (PowerManager)(context.getSystemService(Context.POWER_SERVICE));
11 wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "com.cnblogs.download.OfflineService");
12 wakeLock.acquire();
13 }
14
15 /**
16 * 释放唤醒服务,返回休眠状态
17 */
18 public static void releaseWakeLock(){
19 if(wakeLock!=null&&wakeLock.isHeld()){
20 wakeLock.release();
21 wakeLock = null;
22 }
23 }

其中PowerManager.PARTIAL_WAKE_LOCK意思是仅唤醒CPU方式,此时能自动主动检测网络状态,从而保证网络正常。
需要在Mainifest.xml中设置权限:
<uses-permission android:name="android.permission.WAKE_LOCK" />
然后在下载服务的onStartConmmand()激活催醒状态,然后在下载完成后释放催醒状态:
1 @Override
2 public int onStartCommand(Intent intent, int flags, int startId) {
3 acquireWakeLock(OfflineService.this);
4 //省略代码... ...
5 return super.onStartCommand(intent, flags, startId);
6 }
5.自启动
为了代码清晰,我们再定义一个自启动的receiver:

1 /**
2 * 自启动离线下载服务
3 * @author user
4 */
5 public class OfflineReceiver extends BroadcastReceiver {
6 @Override
7 public void onReceive(Context context, Intent arg1) {
8 //启动定时器
9 OfflineService.startAlarm(context);
10 }
11 }
12 在AndroidManifest.xml注册此接收器,如下:
13
14 <receiver android:name="cn.cnblogs.download.OfflineReceiver">
15 <intent-filter>
16 <!--自启动-->
17 <action android:name="android.intent.action.BOOT_COMPLETED" />
18 <category android:name="android.intent.category.HOME" />
19 </intent-filter>
20 </receiver>

这样,在启动的时候,能够接受启动广播,并执行启动定时器操作。
6.小结
为了简洁明晰,开门见山,本文仅针对离线下载的最重要的关联点列举说明,而对于清理策略,手动和自动模式,界面跳转,UI设计和业务要求没有过多的涉及,但是往往这些东西才是花费你大量的时间,需要大量细节的积累和耐心的调试,我们唯一要做的事情就是不断的完善!
android离线下载的相关知识的更多相关文章
- Android 基本控件相关知识整理
Android应用开发的一项重要内容就是界面开发.对于用户来说,不管APP包含的逻辑多么复杂,功能多么强大,如果没有提供友好的图形交互界面,将很难吸引最终用户.作为一个程序员如何才能开发出友好的图形界 ...
- Android中的Activity相关知识总结
一.什么是Activity? 简单理解:Activity是Android组件中最基本也是最为常见用的四大组件之一.是一个与用户交互的系统模块,一个Activity通常就是一个单独的屏幕(页面), 它上 ...
- Android 资源目录 相关知识 raw、 drawable、 values..
一定要看的 Android 资源目录的相关知识 raw drwable valueshttp://blog.csdn.net/shichexixi/article/details/5985677 ht ...
- Android Studio下载及离线升级方法
由于众所周知的原因,android官网无法访问,所以我们要用到翻.墙.工具,我用的是自.由.门,大家自行搜索下载. android studio下载地址: https://dl.google.com/ ...
- 【转】Android学习系列–App离线下载功能实现
原文:http://www.cnblogs.com/qianxudetianxia/archive/2011/07/20/2108965.html 宜未雨而绸缪,毋临渴而掘井.----朱用纯<治 ...
- Android学习系列(19)--App离线下载
宜未雨而绸缪,毋临渴而掘井.----朱用纯<治家格言> 离线下载,在有网络的情况下下载服务器数据,以便无网络时也能阅读,就是离线阅读. 离线下载的功能点如下: ...
- 客户端相关知识学习(十一)之Android H5交互Webview实现localStorage数据存储
前言 最近有一个需求是和在app中前端本地存储相关的,所以恶补了一下相关知识 webView开启支持H5 LocalStorage存储 有些时候我们发现写的本地存储没有起作用,那是因为默认WebVie ...
- Android开发环境搭建相关文章列表(转载)
Android开发虽然有所了解,但是一直没有搭建开发环境去学习,Android的更新速度比较快了,Android1.0是2008年发布的,截止到目前为止Android已经更新Android5.0.1, ...
- [转]Android进程与线程基本知识
转自:http://www.cnblogs.com/hanyonglu/archive/2012/04/12/2443262.html 本文介绍Android平台中进程与线程的基本知识. 很早的时候就 ...
随机推荐
- 【sql】经典SQL语句大全
原文链接:http://www.cnblogs.com/yubinfeng/archive/2010/11/02/1867386.html —————————————————————————————— ...
- Winamp传统外观皮肤MusicRio发放
这款皮肤是我在2002年自己弄的,如果能给还在使用Winamp的朋友使用那就最好了. 下载地址:http://files.cnblogs.com/lzhdim/MusicRio.rar
- 使用poi3.9的jar输出excel
// 取得模板文件存放的路径 ReadFilePath = ServletActionContext.getServletContext().getRealPath(ExcelTemplateFile ...
- explicit 关键字
C++ explicit关键字用来修饰类的构造函数,表明该构造函数是显式的,既然有"显式"那么必然就有"隐式",那么什么是显示而什么又是隐式的呢? 如果c++类 ...
- JQuery 获取验证码倒计时
HTML代码: <button id="btn">点击获取验证码</button> Jquery:代码: $(document).ready(functio ...
- ionic框架,快速开发webAPP神器。
官网地址 http://www.ionicframework.com/ 这个国外框架已经很火了.会使用插件的话更好,例如支付宝支付插件,调用摄像头拍照,二维码扫描,通讯录,文件上传,推送信息等等. 最 ...
- .Net冷知识之动态查找类型时的程序集路径问题
今天就说说.Net中通过反射取得某个类型时,我们怎么知道这个类型在硬盘上的哪个角落?比如说,假如我们需要要求服务端动态载入某个数据源,那服务端怎么知道数据源在哪? 网上大部分的教程都写着,可以使用As ...
- with语句
<script type="text/javascript"> /* with语句:有了 With 语句,在存取对象属性和调用方法时就不用重复指定对象. 格式: wit ...
- Android 自定义回调
刚开始接触的时候,觉得 回调 是一个很难理解的概念,之后就不停的上网查找回调的定义:(当你想要把具体的操作,让具体的人来完成,自己定义一个接口就好.使用的时候用接口,具体的人来实现你的接口,也就是实现 ...
- JS版本网站资源状态检测
Title:JS版本网站资源状态检测 --2012-08-28 14:08 前几天需要一个网站状态检测的东东,后面写了个蹩脚的JS版本,里面用到了以前没用过的东西,在这里记下来,其实批处理加curl ...