用粗糙而简陋的语言描述完了Andriod系统的DownloadManager的DownloadThread类,那么,继续我们的粗糙吧。现在就来描述一下DownloadManager的生命——DownloadService类。一如前面的思路,现在假设我们都没看过DownloadService的实现。我们打算怎么弄懂它呢,或者,对于这个神奇的类,你有哪些疑问呢。以下是我能想到的问题:
1、它完成了什么功能,最主要做了什么事儿,这肯定是我们第一个关心的。
2、系统服务与我们所用的应用层Service有什么不同吗?
3、对于一个Service,它实现了哪些接口?
4、这里是不是就是下载的开始点呢?
先看看第三个问题吧,第三个问题最简单,为什么呢,看看源码,看它Override 了几个接口就知道了。
/**
* Performs the background downloads requested by applications that use the Downloads provider.
*/
public class DownloadService extends Service {
@Override
public IBinder onBind(Intent i) {
throw new UnsupportedOperationException("Cannot bind to Download Manager Service");
}
@Override
public void onCreate() {
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
}
@Override
public void onDestroy() {
}
@Override
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
}
}
从实现的接口上来说,它只是实现了一个服务最基础的几个接口,并没有其他特殊接口。不过,这里有一个比较有意思的接口实现,对了,就是OnBind()。它告诉别人,你不能绑定我,只能启动我。一般来说,如果我们要绑定一个服务,可能会希望通过与服务注册一个远程回调,然后服务通过远程的回调将计算结果传给绑定服务的客户端。那么,可想而知,DownloadService是希望不与客户端直接通信的。这算不算与我们写的Service的不同点呢。
那么它是怎么通信的,简单点说,就是通过DownloadProvider来进行的。其实,这样做也能很容易就理解到。因为如果是采用接口的方式的话,服务可能还没发完所有回调,结果自己挂调了,那么就有可能它的客户端就得不到正常的更新。从而导致状态错误。
接下来,可以看第一个问题了。它都做了些什么。从面向对象的角度来说。一个类能不能做什么,是不是先要看看它有哪些成员属性以及成员方法呢。那就行看其成员属性吧。
/** amount of time to wait to connect to MediaScannerService before timing out */
// 等待扫描服务的超时时间
private static final long WAIT_TIMEOUT = 10 * 1000;
/** Observer to get notified when the content observer's data changes */
//能够监听DownloadProvider的Observer
private DownloadManagerContentObserver mObserver;
/** Class to handle Notification Manager updates */
// 通知栏箮理
private DownloadNotifier mNotifier;
//下载队列,通过从DownloadProvider里取出,并将每条下载记录与其生成的下载ID作为一个Map值。
private Map<Long, DownloadInfo> mDownloads = Maps.newHashMap();
/**
* The thread that updates the internal download list from the content
* provider.
*/
//更新线程,是DownloadService的一个内部类,同时,这个也是其功臣类,幕后的英雄。
@VisibleForTesting
UpdateThread mUpdateThread;
/**
* Whether the internal download list should be updated from the content
* provider.
*/
//判断是否需要更新mDownloads
private boolean mPendingUpdate;
/**
* The ServiceConnection object that tells us when we're connected to and disconnected from
* the Media Scanner
*/
//媒体扫描,不关的可以不管,目前我就没管它
private MediaScannerConnection mMediaScannerConnection;
private boolean mMediaScannerConnecting;
/**
* The IPC interface to the Media Scanner
*/
private IMediaScannerService mMediaScannerService;
//外观接口,其实就是通过这个接口去做一些公共的事
@VisibleForTesting
SystemFacade mSystemFacade;
//存储管理
private StorageManager mStorageManager;
以上基本就是DoiwnloadService的成员属性了。关于媒体扫描,暂时可以不管,因为它并不决定下载,初步理解阶段,我们只关心我们最关心的问题。这里,我们只关心最有用,关系也最紧密的两个成员,即mDonwnloads以及mUpdateThread。
简单的过了一遍其成员接口,以及其它所实现的接口。应该对其一些感性的认识了,至少不应该那么陌生了。好了,那么真正去分析这个类吧。
对于一个服务,最让人容易想到的就是其生命周期。所以,引导我们的头,肯定是其onCrreate与onStartCommand.大家都知道,onCreate只执行一次,而onStartCommand会随服务被startService而启动多次。下面依次来看这两个代码。
/**
* Initializes the service when it is first created
*/
@Override
public void onCreate() {
super.onCreate();
//初始化外观接口
if (mSystemFacade == null) {
mSystemFacade = new RealSystemFacade(this);
}
//实始化并注册一个监听DownloadProvider的Observer
mObserver = new DownloadManagerContentObserver();
getContentResolver().registerContentObserver(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI,
true, mObserver);
//媒体扫描相关
mMediaScannerService = null;
mMediaScannerConnecting = false;
mMediaScannerConnection = new MediaScannerConnection();
// 通知管理
mNotifier = new DownloadNotifier(this);
mNotifier.cancelAll();
//初始化存储管理
mStorageManager = StorageManager.getInstance(getApplicationContext());
//从DownloadProvider更新下载。
updateFromProvider();
}
onCreate与我们的习惯写法应该差不多,就是初始化实例。当然,这里也做了一件很重要的事情,那就是从DownloadProvider更新下载。
@Override
public int onSta