Aria下载器源码分析

Aria下载器源码分析

Aria 中文文档: https://aria.laoyuyu.me/aria_doc/

版本:3.8.15

0x01 注册流程

在Activity的onCreate、fragment的onCreate、java的构造函数中使用Aria.download(this).register()便可以实现注册。

0x0101 Aria类,下载库的统一入口

Aria类仅一个私有的构造方法,无法实例化

1
private Aria() {}

0x0102 Aria类的download方法

Aria类中的2个主要静态方法 download, upload, 对应下载和上传两种类型

以下载方法为例,下载,在当前类中调用Aria方法,参数需要使用this,返回对象是 DownloadReceiver

1
2
3
4
5
6
public static DownloadReceiver download(Object obj) {
if (AriaManager.getInstance() != null) {
return AriaManager.getInstance().download(obj);
}
return get(convertContext(obj)).download(obj);
}
  1. AriaManager是个单例
  2. 首次会走get方法,最终执行AriaManager#init()方法进行初始化
  3. convertContext()方法会判断当前参数obj是否是Context对象,并返回Context
  4. 最后都会执行AriaManager单例对象的download()方法,返回一个DownloadReceiver对象

0x0103 AriaManager初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@SuppressLint("StaticFieldLeak") 
private static volatile AriaManager INSTANCE = null;

private AriaManager(Context context) {
APP = context.getApplicationContext();
}

public static AriaManager getInstance() {
return INSTANCE;
}

static AriaManager init(Context context) {
if (INSTANCE == null) {
synchronized (LOCK) {
if (INSTANCE == null) {
INSTANCE = new AriaManager(context);
INSTANCE.initData();
}
}
}
return INSTANCE;
}

private void initData() {
mConfig = AriaConfig.init(APP);
initDb(APP);
regAppLifeCallback(APP);
initAria();
}

  1. init()方法,双空判断加锁实现AriaManager单例
  2. 初始化调用 initData() 方法
  3. 初始化 AriaConfig
  4. 初始化DB
  5. 注册APP生命周期回调,Activity销毁自动移除当前对象的receiver
  6. Aria初始化,异常处理,日志,命令处理器 CommandManager 初始化

0x0104 AriaManager类的download

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private Map<String, AbsReceiver> mReceivers = new ConcurrentHashMap<>();
/**
* 处理下载操作
*/
DownloadReceiver download(Object obj) {
IReceiver receiver = mReceivers.get(getKey(ReceiverType.DOWNLOAD, obj));
if (receiver == null) {
receiver = putReceiver(ReceiverType.DOWNLOAD, obj);
}
return (receiver instanceof DownloadReceiver) ? (DownloadReceiver) receiver : null;
}

private IReceiver putReceiver(ReceiverType type, Object obj) {
final String key = getKey(type, obj);
IReceiver receiver = mReceivers.get(key);

if (receiver == null) {
AbsReceiver absReceiver =
type.equals(ReceiverType.DOWNLOAD) ? new DownloadReceiver(obj) : new UploadReceiver(obj);
mReceivers.put(key, absReceiver);
receiver = absReceiver;
}
return receiver;
}
  1. 调用download方法,根据obj和ReceiverType.DOWNLOAD类型生成key,查询mReceivers是否已经存在当前对象的下载功能接收器DownloadReceiver,存在直接返回
  2. 首次调用,会走到putReceiver方法,新生成一个下载功能接收器DownloadReceiver,并存储在mReceivers中

0x0105 将当前对象注册到Aria

  1. 调用DownloadReceiver#register()方法
  2. 通过DOWNLOAD注解或者实现DownloadTaskListener接口,调用TaskSchedulers.getInstance().register()将当前类注册到Aria

0x0106 TaskSchedulers注册(TODO)

TaskSchedulers 事件调度器,用于处理任务状态的调度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
private Map<String, Map<TaskEnum, Object>> mObservers = new ConcurrentHashMap<>();
/**
* 将当前类注册到Aria
*
* @param obj 观察者类
* @param taskEnum 任务类型 {@link TaskEnum}
*/
public void register(Object obj, TaskEnum taskEnum) {
String targetName = obj.getClass().getName();
Map<TaskEnum, Object> listeners = mObservers.get(getKey(obj));

if (listeners == null) {
listeners = new ConcurrentHashMap<>();
mObservers.put(getKey(obj), listeners);
}

if (!hasProxyListener(listeners, taskEnum)) {
if (obj instanceof TaskInternalListenerInterface) {
listeners.put(taskEnum, obj);
return;
}
String proxyClassName = targetName + taskEnum.proxySuffix;
ISchedulerListener listener = createListener(proxyClassName);
if (listener != null) {
listener.setListener(obj);
listeners.put(taskEnum, listener);
} else {
ALog.e(TAG, "注册错误,没有【" + proxyClassName + "】观察者");
}
}
}

0x02 下载流程(TODO)

1
2
3
4
long taskId = Aria.download(this)
.load(DOWNLOAD_URL) //读取下载地址
.setFilePath(DOWNLOAD_PATH) //设置文件保存的完整路径
.create(); //启动下载

01 DownloadReceiver.load()
1 HttpBuilderTarget.create()
2 BuilderController.create()
3 CmdHelper.createNormalCmd()
4 NormalCmdFactory.createCmd() -> StartCmd
5 EventMsgUtil.getDefault().post(StartCmd) -> mEventQueue.take()
6 EventMsgUtil.sendEvent()
7 StartCmd.executeCmd() -> AbsNormalCmd.startTask()
8 DTaskQueue.createTask(DTaskWrapper wrapper)
9 TaskWrapperManager.getInstance().putTaskWrapper(wrapper)
10 AbsTaskQueue.startTask()
11 DLoadExecutePool.putTask()
12 AbsTask.start()
13 HttpDLoaderUtil.start() -> AbsNormalLoaderUtil.start()
14 NormalLoader.run() -> AbsNormalLoader.run()
15 AbsNormalLoader.startFlow() -> NormalLoader.handleTask()// 启动单线程任务
16 NormalLoader.startThreadTask()
17 NormalTTBuilder.buildThreadTask()
18 ThreadTaskManager.getInstance().startThread()
19 AbsNormalLoader.startTimer() // 启动进度获取定时器

21 ThreadTask.call() // 线程池执行任务回调
22 AbsThreadTaskAdapter.call()
23 HttpDThreadTaskAdapter.handlerThreadTask() // 正式建立Http连接,下载任务
24 HttpDThreadTaskAdapter.readNormal()

25 HttpDThreadTaskAdapter.handleComplete()
26 ThreadTask.updateCompleteState()
27 NormalThreadStateManager.callback -> STATE_COMPLETE
28 BaseListener.onComplete() // 对应的实体类是BaseDListener
29 BaseListener.sendInState2Target() // 将任务状态发送给下载器

0x03 完成事件逆行分析

  1. IDLoadListener.onComplete()
  2. NormalLoader.addComponent(IRecordHandler recordHandler) -> ILoaderVisitor.addComponent(IRecordHandler recordHandler) // 处理任务记录
  3. RecordHandler.checkTaskCompleted() // 检查任务是否已完成
  4. 遍历TaskRecord中所有的ThreadRecord.isComplete就认为下载完成

0x04 M3U8文件下载过程

M3U8ThreadTaskAdapter.readDynamicFile(InputStream is) // 动态长度文件读取方式
M3U8ThreadTaskAdapter.handleComplete() // 处理完成
ThreadTask.updateCompleteState() // 组装Message消息,发送给VodStateManager.callback -> Handler.Callback
VodStateManager.callback -> STATE_COMPLETE
BaseListener.onComplete() // 对应的实体类是M3U8Listener

作者

Dench

发布于

2023-05-25

更新于

2023-05-25

许可协议

CC BY-NC-SA 4.0

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×