Download模块 (十七)


DownloadProxy是和DownloadService配对存在的,负责维护mainActivity和downloadService的通信交互。


<1>DownloadProxy不是一构造就立刻启动DownloadService,而是将启动Service放在一个init函数中,
出于防止反复初始化,增加一个flag标记,如果当前还没有bind DownloadService,那么如果这时候检测到DownloadService
还在运行,可以直接bind<通过ActivityManager的getRunningServices来获得运行的进程,然后做对比>。
如果没有在运行,而且还有没有完成的下载任务,在WIFI连接情况下,会弹出一个对话框来询问用户是否原因继续下载。


<2>因为需要调用到DownloadService的onStartCommand来传递一些信息,因此还需要运行一次startService,可以判断其返回值,
如果Service已经start了,那么会返回不为null的componentName,如果返回null,说明Service没起来,return。
然后再尝试bindService(
Context.BIND_ABOVE_CLIENT<indicates that the client application
     binding to this service considers the service to be more important than
     * the app itself, 没有在Service进行startForeground>
| Context.BIND_AUTO_CREATE<automatically create the service as long
     * as the binding exists.  Note that while this will create the service,
     * its {@link android.app.Service#onStartCommand}
     * method will still only be called due to an
     * explicit call to {@link #startService}>),
如果返回false,那么也认为bindService失败。
还有一个isServiceStarting flag来标记是否还正在bind<ServiceConnection会在bind成功的时候回调>


<3>在stopService的时候,先进行stop,然后unbind,<对于被start而不是bind启动的Service,只unbind,哪怕没有bind的进程,Service也不会停,必须stop才可以,然后全部unbind以后,Service会自动停止,
* <p>Using startService() overrides the default service lifetime that is
     * managed by {@link #bindService}: it requires the service to remain
     * running until {@link #stopService} is called, regardless of whether
     * any clients are connected to it.>


<4>一旦定制的ServiceConnection的onServiceConnected回调到,取得了Service的binder,那么就将自己的binder也写入到parcel并且
发送INIT 这的 code,transact过去,在确定了binder连通以后,就可以将pending的DownloadTask全部发到Service进行执行了。
注意Service的INIT会有reply的parcel过来,因此在transact以后还要接收Service返回的数据<就是Service从磁盘持久化中恢复出来的
Download信息,通过JsonObject转string的方式>,在Proxy这边恢复,也是转换成一个JsonObject以后通过get 一个 key得到一个JSONArray
,然后将这些临时存储在一个JsonObject的ArrayList中,然后依照DownloadInfo构造出Downloac类,这些被恢复的Download虽然是Service
回传的,但是并不会由Service自动start,还是交给Proxy来处理,如果这时候由于某种原因,Service连接又断开了,那么就将这些加入到
pendingTaskList中,等待下次bind成功以后送过去,否则以NEW_TASK的code将这些Download transact到Service端开始下载。
同时在确认这些Task投递成功以后,这些Task也会被保存在Proxy端的DownloadManager<M>中.
Download割裂为Service和Proxy进一步加剧了数据一致性的问题。


<5>提供了几个重载的startDownload函数,但基本最后都调到一个。大多是装饰性函数,在原来基础加一些检测<是否确认下载/下载路径是否有效等>
下载到网盘有不同的方式,不会和Service产生交互,也不会有相关的Info,直接return。
startDownload最终会根据输入的参数构造出DownloadInfo 以及 Download,然后将createTask和startService封装在一个runnable中<和多线程无关,只是封装了一些操作罢了,换做函数一样>,
直接run或者展示一个dialog再run。




<6>设定在监听每次DownloadFragment显示出来的event,会尝试一次startService<如果已经成功start bind了,没啥用,不过如果上一次失败,这一次
正好retry>


<7>同时还会监听APPExit事件,会告知Service<transact code>


<8>从Service通过onTransact收到实际的DownloadTask的变化以后,通过post runnable在主线程处理:
这些变化都会直接设置相关Download对象的信息<Download对象内部会触发变化的event,M被改变,进一步改变C和V>,没有使用listener机制。
应该把变化所引起的所有细节都放在Download里,或者将一部分逻辑抽离到DownloadManager中,DownloadProxy应该扮演更纯粹的和Service交流通信的角色,不过当时没有这么做。


<9>proxy这边 pause/resume/remove Download,都是通过binder发给Service执行。