修复在activity 的onStop中取消注册导致的内存泄露问题
This commit is contained in:
@@ -25,6 +25,7 @@ import android.os.Build;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.DialogFragment;
|
import android.support.v4.app.DialogFragment;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.widget.PopupWindow;
|
import android.widget.PopupWindow;
|
||||||
import com.arialyy.aria.core.command.ICmd;
|
import com.arialyy.aria.core.command.ICmd;
|
||||||
import com.arialyy.aria.core.common.QueueMod;
|
import com.arialyy.aria.core.common.QueueMod;
|
||||||
@@ -293,39 +294,10 @@ import org.xml.sax.SAXException;
|
|||||||
return receiver;
|
return receiver;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 不允许在"onDestroy"、"finish"、"onStop"这三个方法中添加注册器
|
|
||||||
*/
|
|
||||||
private AbsReceiver checkTarget(String key, AbsReceiver receiver, Object obj,
|
private AbsReceiver checkTarget(String key, AbsReceiver receiver, Object obj,
|
||||||
boolean needRmReceiver) {
|
boolean needRmReceiver) {
|
||||||
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
|
|
||||||
int i = 0;
|
|
||||||
for (StackTraceElement e : stack) {
|
|
||||||
String name = e.getClassName();
|
|
||||||
if (!name.equals(AriaManager.class.getName())) {
|
|
||||||
i++;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i += 4;
|
|
||||||
String methodName = stack[i].getMethodName();
|
|
||||||
boolean isDestroyed =
|
|
||||||
methodName.equals("onDestroy") || methodName.equals("finish") || methodName.equals(
|
|
||||||
"onStop");
|
|
||||||
|
|
||||||
if (isDestroyed) {
|
|
||||||
ALog.e(TAG,
|
|
||||||
"请不要在Activity或Fragment的onDestroy、finish、onStop等方法中注册Aria,Aria的unRegister会在Activity页面销毁时自动执行");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj instanceof Activity && isDestroyed) {
|
|
||||||
return receiver;
|
|
||||||
} else if (obj instanceof Fragment && isDestroyed) {
|
|
||||||
return receiver;
|
|
||||||
}
|
|
||||||
receiver.targetName = obj.getClass().getName();
|
receiver.targetName = obj.getClass().getName();
|
||||||
receiver.obj = obj;
|
AbsReceiver.OBJ_MAP.put(receiver.getKey(), obj);
|
||||||
receiver.needRmListener = needRmReceiver;
|
receiver.needRmListener = needRmReceiver;
|
||||||
mReceivers.put(key, receiver);
|
mReceivers.put(key, receiver);
|
||||||
return receiver;
|
return receiver;
|
||||||
@@ -430,29 +402,16 @@ import org.xml.sax.SAXException;
|
|||||||
/**
|
/**
|
||||||
* 移除指定对象的receiver
|
* 移除指定对象的receiver
|
||||||
*/
|
*/
|
||||||
public void removeReceiver(Object obj) {
|
public void removeReceiver(String targetName) {
|
||||||
if (obj == null) return;
|
if (TextUtils.isEmpty(targetName)) {
|
||||||
String clsName = obj.getClass().getName();
|
ALog.e(TAG, "target name null");
|
||||||
for (Iterator<Map.Entry<String, AbsReceiver>> iter = mReceivers.entrySet().iterator();
|
return;
|
||||||
iter.hasNext(); ) {
|
|
||||||
Map.Entry<String, AbsReceiver> entry = iter.next();
|
|
||||||
String key = entry.getKey();
|
|
||||||
if (key.contains(clsName)) {
|
|
||||||
iter.remove();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Aria注册对象被销毁时调用
|
|
||||||
*/
|
|
||||||
void destroySchedulerListener(Object obj) {
|
|
||||||
String clsName = obj.getClass().getName();
|
|
||||||
for (Iterator<Map.Entry<String, AbsReceiver>> iter = mReceivers.entrySet().iterator();
|
for (Iterator<Map.Entry<String, AbsReceiver>> iter = mReceivers.entrySet().iterator();
|
||||||
iter.hasNext(); ) {
|
iter.hasNext(); ) {
|
||||||
Map.Entry<String, AbsReceiver> entry = iter.next();
|
Map.Entry<String, AbsReceiver> entry = iter.next();
|
||||||
String key = entry.getKey();
|
String key = entry.getKey();
|
||||||
if (key.contains(clsName)) {
|
if (key.contains(targetName)) {
|
||||||
AbsReceiver receiver = mReceivers.get(key);
|
AbsReceiver receiver = mReceivers.get(key);
|
||||||
if (receiver != null) {
|
if (receiver != null) {
|
||||||
receiver.unRegisterListener();
|
receiver.unRegisterListener();
|
||||||
@@ -493,7 +452,7 @@ import org.xml.sax.SAXException;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override public void onActivityDestroyed(Activity activity) {
|
@Override public void onActivityDestroyed(Activity activity) {
|
||||||
destroySchedulerListener(activity);
|
removeReceiver(activity.getClass().getName());
|
||||||
// TODO: 2018/4/11 维护一个activity堆栈,应用被kill,activity会回调onDestroy方法,需要考虑server后台情况
|
// TODO: 2018/4/11 维护一个activity堆栈,应用被kill,activity会回调onDestroy方法,需要考虑server后台情况
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ final class WidgetLiftManager {
|
|||||||
private PopupWindow.OnDismissListener createPopupWindowListener(final PopupWindow popupWindow) {
|
private PopupWindow.OnDismissListener createPopupWindowListener(final PopupWindow popupWindow) {
|
||||||
return new PopupWindow.OnDismissListener() {
|
return new PopupWindow.OnDismissListener() {
|
||||||
@Override public void onDismiss() {
|
@Override public void onDismiss() {
|
||||||
AriaManager.getInstance(AriaManager.APP).destroySchedulerListener(popupWindow);
|
AriaManager.getInstance(AriaManager.APP).removeReceiver(popupWindow.getClass().getName());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,8 @@ final class WidgetLiftManager {
|
|||||||
return new Dialog.OnCancelListener() {
|
return new Dialog.OnCancelListener() {
|
||||||
|
|
||||||
@Override public void onCancel(DialogInterface dialog) {
|
@Override public void onCancel(DialogInterface dialog) {
|
||||||
AriaManager.getInstance(AriaManager.APP).destroySchedulerListener(dialog);
|
AriaManager.getInstance(AriaManager.APP)
|
||||||
|
.destroySchedulerListener(dialog.getClass().getName());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -132,7 +133,8 @@ final class WidgetLiftManager {
|
|||||||
return new Dialog.OnDismissListener() {
|
return new Dialog.OnDismissListener() {
|
||||||
|
|
||||||
@Override public void onDismiss(DialogInterface dialog) {
|
@Override public void onDismiss(DialogInterface dialog) {
|
||||||
AriaManager.getInstance(AriaManager.APP).destroySchedulerListener(dialog);
|
AriaManager.getInstance(AriaManager.APP)
|
||||||
|
.destroySchedulerListener(dialog.getClass().getName());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.arialyy.aria.core.download;
|
|||||||
import android.support.annotation.CheckResult;
|
import android.support.annotation.CheckResult;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
import com.arialyy.aria.core.AriaManager;
|
import com.arialyy.aria.core.AriaManager;
|
||||||
import com.arialyy.aria.core.command.ICmd;
|
import com.arialyy.aria.core.command.ICmd;
|
||||||
import com.arialyy.aria.core.command.normal.CancelAllCmd;
|
import com.arialyy.aria.core.command.normal.CancelAllCmd;
|
||||||
@@ -27,6 +28,7 @@ import com.arialyy.aria.core.download.wrapper.DGEWrapper;
|
|||||||
import com.arialyy.aria.core.inf.AbsEntity;
|
import com.arialyy.aria.core.inf.AbsEntity;
|
||||||
import com.arialyy.aria.core.inf.AbsReceiver;
|
import com.arialyy.aria.core.inf.AbsReceiver;
|
||||||
import com.arialyy.aria.core.inf.AbsTarget;
|
import com.arialyy.aria.core.inf.AbsTarget;
|
||||||
|
import com.arialyy.aria.core.inf.ReceiverType;
|
||||||
import com.arialyy.aria.core.manager.TEManager;
|
import com.arialyy.aria.core.manager.TEManager;
|
||||||
import com.arialyy.aria.core.scheduler.DownloadGroupSchedulers;
|
import com.arialyy.aria.core.scheduler.DownloadGroupSchedulers;
|
||||||
import com.arialyy.aria.core.scheduler.DownloadSchedulers;
|
import com.arialyy.aria.core.scheduler.DownloadSchedulers;
|
||||||
@@ -229,15 +231,23 @@ public class DownloadReceiver extends AbsReceiver {
|
|||||||
* 将当前类注册到Aria
|
* 将当前类注册到Aria
|
||||||
*/
|
*/
|
||||||
public void register() {
|
public void register() {
|
||||||
String className = obj.getClass().getName();
|
if (TextUtils.isEmpty(targetName)) {
|
||||||
|
ALog.e(TAG, "download register target null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Object obj = OBJ_MAP.get(getKey());
|
||||||
|
if (obj == null) {
|
||||||
|
ALog.e(TAG, String.format("【%s】观察者为空", targetName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
Set<String> dCounter = ProxyHelper.getInstance().downloadCounter;
|
Set<String> dCounter = ProxyHelper.getInstance().downloadCounter;
|
||||||
Set<String> dgCounter = ProxyHelper.getInstance().downloadGroupCounter;
|
Set<String> dgCounter = ProxyHelper.getInstance().downloadGroupCounter;
|
||||||
Set<String> dgsCounter = ProxyHelper.getInstance().downloadGroupSubCounter;
|
Set<String> dgsCounter = ProxyHelper.getInstance().downloadGroupSubCounter;
|
||||||
if (dCounter != null && dCounter.contains(className)) {
|
if (dCounter != null && dCounter.contains(targetName)) {
|
||||||
DownloadSchedulers.getInstance().register(obj);
|
DownloadSchedulers.getInstance().register(obj);
|
||||||
}
|
}
|
||||||
if ((dgCounter != null && dgCounter.contains(className)) || (dgsCounter != null
|
if ((dgCounter != null && dgCounter.contains(targetName)) || (dgsCounter != null
|
||||||
&& dgsCounter.contains(className))) {
|
&& dgsCounter.contains(targetName))) {
|
||||||
DownloadGroupSchedulers.getInstance().register(obj);
|
DownloadGroupSchedulers.getInstance().register(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,25 +261,37 @@ public class DownloadReceiver extends AbsReceiver {
|
|||||||
if (needRmListener) {
|
if (needRmListener) {
|
||||||
unRegisterListener();
|
unRegisterListener();
|
||||||
}
|
}
|
||||||
AriaManager.getInstance(AriaManager.APP).removeReceiver(obj);
|
AriaManager.getInstance(AriaManager.APP).removeReceiver(targetName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override protected String getType() {
|
||||||
|
return ReceiverType.DOWNLOAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void unRegisterListener() {
|
@Override public void unRegisterListener() {
|
||||||
String className = obj.getClass().getName();
|
if (TextUtils.isEmpty(targetName)) {
|
||||||
|
ALog.e(TAG, "download unRegisterListener target null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Object obj = OBJ_MAP.get(getKey());
|
||||||
|
if (obj == null) {
|
||||||
|
ALog.e(TAG, String.format("【%s】观察者为空", targetName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
Set<String> dCounter = ProxyHelper.getInstance().downloadCounter;
|
Set<String> dCounter = ProxyHelper.getInstance().downloadCounter;
|
||||||
Set<String> dgCounter = ProxyHelper.getInstance().downloadGroupCounter;
|
Set<String> dgCounter = ProxyHelper.getInstance().downloadGroupCounter;
|
||||||
Set<String> dgsCounter = ProxyHelper.getInstance().downloadGroupSubCounter;
|
Set<String> dgsCounter = ProxyHelper.getInstance().downloadGroupSubCounter;
|
||||||
if (dCounter != null && dCounter.contains(className)) {
|
if (dCounter != null && dCounter.contains(targetName)) {
|
||||||
DownloadSchedulers.getInstance().unRegister(obj);
|
DownloadSchedulers.getInstance().unRegister(obj);
|
||||||
}
|
}
|
||||||
if (dgCounter != null && dgCounter.contains(className) || (dgsCounter != null
|
if (dgCounter != null && dgCounter.contains(targetName) || (dgsCounter != null
|
||||||
&& dgsCounter.contains(className))) {
|
&& dgsCounter.contains(targetName))) {
|
||||||
DownloadGroupSchedulers.getInstance().unRegister(obj);
|
DownloadGroupSchedulers.getInstance().unRegister(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void destroy() {
|
@Override public void destroy() {
|
||||||
targetName = null;
|
removeObj();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -338,8 +360,10 @@ public class DownloadReceiver extends AbsReceiver {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 下载任务是否存在
|
* 下载任务是否存在
|
||||||
|
*
|
||||||
|
* @return {@code true}存在,{@code false} 不存在
|
||||||
*/
|
*/
|
||||||
@Override public boolean taskExists(String downloadUrl) {
|
public boolean taskExists(String downloadUrl) {
|
||||||
return DownloadEntity.findFirst(DownloadEntity.class, "url=?", downloadUrl) != null;
|
return DownloadEntity.findFirst(DownloadEntity.class, "url=?", downloadUrl) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,7 +386,7 @@ public class DownloadReceiver extends AbsReceiver {
|
|||||||
* 获取未完成的普通任务列表{@link #getAllNotCompletTask()}
|
* 获取未完成的普通任务列表{@link #getAllNotCompletTask()}
|
||||||
* 获取已经完成的普通任务列表{@link #getAllCompleteTask()}
|
* 获取已经完成的普通任务列表{@link #getAllCompleteTask()}
|
||||||
*/
|
*/
|
||||||
@Override public List<DownloadEntity> getTaskList() {
|
public List<DownloadEntity> getTaskList() {
|
||||||
return DownloadEntity.findDatas(DownloadEntity.class, "isGroupChild=? and downloadPath!=''",
|
return DownloadEntity.findDatas(DownloadEntity.class, "isGroupChild=? and downloadPath!=''",
|
||||||
"false");
|
"false");
|
||||||
}
|
}
|
||||||
@@ -419,7 +443,7 @@ public class DownloadReceiver extends AbsReceiver {
|
|||||||
/**
|
/**
|
||||||
* 停止所有正在下载的任务,并清空等待队列。
|
* 停止所有正在下载的任务,并清空等待队列。
|
||||||
*/
|
*/
|
||||||
@Override public void stopAllTask() {
|
public void stopAllTask() {
|
||||||
AriaManager.getInstance(AriaManager.APP)
|
AriaManager.getInstance(AriaManager.APP)
|
||||||
.setCmd(NormalCmdFactory.getInstance()
|
.setCmd(NormalCmdFactory.getInstance()
|
||||||
.createCmd(targetName, new DownloadTaskEntity(), NormalCmdFactory.TASK_STOP_ALL,
|
.createCmd(targetName, new DownloadTaskEntity(), NormalCmdFactory.TASK_STOP_ALL,
|
||||||
@@ -446,7 +470,7 @@ public class DownloadReceiver extends AbsReceiver {
|
|||||||
* @param removeFile {@code true} 删除已经下载完成的任务,不仅删除下载记录,还会删除已经下载完成的文件,{@code false}
|
* @param removeFile {@code true} 删除已经下载完成的任务,不仅删除下载记录,还会删除已经下载完成的文件,{@code false}
|
||||||
* 如果文件已经下载完成,只删除下载记录
|
* 如果文件已经下载完成,只删除下载记录
|
||||||
*/
|
*/
|
||||||
@Override public void removeAllTask(boolean removeFile) {
|
public void removeAllTask(boolean removeFile) {
|
||||||
final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP);
|
final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP);
|
||||||
CancelAllCmd cancelCmd =
|
CancelAllCmd cancelCmd =
|
||||||
(CancelAllCmd) CommonUtil.createNormalCmd(targetName, new DownloadTaskEntity(),
|
(CancelAllCmd) CommonUtil.createNormalCmd(targetName, new DownloadTaskEntity(),
|
||||||
|
|||||||
@@ -16,19 +16,76 @@
|
|||||||
|
|
||||||
package com.arialyy.aria.core.inf;
|
package com.arialyy.aria.core.inf;
|
||||||
|
|
||||||
|
import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
|
||||||
|
import com.arialyy.aria.core.queue.DownloadTaskQueue;
|
||||||
|
import com.arialyy.aria.core.queue.UploadTaskQueue;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by AriaL on 2017/6/27.
|
* Created by AriaL on 2017/6/27.
|
||||||
|
* 接收器
|
||||||
*/
|
*/
|
||||||
|
public abstract class AbsReceiver implements IReceiver {
|
||||||
|
/**
|
||||||
|
* 观察者对象map
|
||||||
|
* key 由 {@link #getKey(String, IReceiver)}指定
|
||||||
|
*/
|
||||||
|
public static final Map<String, Object> OBJ_MAP = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public abstract class AbsReceiver<ENTITY extends AbsEntity> implements IReceiver<ENTITY> {
|
|
||||||
public String targetName;
|
public String targetName;
|
||||||
public Object obj;
|
|
||||||
/**
|
/**
|
||||||
* 当dialog、dialogFragment、popupwindow已经被设置了关闭监听时,需要手动移除receiver
|
* 当dialog、dialogFragment、popupwindow已经被设置了关闭监听时,需要手动移除receiver
|
||||||
*/
|
*/
|
||||||
public boolean needRmListener = false;
|
public boolean needRmListener = false;
|
||||||
|
|
||||||
public void unRegisterListener(){
|
/**
|
||||||
|
* 创建观察者对象map的key,生成规则:
|
||||||
|
* {@link #targetName}_{@code download}{@code upload}_{@link #hashCode()}
|
||||||
|
*
|
||||||
|
* @param type {@link ReceiverType}
|
||||||
|
* @param receiver 当前接收器
|
||||||
|
* @return 返回key
|
||||||
|
*/
|
||||||
|
public static String getKey(@ReceiverType String type, IReceiver receiver) {
|
||||||
|
return String.format("%s_%s_%s", receiver.getTargetName(), type, receiver.hashCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public String getTargetName() {
|
||||||
|
return targetName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前Receiver的key
|
||||||
|
*/
|
||||||
|
@Override public String getKey() {
|
||||||
|
return getKey(getType(), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除观察者对象
|
||||||
|
*/
|
||||||
|
protected void removeObj() {
|
||||||
|
for (Iterator<Map.Entry<String, Object>> iter = OBJ_MAP.entrySet().iterator();
|
||||||
|
iter.hasNext(); ) {
|
||||||
|
Map.Entry<String, Object> entry = iter.next();
|
||||||
|
String key = entry.getKey();
|
||||||
|
if (key.equals(getKey())) {
|
||||||
|
iter.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置类型
|
||||||
|
*
|
||||||
|
* @return {@link ReceiverType}
|
||||||
|
*/
|
||||||
|
protected abstract @ReceiverType String getType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除{@link DownloadTaskQueue}、{@link DownloadGroupTaskQueue}、{@link UploadTaskQueue}中注册的观察者
|
||||||
|
*/
|
||||||
|
public abstract void unRegisterListener();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,17 +15,19 @@
|
|||||||
*/
|
*/
|
||||||
package com.arialyy.aria.core.inf;
|
package com.arialyy.aria.core.inf;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by lyy on 2017/2/6.
|
* Created by lyy on 2017/2/6.
|
||||||
*/
|
*/
|
||||||
public interface IReceiver<ENTITY extends IEntity> {
|
public interface IReceiver {
|
||||||
/**
|
/**
|
||||||
* Receiver 销毁
|
* Receiver 销毁
|
||||||
*/
|
*/
|
||||||
void destroy();
|
void destroy();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册
|
||||||
|
*/
|
||||||
|
void register();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 移除观察者
|
* 移除观察者
|
||||||
@@ -33,24 +35,12 @@ public interface IReceiver<ENTITY extends IEntity> {
|
|||||||
void unRegister();
|
void unRegister();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 停止所有任务
|
* 观察者对象的类完整名称
|
||||||
*/
|
*/
|
||||||
void stopAllTask();
|
String getTargetName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除所有任务
|
* 获取当前Receiver的key
|
||||||
*/
|
*/
|
||||||
void removeAllTask(boolean removeFile);
|
String getKey();
|
||||||
|
|
||||||
/**
|
|
||||||
* 任务是否存在
|
|
||||||
*
|
|
||||||
* @param key 下载时为下载路径,上传时为文件路径
|
|
||||||
*/
|
|
||||||
boolean taskExists(String key);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取任务列表
|
|
||||||
*/
|
|
||||||
List<ENTITY> getTaskList();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.arialyy.aria.core.inf;
|
||||||
|
|
||||||
|
import android.support.annotation.StringDef;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link AbsReceiver}类型
|
||||||
|
*/
|
||||||
|
@StringDef({
|
||||||
|
ReceiverType.DOWNLOAD,
|
||||||
|
ReceiverType.UPLOAD,
|
||||||
|
})
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
public @interface ReceiverType {
|
||||||
|
String DOWNLOAD = "download";
|
||||||
|
String UPLOAD = "upload";
|
||||||
|
}
|
||||||
@@ -23,8 +23,10 @@ import com.arialyy.aria.core.command.ICmd;
|
|||||||
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
|
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
|
||||||
import com.arialyy.aria.core.common.ProxyHelper;
|
import com.arialyy.aria.core.common.ProxyHelper;
|
||||||
import com.arialyy.aria.core.inf.AbsReceiver;
|
import com.arialyy.aria.core.inf.AbsReceiver;
|
||||||
|
import com.arialyy.aria.core.inf.ReceiverType;
|
||||||
import com.arialyy.aria.core.scheduler.UploadSchedulers;
|
import com.arialyy.aria.core.scheduler.UploadSchedulers;
|
||||||
import com.arialyy.aria.orm.DbEntity;
|
import com.arialyy.aria.orm.DbEntity;
|
||||||
|
import com.arialyy.aria.util.ALog;
|
||||||
import com.arialyy.aria.util.CheckUtil;
|
import com.arialyy.aria.util.CheckUtil;
|
||||||
import com.arialyy.aria.util.CommonUtil;
|
import com.arialyy.aria.util.CommonUtil;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -34,7 +36,7 @@ import java.util.Set;
|
|||||||
* Created by lyy on 2017/2/6.
|
* Created by lyy on 2017/2/6.
|
||||||
* 上传功能接收器
|
* 上传功能接收器
|
||||||
*/
|
*/
|
||||||
public class UploadReceiver extends AbsReceiver<UploadEntity> {
|
public class UploadReceiver extends AbsReceiver {
|
||||||
private static final String TAG = "UploadReceiver";
|
private static final String TAG = "UploadReceiver";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -71,9 +73,11 @@ public class UploadReceiver extends AbsReceiver<UploadEntity> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 下载任务是否存在
|
* 上传任务是否存在
|
||||||
|
*
|
||||||
|
* @return {@code true}存在,{@code false} 不存在
|
||||||
*/
|
*/
|
||||||
@Override public boolean taskExists(String filePath) {
|
public boolean taskExists(String filePath) {
|
||||||
return DbEntity.findFirst(UploadEntity.class, "filePath=?", filePath) != null;
|
return DbEntity.findFirst(UploadEntity.class, "filePath=?", filePath) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +86,7 @@ public class UploadReceiver extends AbsReceiver<UploadEntity> {
|
|||||||
* 获取未完成的普通任务列表{@link #getAllNotCompletTask()}
|
* 获取未完成的普通任务列表{@link #getAllNotCompletTask()}
|
||||||
* 获取已经完成的普通任务列表{@link #getAllCompleteTask()}
|
* 获取已经完成的普通任务列表{@link #getAllCompleteTask()}
|
||||||
*/
|
*/
|
||||||
@Override public List<UploadEntity> getTaskList() {
|
public List<UploadEntity> getTaskList() {
|
||||||
return DbEntity.findAllData(UploadEntity.class);
|
return DbEntity.findAllData(UploadEntity.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +106,10 @@ public class UploadReceiver extends AbsReceiver<UploadEntity> {
|
|||||||
"isGroupChild=? and isComplete=?", "false", "true");
|
"isGroupChild=? and isComplete=?", "false", "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void stopAllTask() {
|
/**
|
||||||
|
* 停止所有正在下载的任务,并清空等待队列。
|
||||||
|
*/
|
||||||
|
public void stopAllTask() {
|
||||||
AriaManager.getInstance(AriaManager.APP)
|
AriaManager.getInstance(AriaManager.APP)
|
||||||
.setCmd(NormalCmdFactory.getInstance()
|
.setCmd(NormalCmdFactory.getInstance()
|
||||||
.createCmd(targetName, new UploadTaskEntity(), NormalCmdFactory.TASK_STOP_ALL,
|
.createCmd(targetName, new UploadTaskEntity(), NormalCmdFactory.TASK_STOP_ALL,
|
||||||
@@ -116,7 +123,7 @@ public class UploadReceiver extends AbsReceiver<UploadEntity> {
|
|||||||
* @param removeFile {@code true} 删除已经上传完成的任务,不仅删除上传记录,还会删除已经上传完成的文件,{@code false}
|
* @param removeFile {@code true} 删除已经上传完成的任务,不仅删除上传记录,还会删除已经上传完成的文件,{@code false}
|
||||||
* 如果文件已经上传完成,只删除上传记录
|
* 如果文件已经上传完成,只删除上传记录
|
||||||
*/
|
*/
|
||||||
@Override public void removeAllTask(boolean removeFile) {
|
public void removeAllTask(boolean removeFile) {
|
||||||
final AriaManager am = AriaManager.getInstance(AriaManager.APP);
|
final AriaManager am = AriaManager.getInstance(AriaManager.APP);
|
||||||
|
|
||||||
am.setCmd(CommonUtil.createNormalCmd(targetName, new UploadTaskEntity(),
|
am.setCmd(CommonUtil.createNormalCmd(targetName, new UploadTaskEntity(),
|
||||||
@@ -129,16 +136,24 @@ public class UploadReceiver extends AbsReceiver<UploadEntity> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override public void destroy() {
|
@Override public void destroy() {
|
||||||
targetName = null;
|
removeObj();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将当前类注册到Aria
|
* 将当前类注册到Aria
|
||||||
*/
|
*/
|
||||||
public void register() {
|
public void register() {
|
||||||
String className = obj.getClass().getName();
|
if (TextUtils.isEmpty(targetName)) {
|
||||||
|
ALog.e(TAG, "upload register target null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Object obj = OBJ_MAP.get(getKey());
|
||||||
|
if (obj == null) {
|
||||||
|
ALog.e(TAG, String.format("【%s】观察者为空", targetName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
Set<String> cCounter = ProxyHelper.getInstance().uploadCounter;
|
Set<String> cCounter = ProxyHelper.getInstance().uploadCounter;
|
||||||
if (cCounter != null && cCounter.contains(className)) {
|
if (cCounter != null && cCounter.contains(targetName)) {
|
||||||
UploadSchedulers.getInstance().register(obj);
|
UploadSchedulers.getInstance().register(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,13 +166,25 @@ public class UploadReceiver extends AbsReceiver<UploadEntity> {
|
|||||||
if (needRmListener) {
|
if (needRmListener) {
|
||||||
unRegisterListener();
|
unRegisterListener();
|
||||||
}
|
}
|
||||||
AriaManager.getInstance(AriaManager.APP).removeReceiver(obj);
|
AriaManager.getInstance(AriaManager.APP).removeReceiver(targetName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override protected String getType() {
|
||||||
|
return ReceiverType.UPLOAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void unRegisterListener() {
|
@Override public void unRegisterListener() {
|
||||||
String className = obj.getClass().getName();
|
if (TextUtils.isEmpty(targetName)) {
|
||||||
|
ALog.e(TAG, "upload unRegisterListener target null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Object obj = OBJ_MAP.get(getKey());
|
||||||
|
if (obj == null) {
|
||||||
|
ALog.e(TAG, String.format("【%s】观察者为空", targetName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
Set<String> dCounter = ProxyHelper.getInstance().uploadCounter;
|
Set<String> dCounter = ProxyHelper.getInstance().uploadCounter;
|
||||||
if (dCounter != null && dCounter.contains(className)) {
|
if (dCounter != null && dCounter.contains(targetName)) {
|
||||||
UploadSchedulers.getInstance().unRegister(obj);
|
UploadSchedulers.getInstance().unRegister(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import android.net.Uri;
|
|||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
import android.util.Log;
|
|
||||||
import com.arialyy.aria.core.AriaManager;
|
import com.arialyy.aria.core.AriaManager;
|
||||||
import com.arialyy.aria.core.FtpUrlEntity;
|
import com.arialyy.aria.core.FtpUrlEntity;
|
||||||
import com.arialyy.aria.core.command.ICmd;
|
import com.arialyy.aria.core.command.ICmd;
|
||||||
@@ -106,6 +105,11 @@ public class CommonUtil {
|
|||||||
public static List<String> getPkgClassName(String path, String filterClass) {
|
public static List<String> getPkgClassName(String path, String filterClass) {
|
||||||
List<String> list = new ArrayList<>();
|
List<String> list = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
|
File file = new File(path);
|
||||||
|
if (!file.exists()) {
|
||||||
|
ALog.w(TAG, String.format("路径【%s】下的Dex文件不存在", path));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
DexFile df = new DexFile(path);//通过DexFile查找当前的APK中可执行文件
|
DexFile df = new DexFile(path);//通过DexFile查找当前的APK中可执行文件
|
||||||
Enumeration<String> enumeration = df.entries();//获取df中的元素 这里包含了所有可执行的类名 该类名包含了包名+类名的方式
|
Enumeration<String> enumeration = df.entries();//获取df中的元素 这里包含了所有可执行的类名 该类名包含了包名+类名的方式
|
||||||
|
|||||||
148
Aria/src/main/java/com/arialyy/aria/util/FileUtil.java
Normal file
148
Aria/src/main/java/com/arialyy/aria/util/FileUtil.java
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.arialyy.aria.util;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.SequenceInputStream;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.Channels;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.nio.channels.ReadableByteChannel;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件操作工具类
|
||||||
|
*/
|
||||||
|
public class FileUtil {
|
||||||
|
private static final String TAG = "FileUtil";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合并文件
|
||||||
|
*
|
||||||
|
* @param targetPath 目标文件
|
||||||
|
* @param subPaths 碎片文件路径
|
||||||
|
*/
|
||||||
|
public static void mergeFile(String targetPath, List<String> subPaths) {
|
||||||
|
File file = new File(targetPath);
|
||||||
|
FileOutputStream fos = null;
|
||||||
|
FileChannel foc = null;
|
||||||
|
try {
|
||||||
|
if (!file.exists()) {
|
||||||
|
file.createNewFile();
|
||||||
|
fos = new FileOutputStream(targetPath);
|
||||||
|
foc = fos.getChannel();
|
||||||
|
List<FileInputStream> streams = new LinkedList<>();
|
||||||
|
for (String subPath : subPaths) {
|
||||||
|
File f = new File(subPath);
|
||||||
|
if (!f.exists()) {
|
||||||
|
ALog.d(TAG, String.format("合并文件失败,文件【%s】不存在", subPath));
|
||||||
|
for (FileInputStream fis : streams) {
|
||||||
|
fis.close();
|
||||||
|
}
|
||||||
|
streams.clear();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
streams.add(new FileInputStream(subPath));
|
||||||
|
}
|
||||||
|
Enumeration<FileInputStream> en = Collections.enumeration(streams);
|
||||||
|
SequenceInputStream sis = new SequenceInputStream(en);
|
||||||
|
ReadableByteChannel fic = Channels.newChannel(sis);
|
||||||
|
ByteBuffer bf = ByteBuffer.allocate(8196);
|
||||||
|
while (fic.read(bf) != -1) {
|
||||||
|
bf.flip();
|
||||||
|
foc.write(bf);
|
||||||
|
bf.compact();
|
||||||
|
}
|
||||||
|
fic.close();
|
||||||
|
sis.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (foc != null) {
|
||||||
|
foc.close();
|
||||||
|
}
|
||||||
|
if (fos != null) {
|
||||||
|
fos.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分割文件
|
||||||
|
*
|
||||||
|
* @param filePath 被分割的文件路径
|
||||||
|
* @param num 分割的块数
|
||||||
|
*/
|
||||||
|
public static void splitFile(String filePath, int num) {
|
||||||
|
try {
|
||||||
|
final File file = new File(filePath);
|
||||||
|
long size = file.length();
|
||||||
|
FileInputStream fis = new FileInputStream(file);
|
||||||
|
FileChannel fic = fis.getChannel();
|
||||||
|
long j = 0;
|
||||||
|
long block = size / num;
|
||||||
|
for (int i = 0; i < num; i++) {
|
||||||
|
if (i == num - 1) {
|
||||||
|
block = size - block * (num - 1);
|
||||||
|
}
|
||||||
|
String subPath = file.getPath() + "." + i + ".part";
|
||||||
|
ALog.d(TAG, String.format("block = %s", block));
|
||||||
|
File subFile = new File(subPath);
|
||||||
|
if (!subFile.exists()) {
|
||||||
|
subFile.createNewFile();
|
||||||
|
}
|
||||||
|
FileOutputStream fos = new FileOutputStream(subFile);
|
||||||
|
FileChannel sfoc = fos.getChannel();
|
||||||
|
ByteBuffer bf = ByteBuffer.allocate(8196);
|
||||||
|
int len;
|
||||||
|
//fis.skip(block * i);
|
||||||
|
while ((len = fic.read(bf)) != -1) {
|
||||||
|
bf.flip();
|
||||||
|
sfoc.write(bf);
|
||||||
|
bf.compact();
|
||||||
|
j += len;
|
||||||
|
if (j >= block * (i + 1)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ALog.d(TAG, String.format("len = %s", subFile.length()));
|
||||||
|
fos.close();
|
||||||
|
sfoc.close();
|
||||||
|
}
|
||||||
|
fis.close();
|
||||||
|
fic.close();
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -254,6 +254,6 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
|
|||||||
|
|
||||||
@Override protected void onStop() {
|
@Override protected void onStop() {
|
||||||
super.onStop();
|
super.onStop();
|
||||||
//Aria.download(this).unRegister();
|
Aria.download(this).unRegister();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,7 +39,7 @@ task clean(type: Delete) {
|
|||||||
ext {
|
ext {
|
||||||
userOrg = 'arialyy'
|
userOrg = 'arialyy'
|
||||||
groupId = 'com.arialyy.aria'
|
groupId = 'com.arialyy.aria'
|
||||||
publishVersion = '3.4.2_dev6'
|
publishVersion = '3.4.3_dev1'
|
||||||
// publishVersion = '1.0.3' //FTP插件
|
// publishVersion = '1.0.3' //FTP插件
|
||||||
repoName='maven'
|
repoName='maven'
|
||||||
desc = 'android 下载框架'
|
desc = 'android 下载框架'
|
||||||
|
|||||||
Reference in New Issue
Block a user