修复一个匿名内部类中的内存溢出的问题 https://github.com/AriaLyy/Aria/issues/705
m3u8密钥下载地址转换器增加ts列表的url地址https://github.com/AriaLyy/Aria/issues/718
This commit is contained in:
@@ -27,6 +27,7 @@ import android.widget.PopupWindow;
|
|||||||
import com.arialyy.aria.core.download.DownloadReceiver;
|
import com.arialyy.aria.core.download.DownloadReceiver;
|
||||||
import com.arialyy.aria.core.upload.UploadReceiver;
|
import com.arialyy.aria.core.upload.UploadReceiver;
|
||||||
import com.arialyy.aria.util.ALog;
|
import com.arialyy.aria.util.ALog;
|
||||||
|
import com.arialyy.aria.util.CommonUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by lyy on 2016/12/1.
|
* Created by lyy on 2016/12/1.
|
||||||
@@ -134,8 +135,8 @@ import com.arialyy.aria.util.ALog;
|
|||||||
return (Service) obj;
|
return (Service) obj;
|
||||||
} else if (obj instanceof Activity) {
|
} else if (obj instanceof Activity) {
|
||||||
return (Activity) obj;
|
return (Activity) obj;
|
||||||
} else if (AriaManager.isFragment(obj.getClass())) {
|
} else if (CommonUtil.isFragment(obj.getClass())) {
|
||||||
return AriaManager.getFragmentActivity(obj);
|
return CommonUtil.getFragmentActivity(obj);
|
||||||
} else if (obj instanceof Dialog) {
|
} else if (obj instanceof Dialog) {
|
||||||
return ((Dialog) obj).getContext();
|
return ((Dialog) obj).getContext();
|
||||||
} else if (obj instanceof PopupWindow) {
|
} else if (obj instanceof PopupWindow) {
|
||||||
|
|||||||
@@ -19,11 +19,10 @@ import android.annotation.SuppressLint;
|
|||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.widget.PopupWindow;
|
import android.util.Log;
|
||||||
import com.arialyy.aria.core.command.CommandManager;
|
import com.arialyy.aria.core.command.CommandManager;
|
||||||
import com.arialyy.aria.core.common.QueueMod;
|
import com.arialyy.aria.core.common.QueueMod;
|
||||||
import com.arialyy.aria.core.config.AppConfig;
|
import com.arialyy.aria.core.config.AppConfig;
|
||||||
@@ -35,23 +34,19 @@ import com.arialyy.aria.core.download.DownloadGroupEntity;
|
|||||||
import com.arialyy.aria.core.download.DownloadReceiver;
|
import com.arialyy.aria.core.download.DownloadReceiver;
|
||||||
import com.arialyy.aria.core.inf.AbsReceiver;
|
import com.arialyy.aria.core.inf.AbsReceiver;
|
||||||
import com.arialyy.aria.core.inf.IReceiver;
|
import com.arialyy.aria.core.inf.IReceiver;
|
||||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
|
||||||
import com.arialyy.aria.core.inf.ReceiverType;
|
import com.arialyy.aria.core.inf.ReceiverType;
|
||||||
|
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||||
import com.arialyy.aria.core.upload.UploadEntity;
|
import com.arialyy.aria.core.upload.UploadEntity;
|
||||||
import com.arialyy.aria.core.upload.UploadReceiver;
|
import com.arialyy.aria.core.upload.UploadReceiver;
|
||||||
import com.arialyy.aria.orm.DbEntity;
|
import com.arialyy.aria.orm.DbEntity;
|
||||||
import com.arialyy.aria.orm.DelegateWrapper;
|
import com.arialyy.aria.orm.DelegateWrapper;
|
||||||
import com.arialyy.aria.util.ALog;
|
import com.arialyy.aria.util.ALog;
|
||||||
import com.arialyy.aria.util.AriaCrashHandler;
|
import com.arialyy.aria.util.AriaCrashHandler;
|
||||||
import com.arialyy.aria.util.DeleteDGRecord;
|
import com.arialyy.aria.util.CommonUtil;
|
||||||
import com.arialyy.aria.util.DeleteURecord;
|
import com.arialyy.aria.util.DeleteURecord;
|
||||||
import com.arialyy.aria.util.RecordUtil;
|
import com.arialyy.aria.util.RecordUtil;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@@ -63,35 +58,12 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
private static final String TAG = "AriaManager";
|
private static final String TAG = "AriaManager";
|
||||||
private static final Object LOCK = new Object();
|
private static final Object LOCK = new Object();
|
||||||
|
|
||||||
/**
|
|
||||||
* android、androidx、support的fragment、dialogFragment类名
|
|
||||||
*/
|
|
||||||
private static List<String> mFragmentClassName = new ArrayList<>();
|
|
||||||
private static List<String> mDialogFragmentClassName = new ArrayList<>();
|
|
||||||
|
|
||||||
@SuppressLint("StaticFieldLeak") private static volatile AriaManager INSTANCE = null;
|
@SuppressLint("StaticFieldLeak") private static volatile AriaManager INSTANCE = null;
|
||||||
private Map<String, AbsReceiver> mReceivers = new ConcurrentHashMap<>();
|
private Map<String, AbsReceiver> mReceivers = new ConcurrentHashMap<>();
|
||||||
/**
|
|
||||||
* activity 和其Dialog、Fragment的映射表
|
|
||||||
*/
|
|
||||||
private Map<String, List<String>> mSubClass = new ConcurrentHashMap<>();
|
|
||||||
private static Context APP;
|
private static Context APP;
|
||||||
private DelegateWrapper mDbWrapper;
|
private DelegateWrapper mDbWrapper;
|
||||||
private AriaConfig mConfig;
|
private AriaConfig mConfig;
|
||||||
|
|
||||||
static {
|
|
||||||
mFragmentClassName.add("androidx.fragment.app.Fragment");
|
|
||||||
mFragmentClassName.add("androidx.fragment.app.DialogFragment");
|
|
||||||
mFragmentClassName.add("android.app.Fragment");
|
|
||||||
mFragmentClassName.add("android.app.DialogFragment");
|
|
||||||
mFragmentClassName.add("android.support.v4.app.Fragment");
|
|
||||||
mFragmentClassName.add("android.support.v4.app.DialogFragment");
|
|
||||||
|
|
||||||
mDialogFragmentClassName.add("androidx.fragment.app.DialogFragment");
|
|
||||||
mDialogFragmentClassName.add("android.app.DialogFragment");
|
|
||||||
mDialogFragmentClassName.add("android.support.v4.app.DialogFragment");
|
|
||||||
}
|
|
||||||
|
|
||||||
private AriaManager(Context context) {
|
private AriaManager(Context context) {
|
||||||
APP = context.getApplicationContext();
|
APP = context.getApplicationContext();
|
||||||
}
|
}
|
||||||
@@ -253,6 +225,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
* 处理下载操作
|
* 处理下载操作
|
||||||
*/
|
*/
|
||||||
DownloadReceiver download(Object obj) {
|
DownloadReceiver download(Object obj) {
|
||||||
|
|
||||||
IReceiver receiver = mReceivers.get(getKey(ReceiverType.DOWNLOAD, obj));
|
IReceiver receiver = mReceivers.get(getKey(ReceiverType.DOWNLOAD, obj));
|
||||||
if (receiver == null) {
|
if (receiver == null) {
|
||||||
receiver = putReceiver(ReceiverType.DOWNLOAD, obj);
|
receiver = putReceiver(ReceiverType.DOWNLOAD, obj);
|
||||||
@@ -292,138 +265,19 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IReceiver putReceiver(String type, Object obj) {
|
private IReceiver putReceiver(ReceiverType type, Object obj) {
|
||||||
final String key = getKey(type, obj);
|
final String key = getKey(type, obj);
|
||||||
IReceiver receiver = mReceivers.get(key);
|
IReceiver receiver = mReceivers.get(key);
|
||||||
boolean needRmReceiver = false;
|
|
||||||
// 监控Dialog、fragment、popupWindow的生命周期
|
|
||||||
final WidgetLiftManager widgetLiftManager = new WidgetLiftManager();
|
|
||||||
Context subParenActivity = null;
|
|
||||||
|
|
||||||
if (obj instanceof Dialog) {
|
|
||||||
needRmReceiver = widgetLiftManager.handleDialogLift((Dialog) obj);
|
|
||||||
subParenActivity = ((Dialog) obj).getOwnerActivity();
|
|
||||||
} else if (obj instanceof PopupWindow) {
|
|
||||||
needRmReceiver = widgetLiftManager.handlePopupWindowLift((PopupWindow) obj);
|
|
||||||
subParenActivity = ((PopupWindow) obj).getContentView().getContext();
|
|
||||||
} else if (isDialogFragment(obj.getClass())) {
|
|
||||||
needRmReceiver = widgetLiftManager.handleDialogFragmentLift(getDialog(obj));
|
|
||||||
subParenActivity = getFragmentActivity(obj);
|
|
||||||
} else if (isFragment(obj.getClass())) {
|
|
||||||
subParenActivity = getFragmentActivity(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subParenActivity instanceof Activity) {
|
|
||||||
relateSubClass(type, obj, (Activity) subParenActivity);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (receiver == null) {
|
if (receiver == null) {
|
||||||
AbsReceiver absReceiver =
|
AbsReceiver absReceiver =
|
||||||
type.equals(ReceiverType.DOWNLOAD) ? new DownloadReceiver() : new UploadReceiver();
|
type.equals(ReceiverType.DOWNLOAD) ? new DownloadReceiver(obj) : new UploadReceiver(obj);
|
||||||
absReceiver.targetName = obj.getClass().getName();
|
|
||||||
AbsReceiver.OBJ_MAP.put(absReceiver.getKey(), obj);
|
|
||||||
absReceiver.needRmListener = needRmReceiver;
|
|
||||||
mReceivers.put(key, absReceiver);
|
mReceivers.put(key, absReceiver);
|
||||||
receiver = absReceiver;
|
receiver = absReceiver;
|
||||||
}
|
}
|
||||||
return receiver;
|
return receiver;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取fragment的activity
|
|
||||||
*
|
|
||||||
* @return 获取失败,返回null
|
|
||||||
*/
|
|
||||||
static Activity getFragmentActivity(Object obj) {
|
|
||||||
try {
|
|
||||||
Method method = obj.getClass().getMethod("getActivity");
|
|
||||||
return (Activity) method.invoke(obj);
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断注解对象是否是fragment
|
|
||||||
*
|
|
||||||
* @return true 对象是fragment
|
|
||||||
*/
|
|
||||||
static boolean isFragment(Class subClazz) {
|
|
||||||
Class parentClass = subClazz.getSuperclass();
|
|
||||||
if (parentClass == null) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
String parentName = parentClass.getName();
|
|
||||||
if (mFragmentClassName.contains(parentName)) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return isFragment(parentClass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断对象是否是DialogFragment
|
|
||||||
*
|
|
||||||
* @return true 对象是DialogFragment
|
|
||||||
*/
|
|
||||||
private boolean isDialogFragment(Class subClazz) {
|
|
||||||
Class parentClass = subClazz.getSuperclass();
|
|
||||||
if (parentClass == null) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
String parentName = parentClass.getName();
|
|
||||||
if (mDialogFragmentClassName.contains(parentName)) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return isDialogFragment(parentClass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取DialogFragment的dialog
|
|
||||||
*
|
|
||||||
* @return 获取失败,返回null
|
|
||||||
*/
|
|
||||||
private Dialog getDialog(Object obj) {
|
|
||||||
try {
|
|
||||||
Method method = obj.getClass().getMethod("getDialog");
|
|
||||||
return (Dialog) method.invoke(obj);
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 关联Activity类和Fragment间的关系
|
|
||||||
*
|
|
||||||
* @param sub Fragment或dialog类
|
|
||||||
* @param activity activity寄主类
|
|
||||||
*/
|
|
||||||
private void relateSubClass(String type, Object sub, Activity activity) {
|
|
||||||
String key = getKey(type, activity);
|
|
||||||
List<String> subClass = mSubClass.get(key);
|
|
||||||
if (subClass == null) {
|
|
||||||
subClass = new ArrayList<>();
|
|
||||||
mSubClass.put(key, subClass);
|
|
||||||
}
|
|
||||||
subClass.add(getKey(type, sub));
|
|
||||||
if (mReceivers.get(key) == null) { // 将activity填充进去
|
|
||||||
mReceivers.put(key, new DownloadReceiver());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据功能类型和控件类型获取对应的key
|
* 根据功能类型和控件类型获取对应的key
|
||||||
*
|
*
|
||||||
@@ -432,8 +286,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
* @return key的格式为:{@code String.format("%s_%s_%s", obj.getClass().getName(), type,
|
* @return key的格式为:{@code String.format("%s_%s_%s", obj.getClass().getName(), type,
|
||||||
* obj.hashCode());}
|
* obj.hashCode());}
|
||||||
*/
|
*/
|
||||||
private String getKey(String type, Object obj) {
|
private String getKey(ReceiverType type, Object obj) {
|
||||||
return String.format("%s_%s_%s", obj.getClass().getName(), type, obj.hashCode());
|
return String.format("%s_%s_%s", CommonUtil.getTargetName(obj), type.name(), obj.hashCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -455,40 +309,27 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
ALog.e(TAG, "target obj is null");
|
ALog.e(TAG, "target obj is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<String> temp = new ArrayList<>();
|
|
||||||
// 移除寄主的receiver
|
// 移除寄主的receiver
|
||||||
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.equals(getKey(ReceiverType.DOWNLOAD, obj)) || key.equals(
|
AbsReceiver receiver = entry.getValue();
|
||||||
getKey(ReceiverType.UPLOAD, obj))) {
|
if ((receiver.isLocalOrAnonymousClass || receiver.isFragment())
|
||||||
AbsReceiver receiver = mReceivers.get(key);
|
&& key.startsWith(obj.getClass().getName())) {
|
||||||
List<String> subNames = mSubClass.get(key);
|
receiver.destroy();
|
||||||
if (subNames != null && !subNames.isEmpty()) {
|
iter.remove();
|
||||||
temp.addAll(subNames);
|
continue;
|
||||||
}
|
}
|
||||||
if (receiver != null) {
|
|
||||||
receiver.destroy();
|
if (key.equals(getKey(ReceiverType.DOWNLOAD, obj))
|
||||||
}
|
|| key.equals(getKey(ReceiverType.UPLOAD, obj))
|
||||||
|
) {
|
||||||
|
receiver.destroy();
|
||||||
iter.remove();
|
iter.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Log.d(TAG, "debug");
|
||||||
// 移除寄生的receiver
|
|
||||||
if (!temp.isEmpty()) {
|
|
||||||
for (Iterator<Map.Entry<String, AbsReceiver>> iter = mReceivers.entrySet().iterator();
|
|
||||||
iter.hasNext(); ) {
|
|
||||||
Map.Entry<String, AbsReceiver> entry = iter.next();
|
|
||||||
if (temp.contains(entry.getKey())) {
|
|
||||||
AbsReceiver receiver = mReceivers.get(entry.getKey());
|
|
||||||
if (receiver != null) {
|
|
||||||
receiver.destroy();
|
|
||||||
}
|
|
||||||
iter.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -29,20 +29,20 @@ import java.lang.reflect.Field;
|
|||||||
* Created by lyy on 2017/2/7.
|
* Created by lyy on 2017/2/7.
|
||||||
* 为组件添加生命周期
|
* 为组件添加生命周期
|
||||||
*/
|
*/
|
||||||
final class WidgetLiftManager {
|
public final class WidgetLiftManager {
|
||||||
private final String TAG = "WidgetLiftManager";
|
private final String TAG = "WidgetLiftManager";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理DialogFragment事件
|
* 处理DialogFragment事件
|
||||||
*/
|
*/
|
||||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB) boolean handleDialogFragmentLift(Dialog dialog) {
|
@TargetApi(Build.VERSION_CODES.HONEYCOMB) public boolean handleDialogFragmentLift(Dialog dialog) {
|
||||||
return handleDialogLift(dialog);
|
return handleDialogLift(dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理悬浮框取消或dismiss事件
|
* 处理悬浮框取消或dismiss事件
|
||||||
*/
|
*/
|
||||||
boolean handlePopupWindowLift(PopupWindow popupWindow) {
|
public boolean handlePopupWindowLift(PopupWindow popupWindow) {
|
||||||
try {
|
try {
|
||||||
Field dismissField = CommonUtil.getField(popupWindow.getClass(), "mOnDismissListener");
|
Field dismissField = CommonUtil.getField(popupWindow.getClass(), "mOnDismissListener");
|
||||||
PopupWindow.OnDismissListener listener =
|
PopupWindow.OnDismissListener listener =
|
||||||
@@ -76,7 +76,7 @@ final class WidgetLiftManager {
|
|||||||
*
|
*
|
||||||
* @return true 设置了dialog的销毁事件。false 没有设置dialog的销毁事件
|
* @return true 设置了dialog的销毁事件。false 没有设置dialog的销毁事件
|
||||||
*/
|
*/
|
||||||
boolean handleDialogLift(Dialog dialog) {
|
public boolean handleDialogLift(Dialog dialog) {
|
||||||
if (dialog == null) {
|
if (dialog == null) {
|
||||||
ALog.w(TAG,
|
ALog.w(TAG,
|
||||||
"dialog 为空,没有设置自动销毁事件,为了防止内存泄露,请在dismiss方法中调用Aria.download(this).unRegister();来注销事件\n"
|
"dialog 为空,没有设置自动销毁事件,为了防止内存泄露,请在dismiss方法中调用Aria.download(this).unRegister();来注销事件\n"
|
||||||
|
|||||||
@@ -55,7 +55,10 @@ import java.util.Set;
|
|||||||
* 下载功能接收器
|
* 下载功能接收器
|
||||||
*/
|
*/
|
||||||
public class DownloadReceiver extends AbsReceiver {
|
public class DownloadReceiver extends AbsReceiver {
|
||||||
private final String TAG = "DownloadReceiver";
|
|
||||||
|
public DownloadReceiver(Object obj) {
|
||||||
|
super(obj);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置最大下载速度,单位:kb
|
* 设置最大下载速度,单位:kb
|
||||||
@@ -164,7 +167,6 @@ public class DownloadReceiver extends AbsReceiver {
|
|||||||
* 将当前类注册到Aria
|
* 将当前类注册到Aria
|
||||||
*/
|
*/
|
||||||
public void register() {
|
public void register() {
|
||||||
Object obj = OBJ_MAP.get(getKey());
|
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
ALog.e(TAG, String.format("register【%s】观察者为空", getTargetName()));
|
ALog.e(TAG, String.format("register【%s】观察者为空", getTargetName()));
|
||||||
return;
|
return;
|
||||||
@@ -199,18 +201,17 @@ public class DownloadReceiver extends AbsReceiver {
|
|||||||
* @see <a href="https://aria.laoyuyu.me/aria_doc/start/any_java.html#%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9">module类中销毁</a>
|
* @see <a href="https://aria.laoyuyu.me/aria_doc/start/any_java.html#%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9">module类中销毁</a>
|
||||||
*/
|
*/
|
||||||
@Override public void unRegister() {
|
@Override public void unRegister() {
|
||||||
if (needRmListener) {
|
if (isNeedRmListener()) {
|
||||||
unRegisterListener();
|
unRegisterListener();
|
||||||
}
|
}
|
||||||
AriaManager.getInstance().removeReceiver(OBJ_MAP.get(getKey()));
|
AriaManager.getInstance().removeReceiver(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public String getType() {
|
@Override public ReceiverType getType() {
|
||||||
return ReceiverType.DOWNLOAD;
|
return ReceiverType.DOWNLOAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override protected void unRegisterListener() {
|
@Override protected void unRegisterListener() {
|
||||||
Object obj = OBJ_MAP.get(getKey());
|
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
ALog.e(TAG, String.format("unRegister【%s】观察者为空", getTargetName()));
|
ALog.e(TAG, String.format("unRegister【%s】观察者为空", getTargetName()));
|
||||||
return;
|
return;
|
||||||
@@ -220,7 +221,9 @@ public class DownloadReceiver extends AbsReceiver {
|
|||||||
for (Integer integer : set) {
|
for (Integer integer : set) {
|
||||||
if (integer == ProxyHelper.PROXY_TYPE_DOWNLOAD) {
|
if (integer == ProxyHelper.PROXY_TYPE_DOWNLOAD) {
|
||||||
TaskSchedulers.getInstance().unRegister(obj);
|
TaskSchedulers.getInstance().unRegister(obj);
|
||||||
} else if (integer == ProxyHelper.PROXY_TYPE_DOWNLOAD_GROUP) {
|
continue;
|
||||||
|
}
|
||||||
|
if (integer == ProxyHelper.PROXY_TYPE_DOWNLOAD_GROUP) {
|
||||||
TaskSchedulers.getInstance().unRegister(obj);
|
TaskSchedulers.getInstance().unRegister(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -417,7 +420,7 @@ public class DownloadReceiver extends AbsReceiver {
|
|||||||
* @return 如果没有任务组列表,则返回null
|
* @return 如果没有任务组列表,则返回null
|
||||||
*/
|
*/
|
||||||
public List<DownloadGroupEntity> getGroupTaskList() {
|
public List<DownloadGroupEntity> getGroupTaskList() {
|
||||||
return getGroupTaskList(1,10);
|
return getGroupTaskList(1, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -16,31 +16,119 @@
|
|||||||
|
|
||||||
package com.arialyy.aria.core.inf;
|
package com.arialyy.aria.core.inf;
|
||||||
|
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.PopupWindow;
|
||||||
|
import com.arialyy.aria.core.WidgetLiftManager;
|
||||||
import com.arialyy.aria.core.queue.DGroupTaskQueue;
|
import com.arialyy.aria.core.queue.DGroupTaskQueue;
|
||||||
import com.arialyy.aria.core.queue.DTaskQueue;
|
import com.arialyy.aria.core.queue.DTaskQueue;
|
||||||
import com.arialyy.aria.core.queue.UTaskQueue;
|
import com.arialyy.aria.core.queue.UTaskQueue;
|
||||||
import java.util.Iterator;
|
import com.arialyy.aria.util.CommonUtil;
|
||||||
import java.util.Map;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by AriaL on 2017/6/27.
|
* Created by AriaL on 2017/6/27.
|
||||||
* 接收器
|
* 接收器
|
||||||
*/
|
*/
|
||||||
public abstract class AbsReceiver implements IReceiver {
|
public abstract class AbsReceiver implements IReceiver {
|
||||||
|
protected String TAG = getClass().getSimpleName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 观察者对象map
|
* 观察者对象
|
||||||
* key 由 {@link #getKey(IReceiver)}指定
|
|
||||||
*/
|
*/
|
||||||
public static final Map<String, Object> OBJ_MAP = new ConcurrentHashMap<>();
|
protected Object obj;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 观察者对象类的完整名称
|
* 观察者对象类的完整名称
|
||||||
*/
|
*/
|
||||||
public String targetName;
|
private String targetName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当dialog、dialogFragment、popupwindow已经被用户使用了Dismiss事件或Cancel事件,需要手动移除receiver
|
* 当dialog、dialogFragment、popupwindow已经被用户使用了Dismiss事件或Cancel事件,需要手动移除receiver
|
||||||
*/
|
*/
|
||||||
public boolean needRmListener = false;
|
private boolean needRmReceiver = false;
|
||||||
|
|
||||||
|
private boolean isFragment = false;
|
||||||
|
|
||||||
|
public boolean isLocalOrAnonymousClass = false;
|
||||||
|
|
||||||
|
public AbsReceiver(Object obj) {
|
||||||
|
this.obj = obj;
|
||||||
|
initParams();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initParams() {
|
||||||
|
try {
|
||||||
|
targetName = CommonUtil.getTargetName(obj);
|
||||||
|
Class clazz = obj.getClass();
|
||||||
|
if (CommonUtil.isLocalOrAnonymousClass(clazz)) {
|
||||||
|
isLocalOrAnonymousClass = true;
|
||||||
|
String parentName = CommonUtil.getTargetName(obj);
|
||||||
|
Class parentClazz = Class.forName(parentName);
|
||||||
|
handleFragmentOrDialogParam(parentClazz, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handleFragmentOrDialogParam(clazz, false);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleFragmentOrDialogParam(Class clazz, boolean isLocalOrAnonymousClass) {
|
||||||
|
final WidgetLiftManager widgetLiftManager = new WidgetLiftManager();
|
||||||
|
if (obj instanceof Dialog) {
|
||||||
|
needRmReceiver = widgetLiftManager.handleDialogLift((Dialog) obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (obj instanceof PopupWindow) {
|
||||||
|
needRmReceiver = widgetLiftManager.handlePopupWindowLift((PopupWindow) obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CommonUtil.isFragment(clazz)){
|
||||||
|
isFragment = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CommonUtil.isDialogFragment(clazz)) {
|
||||||
|
isFragment = true;
|
||||||
|
if (isLocalOrAnonymousClass) {
|
||||||
|
Log.e(TAG, String.format(
|
||||||
|
"%s 是匿名内部类,无法获取到dialog对象,为了防止内存泄漏,请在dismiss方法中调用Aria.download(this).unRegister();来注销事件",
|
||||||
|
obj.getClass().getName()
|
||||||
|
));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
needRmReceiver = widgetLiftManager.handleDialogFragmentLift(getDialog(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取DialogFragment的dialog
|
||||||
|
*
|
||||||
|
* @return 获取失败,返回null
|
||||||
|
*/
|
||||||
|
private Dialog getDialog(Object obj) {
|
||||||
|
try {
|
||||||
|
Method method = obj.getClass().getMethod("getDialog");
|
||||||
|
return (Dialog) method.invoke(obj);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isNeedRmListener() {
|
||||||
|
return needRmReceiver;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public boolean isFragment() {
|
||||||
|
return isFragment;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建观察者对象map的key,生成规则:
|
* 创建观察者对象map的key,生成规则:
|
||||||
@@ -69,14 +157,7 @@ public abstract class AbsReceiver implements IReceiver {
|
|||||||
* 移除观察者对象
|
* 移除观察者对象
|
||||||
*/
|
*/
|
||||||
private void removeObj() {
|
private void removeObj() {
|
||||||
for (Iterator<Map.Entry<String, Object>> iter = OBJ_MAP.entrySet().iterator();
|
obj = null;
|
||||||
iter.hasNext(); ) {
|
|
||||||
Map.Entry<String, Object> entry = iter.next();
|
|
||||||
String key = entry.getKey();
|
|
||||||
if (key.equals(getKey())) {
|
|
||||||
iter.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void destroy() {
|
@Override public void destroy() {
|
||||||
|
|||||||
@@ -49,5 +49,11 @@ public interface IReceiver {
|
|||||||
*
|
*
|
||||||
* @return {@link ReceiverType}
|
* @return {@link ReceiverType}
|
||||||
*/
|
*/
|
||||||
String getType();
|
ReceiverType getType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否是fragment,如果是fragment,在activity销毁时,需要将其从receiver中移除
|
||||||
|
*/
|
||||||
|
boolean isFragment();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,15 @@ package com.arialyy.aria.core.inf;
|
|||||||
/**
|
/**
|
||||||
* {@link AbsReceiver}类型
|
* {@link AbsReceiver}类型
|
||||||
*/
|
*/
|
||||||
public interface ReceiverType {
|
public enum ReceiverType {
|
||||||
String DOWNLOAD = "download";
|
DOWNLOAD(1, "download"),
|
||||||
String UPLOAD = "upload";
|
UPLOAD(2, "upload");
|
||||||
|
|
||||||
|
String name;
|
||||||
|
int type;
|
||||||
|
|
||||||
|
ReceiverType(int type, String name) {
|
||||||
|
this.type = type;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -48,7 +48,9 @@ import java.util.Set;
|
|||||||
* 上传功能接收器
|
* 上传功能接收器
|
||||||
*/
|
*/
|
||||||
public class UploadReceiver extends AbsReceiver {
|
public class UploadReceiver extends AbsReceiver {
|
||||||
private static final String TAG = "UploadReceiver";
|
public UploadReceiver(Object obj) {
|
||||||
|
super(obj);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置最大上传速度,单位:kb
|
* 设置最大上传速度,单位:kb
|
||||||
@@ -264,7 +266,6 @@ public class UploadReceiver extends AbsReceiver {
|
|||||||
* 将当前类注册到Aria
|
* 将当前类注册到Aria
|
||||||
*/
|
*/
|
||||||
public void register() {
|
public void register() {
|
||||||
Object obj = OBJ_MAP.get(getKey());
|
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
ALog.e(TAG, String.format("【%s】观察者为空", getTargetName()));
|
ALog.e(TAG, String.format("【%s】观察者为空", getTargetName()));
|
||||||
return;
|
return;
|
||||||
@@ -286,18 +287,17 @@ public class UploadReceiver extends AbsReceiver {
|
|||||||
* 如果是Dialog或popupwindow,需要你在撤销界面时调用该方法
|
* 如果是Dialog或popupwindow,需要你在撤销界面时调用该方法
|
||||||
*/
|
*/
|
||||||
@Override public void unRegister() {
|
@Override public void unRegister() {
|
||||||
if (needRmListener) {
|
if (isNeedRmListener()) {
|
||||||
unRegisterListener();
|
unRegisterListener();
|
||||||
}
|
}
|
||||||
AriaManager.getInstance().removeReceiver(OBJ_MAP.get(getKey()));
|
AriaManager.getInstance().removeReceiver(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public String getType() {
|
@Override public ReceiverType getType() {
|
||||||
return ReceiverType.UPLOAD;
|
return ReceiverType.UPLOAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override protected void unRegisterListener() {
|
@Override protected void unRegisterListener() {
|
||||||
Object obj = OBJ_MAP.get(getKey());
|
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
ALog.e(TAG, String.format("【%s】观察者为空", getTargetName()));
|
ALog.e(TAG, String.format("【%s】观察者为空", getTargetName()));
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
## 开发日志
|
## 开发日志
|
||||||
|
+ v_3.8.11
|
||||||
|
- 修复一个正则表达式导致的文件名保存号异常问题 https://github.com/AriaLyy/Aria/issues/715
|
||||||
|
- 修复一个匿名内部类中的内存溢出的问题 https://github.com/AriaLyy/Aria/issues/705
|
||||||
|
- m3u8密钥下载地址转换器增加ts列表的url地址 https://github.com/AriaLyy/Aria/issues/718
|
||||||
+ v_3.8.10 (2020/6/26)
|
+ v_3.8.10 (2020/6/26)
|
||||||
- fix bug https://github.com/AriaLyy/Aria/issues/703
|
- fix bug https://github.com/AriaLyy/Aria/issues/703
|
||||||
- fix bug https://github.com/AriaLyy/Aria/issues/702
|
- fix bug https://github.com/AriaLyy/Aria/issues/702
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ final public class M3U8InfoTask implements IInfoTask {
|
|||||||
ConnectionHelp.setConnectParam(mHttpOption, conn);
|
ConnectionHelp.setConnectParam(mHttpOption, conn);
|
||||||
conn.setConnectTimeout(mConnectTimeOut);
|
conn.setConnectTimeout(mConnectTimeOut);
|
||||||
conn.connect();
|
conn.connect();
|
||||||
handleConnect(conn);
|
handleConnect(mEntity.getUrl(), conn);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
failDownload(e.getMessage(), false);
|
failDownload(e.getMessage(), false);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -115,7 +115,7 @@ final public class M3U8InfoTask implements IInfoTask {
|
|||||||
mCallback = callback;
|
mCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleConnect(HttpURLConnection conn) throws IOException {
|
private void handleConnect(String tsListUrl, HttpURLConnection conn) throws IOException {
|
||||||
int code = conn.getResponseCode();
|
int code = conn.getResponseCode();
|
||||||
if (code == HttpURLConnection.HTTP_OK) {
|
if (code == HttpURLConnection.HTTP_OK) {
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||||
@@ -151,7 +151,9 @@ final public class M3U8InfoTask implements IInfoTask {
|
|||||||
// 点播文件的下载写入结束标志,直播文件的下载在停止时才写入结束标志
|
// 点播文件的下载写入结束标志,直播文件的下载在停止时才写入结束标志
|
||||||
addIndexInfo(isGenerateIndexFile && !isLive, fos, line);
|
addIndexInfo(isGenerateIndexFile && !isLive, fos, line);
|
||||||
break;
|
break;
|
||||||
} else if (line.startsWith("#EXTINF")) {
|
}
|
||||||
|
|
||||||
|
if (line.startsWith("#EXTINF")) {
|
||||||
String url = reader.readLine();
|
String url = reader.readLine();
|
||||||
if (isLive) {
|
if (isLive) {
|
||||||
if (onGetPeerCallback != null) {
|
if (onGetPeerCallback != null) {
|
||||||
@@ -163,7 +165,10 @@ final public class M3U8InfoTask implements IInfoTask {
|
|||||||
ALog.d(TAG, url);
|
ALog.d(TAG, url);
|
||||||
addIndexInfo(isGenerateIndexFile && !isLive, fos, line);
|
addIndexInfo(isGenerateIndexFile && !isLive, fos, line);
|
||||||
addIndexInfo(isGenerateIndexFile && !isLive, fos, url);
|
addIndexInfo(isGenerateIndexFile && !isLive, fos, url);
|
||||||
} else if (line.startsWith("#EXT-X-STREAM-INF")) {
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.startsWith("#EXT-X-STREAM-INF")) {
|
||||||
addIndexInfo(isGenerateIndexFile, fos, line);
|
addIndexInfo(isGenerateIndexFile, fos, line);
|
||||||
int setBand = mM3U8Option.getBandWidth();
|
int setBand = mM3U8Option.getBandWidth();
|
||||||
int bandWidth = getBandWidth(line);
|
int bandWidth = getBandWidth(line);
|
||||||
@@ -179,12 +184,14 @@ final public class M3U8InfoTask implements IInfoTask {
|
|||||||
failDownload(String.format("【%s】码率不存在", setBand), false);
|
failDownload(String.format("【%s】码率不存在", setBand), false);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (line.startsWith("#EXT-X-KEY")) {
|
|
||||||
addIndexInfo(isGenerateIndexFile, fos, line);
|
|
||||||
getKeyInfo(line);
|
|
||||||
} else {
|
|
||||||
addIndexInfo(isGenerateIndexFile, fos, line);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (line.startsWith("#EXT-X-KEY")) {
|
||||||
|
addIndexInfo(isGenerateIndexFile, fos, line);
|
||||||
|
getKeyInfo(tsListUrl, line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
addIndexInfo(isGenerateIndexFile, fos, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isLive && extInf.isEmpty()) {
|
if (!isLive && extInf.isEmpty()) {
|
||||||
@@ -248,7 +255,7 @@ final public class M3U8InfoTask implements IInfoTask {
|
|||||||
/**
|
/**
|
||||||
* 获取加密的密钥信息
|
* 获取加密的密钥信息
|
||||||
*/
|
*/
|
||||||
private void getKeyInfo(String line) {
|
private void getKeyInfo(String tsListUrl, String line) {
|
||||||
String temp = line.substring(line.indexOf(":") + 1);
|
String temp = line.substring(line.indexOf(":") + 1);
|
||||||
String[] params = temp.split(",");
|
String[] params = temp.split(",");
|
||||||
M3U8Entity m3U8Entity = mEntity.getM3U8Entity();
|
M3U8Entity m3U8Entity = mEntity.getM3U8Entity();
|
||||||
@@ -273,7 +280,7 @@ final public class M3U8InfoTask implements IInfoTask {
|
|||||||
m3U8Entity.keyFormatVersion = param.split("=")[1];
|
m3U8Entity.keyFormatVersion = param.split("=")[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
downloadKey(m3U8Entity);
|
downloadKey(tsListUrl, m3U8Entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -320,7 +327,7 @@ final public class M3U8InfoTask implements IInfoTask {
|
|||||||
conn.setRequestProperty("Cookie", cookies);
|
conn.setRequestProperty("Cookie", cookies);
|
||||||
conn.setConnectTimeout(mConnectTimeOut);
|
conn.setConnectTimeout(mConnectTimeOut);
|
||||||
conn.connect();
|
conn.connect();
|
||||||
handleConnect(conn);
|
handleConnect(newUrl, conn);
|
||||||
conn.disconnect();
|
conn.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,7 +356,7 @@ final public class M3U8InfoTask implements IInfoTask {
|
|||||||
conn.setRequestProperty("Cookie", cookies);
|
conn.setRequestProperty("Cookie", cookies);
|
||||||
conn.setConnectTimeout(mConnectTimeOut);
|
conn.setConnectTimeout(mConnectTimeOut);
|
||||||
conn.connect();
|
conn.connect();
|
||||||
handleConnect(conn);
|
handleConnect(bandWidthM3u8Url, conn);
|
||||||
conn.disconnect();
|
conn.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,7 +367,7 @@ final public class M3U8InfoTask implements IInfoTask {
|
|||||||
/**
|
/**
|
||||||
* 密钥不存在,下载密钥
|
* 密钥不存在,下载密钥
|
||||||
*/
|
*/
|
||||||
private void downloadKey(M3U8Entity info) {
|
private void downloadKey(String tsListUr, M3U8Entity info) {
|
||||||
HttpURLConnection conn = null;
|
HttpURLConnection conn = null;
|
||||||
FileOutputStream fos = null;
|
FileOutputStream fos = null;
|
||||||
try {
|
try {
|
||||||
@@ -375,7 +382,7 @@ final public class M3U8InfoTask implements IInfoTask {
|
|||||||
IKeyUrlConverter keyUrlConverter = mM3U8Option.getKeyUrlConverter();
|
IKeyUrlConverter keyUrlConverter = mM3U8Option.getKeyUrlConverter();
|
||||||
String keyUrl = info.keyUrl;
|
String keyUrl = info.keyUrl;
|
||||||
if (keyUrlConverter != null) {
|
if (keyUrlConverter != null) {
|
||||||
keyUrl = keyUrlConverter.convert(mEntity.getUrl(), keyUrl);
|
keyUrl = keyUrlConverter.convert(mEntity.getUrl(), tsListUr, keyUrl);
|
||||||
}
|
}
|
||||||
if (TextUtils.isEmpty(keyUrl)) {
|
if (TextUtils.isEmpty(keyUrl)) {
|
||||||
ALog.e(TAG, "m3u8密钥key url 为空");
|
ALog.e(TAG, "m3u8密钥key url 为空");
|
||||||
|
|||||||
@@ -25,9 +25,10 @@ public interface IKeyUrlConverter extends IEventHandler {
|
|||||||
/**
|
/**
|
||||||
* 将被加密的密钥下载地址转换为可使用的http下载地址
|
* 将被加密的密钥下载地址转换为可使用的http下载地址
|
||||||
*
|
*
|
||||||
* @param m3u8Url m3u8文件的下载地址
|
* @param m3u8Url 主m3u8的url地址
|
||||||
|
* @param tsListUrl m3u8切片列表url地址
|
||||||
* @param keyUrl 加密的url地址
|
* @param keyUrl 加密的url地址
|
||||||
* @return 可正常访问的http地址
|
* @return 可正常访问的http地址
|
||||||
*/
|
*/
|
||||||
String convert(String m3u8Url, String keyUrl);
|
String convert(String m3u8Url, String tsListUrl, String keyUrl);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ public class AriaServiceLoader<S> {
|
|||||||
private Class<S> service;
|
private Class<S> service;
|
||||||
private ClassLoader loader;
|
private ClassLoader loader;
|
||||||
private Enumeration<URL> configs = null;
|
private Enumeration<URL> configs = null;
|
||||||
private Iterator<String> pending = null;
|
private List<String> pending = null;
|
||||||
|
|
||||||
private LazyLoader(Class<S> service, ClassLoader loader) {
|
private LazyLoader(Class<S> service, ClassLoader loader) {
|
||||||
this.service = service;
|
this.service = service;
|
||||||
@@ -103,7 +103,7 @@ public class AriaServiceLoader<S> {
|
|||||||
// If an I/O error occurs while reading from the given URL, or
|
// If an I/O error occurs while reading from the given URL, or
|
||||||
// if a configuration-file format error is detected
|
// if a configuration-file format error is detected
|
||||||
//
|
//
|
||||||
private Iterator<String> parse(Class<?> service, URL u) throws ServiceConfigurationError {
|
private List<String> parse(Class<?> service, URL u) throws ServiceConfigurationError {
|
||||||
InputStream in = null;
|
InputStream in = null;
|
||||||
BufferedReader r = null;
|
BufferedReader r = null;
|
||||||
ArrayList<String> names = new ArrayList<>();
|
ArrayList<String> names = new ArrayList<>();
|
||||||
@@ -122,7 +122,7 @@ public class AriaServiceLoader<S> {
|
|||||||
fail(service, "Error closing configuration file", y);
|
fail(service, "Error closing configuration file", y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return names.iterator();
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fail(Class<?> service, String msg, Throwable cause)
|
private void fail(Class<?> service, String msg, Throwable cause)
|
||||||
@@ -177,8 +177,8 @@ public class AriaServiceLoader<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private S loadService(String serviceName) {
|
private S loadService(String serviceName) {
|
||||||
while (pending.hasNext()) {
|
for (String s : pending) {
|
||||||
if (pending.next().equals(serviceName)) {
|
if (s.equals(serviceName)) {
|
||||||
Class<?> c = null;
|
Class<?> c = null;
|
||||||
try {
|
try {
|
||||||
c = Class.forName(serviceName, false, loader);
|
c = Class.forName(serviceName, false, loader);
|
||||||
@@ -224,7 +224,7 @@ public class AriaServiceLoader<S> {
|
|||||||
fail(service, "Error locating configuration files", x);
|
fail(service, "Error locating configuration files", x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while ((pending == null) || !pending.hasNext()) {
|
while ((pending == null) || pending.isEmpty()) {
|
||||||
if (!configs.hasMoreElements()) {
|
if (!configs.hasMoreElements()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.arialyy.aria.util;
|
package com.arialyy.aria.util;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
@@ -23,6 +24,7 @@ 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.AriaConfig;
|
import com.arialyy.aria.core.AriaConfig;
|
||||||
import com.arialyy.aria.core.FtpUrlEntity;
|
import com.arialyy.aria.core.FtpUrlEntity;
|
||||||
import dalvik.system.DexFile;
|
import dalvik.system.DexFile;
|
||||||
@@ -34,6 +36,8 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@@ -60,6 +64,101 @@ public class CommonUtil {
|
|||||||
private static final String TAG = "CommonUtil";
|
private static final String TAG = "CommonUtil";
|
||||||
public static final String SERVER_CHARSET = "ISO-8859-1";
|
public static final String SERVER_CHARSET = "ISO-8859-1";
|
||||||
private static long lastClickTime;
|
private static long lastClickTime;
|
||||||
|
/**
|
||||||
|
* android、androidx、support的fragment、dialogFragment类名
|
||||||
|
*/
|
||||||
|
private static List<String> mFragmentClassName = new ArrayList<>();
|
||||||
|
private static List<String> mDialogFragmentClassName = new ArrayList<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
mFragmentClassName.add("androidx.fragment.app.Fragment");
|
||||||
|
mFragmentClassName.add("androidx.fragment.app.DialogFragment");
|
||||||
|
mFragmentClassName.add("android.app.Fragment");
|
||||||
|
mFragmentClassName.add("android.app.DialogFragment");
|
||||||
|
mFragmentClassName.add("android.support.v4.app.Fragment");
|
||||||
|
mFragmentClassName.add("android.support.v4.app.DialogFragment");
|
||||||
|
|
||||||
|
mDialogFragmentClassName.add("androidx.fragment.app.DialogFragment");
|
||||||
|
mDialogFragmentClassName.add("android.app.DialogFragment");
|
||||||
|
mDialogFragmentClassName.add("android.support.v4.app.DialogFragment");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取fragment的activityz
|
||||||
|
*
|
||||||
|
* @return 获取失败,返回null
|
||||||
|
*/
|
||||||
|
public static Activity getFragmentActivity(Object obj) {
|
||||||
|
try {
|
||||||
|
Method method = obj.getClass().getMethod("getActivity");
|
||||||
|
return (Activity) method.invoke(obj);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断注解对象是否是fragment
|
||||||
|
*
|
||||||
|
* @return true 对象是fragment
|
||||||
|
*/
|
||||||
|
public static boolean isFragment(Class subClazz) {
|
||||||
|
Class parentClass = subClazz.getSuperclass();
|
||||||
|
if (parentClass == null) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
String parentName = parentClass.getName();
|
||||||
|
if (mFragmentClassName.contains(parentName)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return isFragment(parentClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断对象是否是DialogFragment
|
||||||
|
*
|
||||||
|
* @return true 对象是DialogFragment
|
||||||
|
*/
|
||||||
|
public static boolean isDialogFragment(Class subClazz) {
|
||||||
|
Class parentClass = subClazz.getSuperclass();
|
||||||
|
if (parentClass == null) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
String parentName = parentClass.getName();
|
||||||
|
if (mDialogFragmentClassName.contains(parentName)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return isDialogFragment(parentClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isLocalOrAnonymousClass(Class clazz) {
|
||||||
|
// JVM Spec 4.8.6: A class must have an EnclosingMethod
|
||||||
|
// attribute if and only if it is a local class or an
|
||||||
|
// anonymous class.
|
||||||
|
return clazz.isLocalClass() || clazz.isAnonymousClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getTargetName(Object obj) {
|
||||||
|
String targetName;
|
||||||
|
if (isLocalOrAnonymousClass(obj.getClass())) {
|
||||||
|
Log.w(TAG, String.format("%s 是匿名内部类或局部类,将使用其主类的对象", obj.getClass().getName()));
|
||||||
|
String clsName = obj.getClass().getName();
|
||||||
|
int $Index = clsName.lastIndexOf("$");
|
||||||
|
targetName = clsName.substring(0, $Index);
|
||||||
|
} else {
|
||||||
|
targetName = obj.getClass().getName();
|
||||||
|
}
|
||||||
|
return targetName;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取线程名称,命名规则:md5(任务地址 + 线程id)
|
* 获取线程名称,命名规则:md5(任务地址 + 线程id)
|
||||||
|
|||||||
@@ -106,7 +106,6 @@ public class ComponentUtil {
|
|||||||
* @return 返回任务工具
|
* @return 返回任务工具
|
||||||
*/
|
*/
|
||||||
public synchronized IUtil buildUtil(AbsTaskWrapper wrapper, IEventListener listener) {
|
public synchronized IUtil buildUtil(AbsTaskWrapper wrapper, IEventListener listener) {
|
||||||
utilLoader.reload();
|
|
||||||
int requestType = wrapper.getRequestType();
|
int requestType = wrapper.getRequestType();
|
||||||
String className = null;
|
String className = null;
|
||||||
switch (requestType) {
|
switch (requestType) {
|
||||||
|
|||||||
@@ -4,11 +4,23 @@ import androidx.test.runner.AndroidJUnit4
|
|||||||
import com.arialyy.aria.util.CommonUtil
|
import com.arialyy.aria.util.CommonUtil
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
import java.net.URLDecoder
|
||||||
|
import java.net.URLEncoder
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
class ApiTest {
|
class ApiTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testAddChar(){
|
||||||
|
var str = "\\\\+道+歉+信\u0026感 谢 信"
|
||||||
|
str = str.replace("\\+".toRegex(), "%2B")
|
||||||
|
println("========")
|
||||||
|
println(str)
|
||||||
|
println(URLEncoder.encode(str))
|
||||||
|
println(URLDecoder.decode(str))
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSpeed() {
|
fun testSpeed() {
|
||||||
val speed = 1024.0.pow(4.0) * 2
|
val speed = 1024.0.pow(4.0) * 2
|
||||||
|
|||||||
@@ -311,8 +311,9 @@ public class M3U8VodDLoadActivity extends BaseActivity<ActivityM3u8VodBinding> {
|
|||||||
//.setMergeHandler(new TsMergeHandler());
|
//.setMergeHandler(new TsMergeHandler());
|
||||||
option.setUseDefConvert(false);
|
option.setUseDefConvert(false);
|
||||||
option.setKeyUrlConverter(new KeyUrlConverter());
|
option.setKeyUrlConverter(new KeyUrlConverter());
|
||||||
|
option.setVodTsUrlConvert(new VodTsUrlConverter());
|
||||||
option.setBandWidthUrlConverter(new BandWidthUrlConverter());
|
option.setBandWidthUrlConverter(new BandWidthUrlConverter());
|
||||||
option.setUseDefConvert(true);
|
//option.setUseDefConvert(true);
|
||||||
return option;
|
return option;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,18 +330,19 @@ public class M3U8VodDLoadActivity extends BaseActivity<ActivityM3u8VodBinding> {
|
|||||||
@Override public List<String> convert(String m3u8Url, List<String> tsUrls) {
|
@Override public List<String> convert(String m3u8Url, List<String> tsUrls) {
|
||||||
Uri uri = Uri.parse(m3u8Url);
|
Uri uri = Uri.parse(m3u8Url);
|
||||||
//String parentUrl = "http://devimages.apple.com/iphone/samples/bipbop/gear1/";
|
//String parentUrl = "http://devimages.apple.com/iphone/samples/bipbop/gear1/";
|
||||||
String parentUrl = "http://youku.cdn7-okzy.com/20200123/16815_fbe419ed/1000k/hls/";
|
//String parentUrl = "http://youku.cdn7-okzy.com/20200123/16815_fbe419ed/1000k/hls/";
|
||||||
//String parentUrl = "http://" + uri.getHost() + "/gear1/";
|
//String parentUrl = "http://" + uri.getHost() + "/gear1/";
|
||||||
//int index = m3u8Url.lastIndexOf("/");
|
//int index = m3u8Url.lastIndexOf("/");
|
||||||
//String parentUrl = m3u8Url.substring(0, index + 1);
|
//String parentUrl = m3u8Url.substring(0, index + 1);
|
||||||
//String parentUrl = "https://v1.szjal.cn/20190819/Ql6UD1od/";
|
//String parentUrl = "https://v1.szjal.cn/20190819/Ql6UD1od/";
|
||||||
//String parentUrl = "http://" + uri.getHost() + "/";
|
//String parentUrl = "http://" + uri.getHost() + "/";
|
||||||
List<String> newUrls = new ArrayList<>();
|
//List<String> newUrls = new ArrayList<>();
|
||||||
for (String url : tsUrls) {
|
//for (String url : tsUrls) {
|
||||||
newUrls.add(parentUrl + url);
|
// newUrls.add(parentUrl + url);
|
||||||
}
|
//}
|
||||||
|
|
||||||
return newUrls;
|
//return newUrls;
|
||||||
|
return tsUrls;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ public class M3U8VodModule extends BaseViewModule {
|
|||||||
// m3u8测试集合:http://www.voidcn.com/article/p-snaliarm-ct.html
|
// m3u8测试集合:http://www.voidcn.com/article/p-snaliarm-ct.html
|
||||||
//private final String defUrl = "https://www.gaoya123.cn/2019/1557993797897.m3u8";
|
//private final String defUrl = "https://www.gaoya123.cn/2019/1557993797897.m3u8";
|
||||||
// 多码率地址:
|
// 多码率地址:
|
||||||
private final String defUrl = "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8";
|
//private final String defUrl = "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8";
|
||||||
|
private final String defUrl = "http://mgjx.awu1k.cn:8000/parse/player.m3u8?target=eb2d3ca5198516269cf356463be86573";
|
||||||
//private final String defUrl = "http://youku.cdn7-okzy.com/20200123/16815_fbe419ed/index.m3u8";
|
//private final String defUrl = "http://youku.cdn7-okzy.com/20200123/16815_fbe419ed/index.m3u8";
|
||||||
|
|
||||||
//private final String defUrl = "https://cn7.kankia.com/hls/20200108/e1eaec074274c64fe46a3bdb5d2ba487/1578488360/index.m3u8";
|
//private final String defUrl = "https://cn7.kankia.com/hls/20200108/e1eaec074274c64fe46a3bdb5d2ba487/1578488360/index.m3u8";
|
||||||
|
|||||||
Reference in New Issue
Block a user