绿茶浏览器的下载管理
1、下载相关的类
Android自带的下载管理原理其实很简单,整体基于内容提供者ContentProvider、内容解析者ContentResolver和内容监听者ContentObserver来实现下载的管理,通过ContentResolver操作ContentProvider来触发ContentObserver,从而执行真正的下载操作,下载过程又用到了消息机制。
DownloadListener
网页执行下载的回调接口。
DownloadManager
该类是下载管理的核心类,从名字就可以知道该类主要提供一些管理Download的API,以service的形式提供给开发人员的,即通过getSystemService。它的所有操作都是基于ContentResolver,其中触发真正下载的函数是enqueue(Request request)方法。
DownloadManager.Request下载请求
Downloads
声明了很多常量,主要提供给DownloadManager.(详见源码)
public staticfinal int STATUS_PAUSED = 191;
还没开始下载的暂停状态
public static final int STATUS_RUNNING = 192;
已经开始下载
public static final int STATUS_PAUSED_BY_APP= 193;
手动暂停下载
public static final int STATUS_SUCCEED = 200;
已经下载完全成功,但是也有一些状态值能代表成功了,用isSucccess函数来获得其他的信息
DownloadService
用于监听DownloadContent中的数据变化,从而执行相应的操作,例如:开启下载线程、暂停、重新开始下载等
DownloadThread
主要用于执行下载的操作,包括一些下载中异常的处理。
2、下载中的MimeType和ContentDisposition
常见MimeType:
MimeType | extension |
---|---|
image/jpeg | jpg |
image/gif | gif |
text/html | html |
audio/mpeg | mp3 |
audio/x-wav | wav |
video/x-msvideo | avi |
mime-type指定了下载资源的类型,如果为下载的文件指定mime-type有错误,可能出现不能被其他应用识别的情况,例如下载的图片时,如果指定mime-type类型为image/*,会导致文件管理器中的图片分类可能无法识别图片类型的文件,彩信无法发送图片等情况,这些应用都是通过mime-type识别图片的。
ContentDisposition
ContentDisposition主要在下载时用于猜文件名字
3、当点击了浏览器页面中的某个连接,为什么会下载?
点击浏览器中的链接,向服务器发送请求得到相应的资源,如果资源无法被浏览器的rendering engine处理,就会调用OnDownloadStart,这部分逻辑主要由内核处理。
在Android4.4以后部分下载链接没有回调OnDownloadStart,原因是Android4.3内核升级之后,在点击网页中的链接时,网页发送了GET的request,渲染引擎根据request信息里的MIME Type,判断是否支持在线播放该类型的视频,如果能够处理服务器返回的响应,支持了在线播放此类型的视频, 就不会回调onDownloadStart,也就是该链接不会产生下载事件,因此不会调用浏览器应用的回调onDownloadStart,而是直接通过网页打开播放。这样就导致部分音视频不能选择下载而只能直接播放,为满足项目项目中运营商规范,提供workround解决方案包括:长按处理、过滤url。
4、网络变化时的下载
在项目中经常遇到的下载问题是接打电话、收发短信和彩信、切换网络类型时遇到下载暂停后无法按要求自动恢复,此类问题的本质原因是网络状态发生了变化,因此解决这些问题主要是围绕网络变化的规律来展开。
理解网络类型
平时对网络类型的理解还不够准确,容易将wifi、3G、2G的类别混淆,网络类型主要包括Wifi、移动数据连接(4G、3G、2G),它们在底层的实现各不相同,像打电话、收发短信之类的功能都是与数据连接有关,使用这些功能的时候会对数据连接造成影响,但不会影响wifi。
由于两种网络类型有本质的区别,切换这两种类型的网络时会出现网络短暂的断开,导致下载暂停,下载的状态变为STATUS_WAITING_FOR_NETWORK,Android官方的自动恢复下载需要5分钟,为了符合项目规范的30秒内恢复下载,浏览器需要提前执行恢复下载。
恢复下载的时机
要想使恢复下载成功需具备以下条件:
1).网络的连接良好
2).支持断点续传(基本都支持)
依据这两个条件我们需要监听网络改变后的网络状态
Wifi状态的监听
需要注册广播:WifiManager.NETWORK_STATE_CHANGED_ACTION
只适用于监听Wifi关闭或打开过程的状态。Wifi打开需要一个过程,其DetailedState如下:
OBTAINING_IPADDR(分配IP地址)——>VERIFYING_POOR_LINK(不可靠的连接)——>CAPTIVE_PORTAL_CHECK(检查是否为强制用户)——>CONNECTED(连接完成,会发送ConnectivityManager.CONNECTIVITY_ACTION广播)
当wifi处于CONNECTED后可以执行恢复下载。
Wifi关闭过程的DetailedState一直是DISCONNECTED,可用于控制是否自动恢复。
数据连接状态的监听:
通过TelephonyManager的listen方法注册一个重载了onDataConnectionStateChanged方法的PhoneStateListener对象就可以实现监听
PhoneStateListener.onDataConnectionStateChanged()
只适用于监听数据连接改变时的状态,如2G和3G之间的切换,切换过程一般是经历连接-断开-连接过程,由于有时候2G和3G之间切换会平滑过渡,不会出现断开的情况,也就不会发送ConnectivityManager.CONNECTIVITY_ACTION的广播。
网络连接状态的监听:
需要注册广播:ConnectivityManager.CONNECTIVITY_ACTION
只适用于监听网络连接改变后处于connected时的状态,当数据连接的不同类型之间平滑切换就不能能通过此方式监听到。
PS:
此外网络中断下载也有可能与网络质量有关系,网络中断大部分会产生sockettimeoutexception,造成这种异常的情况有很多,需结合实际场景分析。