diff --git a/Aria/src/main/java/com/arialyy/aria/core/Aria.java b/Aria/src/main/java/com/arialyy/aria/core/Aria.java index 11f2c63d..b68d0c38 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/Aria.java +++ b/Aria/src/main/java/com/arialyy/aria/core/Aria.java @@ -27,6 +27,7 @@ import android.widget.PopupWindow; import com.arialyy.aria.core.download.DownloadReceiver; import com.arialyy.aria.core.upload.UploadReceiver; import com.arialyy.aria.util.ALog; +import com.arialyy.aria.util.CommonUtil; /** * Created by lyy on 2016/12/1. @@ -134,8 +135,8 @@ import com.arialyy.aria.util.ALog; return (Service) obj; } else if (obj instanceof Activity) { return (Activity) obj; - } else if (AriaManager.isFragment(obj.getClass())) { - return AriaManager.getFragmentActivity(obj); + } else if (CommonUtil.isFragment(obj.getClass())) { + return CommonUtil.getFragmentActivity(obj); } else if (obj instanceof Dialog) { return ((Dialog) obj).getContext(); } else if (obj instanceof PopupWindow) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java index 99e25856..fe4ecffc 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java +++ b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java @@ -19,11 +19,10 @@ import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Activity; import android.app.Application; -import android.app.Dialog; import android.content.Context; import android.os.Build; import android.os.Bundle; -import android.widget.PopupWindow; +import android.util.Log; import com.arialyy.aria.core.command.CommandManager; import com.arialyy.aria.core.common.QueueMod; 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.inf.AbsReceiver; 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.loader.IRecordHandler; import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.core.upload.UploadReceiver; import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DelegateWrapper; import com.arialyy.aria.util.ALog; 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.RecordUtil; 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.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -63,35 +58,12 @@ import java.util.concurrent.ConcurrentHashMap; private static final String TAG = "AriaManager"; private static final Object LOCK = new Object(); - /** - * android、androidx、support的fragment、dialogFragment类名 - */ - private static List mFragmentClassName = new ArrayList<>(); - private static List mDialogFragmentClassName = new ArrayList<>(); - @SuppressLint("StaticFieldLeak") private static volatile AriaManager INSTANCE = null; private Map mReceivers = new ConcurrentHashMap<>(); - /** - * activity 和其Dialog、Fragment的映射表 - */ - private Map> mSubClass = new ConcurrentHashMap<>(); private static Context APP; private DelegateWrapper mDbWrapper; 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) { APP = context.getApplicationContext(); } @@ -253,6 +225,7 @@ import java.util.concurrent.ConcurrentHashMap; * 处理下载操作 */ DownloadReceiver download(Object obj) { + IReceiver receiver = mReceivers.get(getKey(ReceiverType.DOWNLOAD, obj)); if (receiver == null) { 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); 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) { AbsReceiver absReceiver = - type.equals(ReceiverType.DOWNLOAD) ? new DownloadReceiver() : new UploadReceiver(); - absReceiver.targetName = obj.getClass().getName(); - AbsReceiver.OBJ_MAP.put(absReceiver.getKey(), obj); - absReceiver.needRmListener = needRmReceiver; + type.equals(ReceiverType.DOWNLOAD) ? new DownloadReceiver(obj) : new UploadReceiver(obj); mReceivers.put(key, absReceiver); receiver = absReceiver; } 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 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 * @@ -432,8 +286,8 @@ import java.util.concurrent.ConcurrentHashMap; * @return key的格式为:{@code String.format("%s_%s_%s", obj.getClass().getName(), type, * obj.hashCode());} */ - private String getKey(String type, Object obj) { - return String.format("%s_%s_%s", obj.getClass().getName(), type, obj.hashCode()); + private String getKey(ReceiverType type, Object obj) { + 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"); return; } - List temp = new ArrayList<>(); // 移除寄主的receiver for (Iterator> iter = mReceivers.entrySet().iterator(); iter.hasNext(); ) { Map.Entry entry = iter.next(); String key = entry.getKey(); - if (key.equals(getKey(ReceiverType.DOWNLOAD, obj)) || key.equals( - getKey(ReceiverType.UPLOAD, obj))) { - AbsReceiver receiver = mReceivers.get(key); - List subNames = mSubClass.get(key); - if (subNames != null && !subNames.isEmpty()) { - temp.addAll(subNames); - } - if (receiver != null) { - receiver.destroy(); - } + AbsReceiver receiver = entry.getValue(); + if ((receiver.isLocalOrAnonymousClass || receiver.isFragment()) + && key.startsWith(obj.getClass().getName())) { + receiver.destroy(); iter.remove(); + continue; } - } - // 移除寄生的receiver - if (!temp.isEmpty()) { - for (Iterator> iter = mReceivers.entrySet().iterator(); - iter.hasNext(); ) { - Map.Entry entry = iter.next(); - if (temp.contains(entry.getKey())) { - AbsReceiver receiver = mReceivers.get(entry.getKey()); - if (receiver != null) { - receiver.destroy(); - } - iter.remove(); - } + if (key.equals(getKey(ReceiverType.DOWNLOAD, obj)) + || key.equals(getKey(ReceiverType.UPLOAD, obj)) + ) { + receiver.destroy(); + iter.remove(); } } + Log.d(TAG, "debug"); } /** diff --git a/Aria/src/main/java/com/arialyy/aria/core/WidgetLiftManager.java b/Aria/src/main/java/com/arialyy/aria/core/WidgetLiftManager.java index 1ab43e76..763280d2 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/WidgetLiftManager.java +++ b/Aria/src/main/java/com/arialyy/aria/core/WidgetLiftManager.java @@ -29,20 +29,20 @@ import java.lang.reflect.Field; * Created by lyy on 2017/2/7. * 为组件添加生命周期 */ -final class WidgetLiftManager { +public final class WidgetLiftManager { private final String TAG = "WidgetLiftManager"; /** * 处理DialogFragment事件 */ - @TargetApi(Build.VERSION_CODES.HONEYCOMB) boolean handleDialogFragmentLift(Dialog dialog) { + @TargetApi(Build.VERSION_CODES.HONEYCOMB) public boolean handleDialogFragmentLift(Dialog dialog) { return handleDialogLift(dialog); } /** * 处理悬浮框取消或dismiss事件 */ - boolean handlePopupWindowLift(PopupWindow popupWindow) { + public boolean handlePopupWindowLift(PopupWindow popupWindow) { try { Field dismissField = CommonUtil.getField(popupWindow.getClass(), "mOnDismissListener"); PopupWindow.OnDismissListener listener = @@ -76,7 +76,7 @@ final class WidgetLiftManager { * * @return true 设置了dialog的销毁事件。false 没有设置dialog的销毁事件 */ - boolean handleDialogLift(Dialog dialog) { + public boolean handleDialogLift(Dialog dialog) { if (dialog == null) { ALog.w(TAG, "dialog 为空,没有设置自动销毁事件,为了防止内存泄露,请在dismiss方法中调用Aria.download(this).unRegister();来注销事件\n" diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java index d69007e4..dadd21da 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java @@ -55,7 +55,10 @@ import java.util.Set; * 下载功能接收器 */ public class DownloadReceiver extends AbsReceiver { - private final String TAG = "DownloadReceiver"; + + public DownloadReceiver(Object obj) { + super(obj); + } /** * 设置最大下载速度,单位:kb @@ -164,7 +167,6 @@ public class DownloadReceiver extends AbsReceiver { * 将当前类注册到Aria */ public void register() { - Object obj = OBJ_MAP.get(getKey()); if (obj == null) { ALog.e(TAG, String.format("register【%s】观察者为空", getTargetName())); return; @@ -199,18 +201,17 @@ public class DownloadReceiver extends AbsReceiver { * @see module类中销毁 */ @Override public void unRegister() { - if (needRmListener) { + if (isNeedRmListener()) { unRegisterListener(); } - AriaManager.getInstance().removeReceiver(OBJ_MAP.get(getKey())); + AriaManager.getInstance().removeReceiver(obj); } - @Override public String getType() { + @Override public ReceiverType getType() { return ReceiverType.DOWNLOAD; } @Override protected void unRegisterListener() { - Object obj = OBJ_MAP.get(getKey()); if (obj == null) { ALog.e(TAG, String.format("unRegister【%s】观察者为空", getTargetName())); return; @@ -220,7 +221,9 @@ public class DownloadReceiver extends AbsReceiver { for (Integer integer : set) { if (integer == ProxyHelper.PROXY_TYPE_DOWNLOAD) { TaskSchedulers.getInstance().unRegister(obj); - } else if (integer == ProxyHelper.PROXY_TYPE_DOWNLOAD_GROUP) { + continue; + } + if (integer == ProxyHelper.PROXY_TYPE_DOWNLOAD_GROUP) { TaskSchedulers.getInstance().unRegister(obj); } } @@ -417,7 +420,7 @@ public class DownloadReceiver extends AbsReceiver { * @return 如果没有任务组列表,则返回null */ public List getGroupTaskList() { - return getGroupTaskList(1,10); + return getGroupTaskList(1, 10); } /** diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsReceiver.java index 95af5111..b8be49d0 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsReceiver.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsReceiver.java @@ -16,31 +16,119 @@ 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.DTaskQueue; import com.arialyy.aria.core.queue.UTaskQueue; -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +import com.arialyy.aria.util.CommonUtil; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; /** * Created by AriaL on 2017/6/27. * 接收器 */ public abstract class AbsReceiver implements IReceiver { + protected String TAG = getClass().getSimpleName(); + /** - * 观察者对象map - * key 由 {@link #getKey(IReceiver)}指定 + * 观察者对象 */ - public static final Map OBJ_MAP = new ConcurrentHashMap<>(); + protected Object obj; + /** * 观察者对象类的完整名称 */ - public String targetName; + private String targetName; + /** * 当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,生成规则: @@ -69,14 +157,7 @@ public abstract class AbsReceiver implements IReceiver { * 移除观察者对象 */ private void removeObj() { - for (Iterator> iter = OBJ_MAP.entrySet().iterator(); - iter.hasNext(); ) { - Map.Entry entry = iter.next(); - String key = entry.getKey(); - if (key.equals(getKey())) { - iter.remove(); - } - } + obj = null; } @Override public void destroy() { diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/IReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/inf/IReceiver.java index d2ca7f81..1ca11e75 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/IReceiver.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/IReceiver.java @@ -49,5 +49,11 @@ public interface IReceiver { * * @return {@link ReceiverType} */ - String getType(); + ReceiverType getType(); + + /** + * 判断是否是fragment,如果是fragment,在activity销毁时,需要将其从receiver中移除 + */ + boolean isFragment(); + } diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/ReceiverType.java b/Aria/src/main/java/com/arialyy/aria/core/inf/ReceiverType.java index 7bc13733..87456d05 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/ReceiverType.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/ReceiverType.java @@ -18,7 +18,15 @@ package com.arialyy.aria.core.inf; /** * {@link AbsReceiver}类型 */ -public interface ReceiverType { - String DOWNLOAD = "download"; - String UPLOAD = "upload"; +public enum ReceiverType { + DOWNLOAD(1, "download"), + UPLOAD(2, "upload"); + + String name; + int type; + + ReceiverType(int type, String name) { + this.type = type; + this.name = name; + } } \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java index 3eaa62ae..f4d9acfd 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java @@ -48,7 +48,9 @@ import java.util.Set; * 上传功能接收器 */ public class UploadReceiver extends AbsReceiver { - private static final String TAG = "UploadReceiver"; + public UploadReceiver(Object obj) { + super(obj); + } /** * 设置最大上传速度,单位:kb @@ -264,7 +266,6 @@ public class UploadReceiver extends AbsReceiver { * 将当前类注册到Aria */ public void register() { - Object obj = OBJ_MAP.get(getKey()); if (obj == null) { ALog.e(TAG, String.format("【%s】观察者为空", getTargetName())); return; @@ -286,18 +287,17 @@ public class UploadReceiver extends AbsReceiver { * 如果是Dialog或popupwindow,需要你在撤销界面时调用该方法 */ @Override public void unRegister() { - if (needRmListener) { + if (isNeedRmListener()) { unRegisterListener(); } - AriaManager.getInstance().removeReceiver(OBJ_MAP.get(getKey())); + AriaManager.getInstance().removeReceiver(obj); } - @Override public String getType() { + @Override public ReceiverType getType() { return ReceiverType.UPLOAD; } @Override protected void unRegisterListener() { - Object obj = OBJ_MAP.get(getKey()); if (obj == null) { ALog.e(TAG, String.format("【%s】观察者为空", getTargetName())); return; diff --git a/DEV_LOG.md b/DEV_LOG.md index 46ad883e..2e77da7d 100644 --- a/DEV_LOG.md +++ b/DEV_LOG.md @@ -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) - fix bug https://github.com/AriaLyy/Aria/issues/703 - fix bug https://github.com/AriaLyy/Aria/issues/702 diff --git a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8InfoTask.java b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8InfoTask.java index b7189778..b105efea 100644 --- a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8InfoTask.java +++ b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8InfoTask.java @@ -101,7 +101,7 @@ final public class M3U8InfoTask implements IInfoTask { ConnectionHelp.setConnectParam(mHttpOption, conn); conn.setConnectTimeout(mConnectTimeOut); conn.connect(); - handleConnect(conn); + handleConnect(mEntity.getUrl(), conn); } catch (IOException e) { failDownload(e.getMessage(), false); } finally { @@ -115,7 +115,7 @@ final public class M3U8InfoTask implements IInfoTask { mCallback = callback; } - private void handleConnect(HttpURLConnection conn) throws IOException { + private void handleConnect(String tsListUrl, HttpURLConnection conn) throws IOException { int code = conn.getResponseCode(); if (code == HttpURLConnection.HTTP_OK) { BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); @@ -151,7 +151,9 @@ final public class M3U8InfoTask implements IInfoTask { // 点播文件的下载写入结束标志,直播文件的下载在停止时才写入结束标志 addIndexInfo(isGenerateIndexFile && !isLive, fos, line); break; - } else if (line.startsWith("#EXTINF")) { + } + + if (line.startsWith("#EXTINF")) { String url = reader.readLine(); if (isLive) { if (onGetPeerCallback != null) { @@ -163,7 +165,10 @@ final public class M3U8InfoTask implements IInfoTask { ALog.d(TAG, url); addIndexInfo(isGenerateIndexFile && !isLive, fos, line); 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); int setBand = mM3U8Option.getBandWidth(); int bandWidth = getBandWidth(line); @@ -179,12 +184,14 @@ final public class M3U8InfoTask implements IInfoTask { failDownload(String.format("【%s】码率不存在", setBand), false); } return; - } else if (line.startsWith("#EXT-X-KEY")) { - addIndexInfo(isGenerateIndexFile, fos, line); - getKeyInfo(line); - } else { + } + + if (line.startsWith("#EXT-X-KEY")) { addIndexInfo(isGenerateIndexFile, fos, line); + getKeyInfo(tsListUrl, line); + continue; } + addIndexInfo(isGenerateIndexFile, fos, line); } 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[] params = temp.split(","); M3U8Entity m3U8Entity = mEntity.getM3U8Entity(); @@ -273,7 +280,7 @@ final public class M3U8InfoTask implements IInfoTask { 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.setConnectTimeout(mConnectTimeOut); conn.connect(); - handleConnect(conn); + handleConnect(newUrl, conn); conn.disconnect(); } @@ -349,7 +356,7 @@ final public class M3U8InfoTask implements IInfoTask { conn.setRequestProperty("Cookie", cookies); conn.setConnectTimeout(mConnectTimeOut); conn.connect(); - handleConnect(conn); + handleConnect(bandWidthM3u8Url, conn); 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; FileOutputStream fos = null; try { @@ -375,7 +382,7 @@ final public class M3U8InfoTask implements IInfoTask { IKeyUrlConverter keyUrlConverter = mM3U8Option.getKeyUrlConverter(); String keyUrl = info.keyUrl; if (keyUrlConverter != null) { - keyUrl = keyUrlConverter.convert(mEntity.getUrl(), keyUrl); + keyUrl = keyUrlConverter.convert(mEntity.getUrl(), tsListUr, keyUrl); } if (TextUtils.isEmpty(keyUrl)) { ALog.e(TAG, "m3u8密钥key url 为空"); diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/processor/IKeyUrlConverter.java b/PublicComponent/src/main/java/com/arialyy/aria/core/processor/IKeyUrlConverter.java index 3a95c06d..7e453dff 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/processor/IKeyUrlConverter.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/processor/IKeyUrlConverter.java @@ -25,9 +25,10 @@ public interface IKeyUrlConverter extends IEventHandler { /** * 将被加密的密钥下载地址转换为可使用的http下载地址 * - * @param m3u8Url m3u8文件的下载地址 + * @param m3u8Url 主m3u8的url地址 + * @param tsListUrl m3u8切片列表url地址 * @param keyUrl 加密的url地址 * @return 可正常访问的http地址 */ - String convert(String m3u8Url, String keyUrl); + String convert(String m3u8Url, String tsListUrl, String keyUrl); } diff --git a/PublicComponent/src/main/java/com/arialyy/aria/util/AriaServiceLoader.java b/PublicComponent/src/main/java/com/arialyy/aria/util/AriaServiceLoader.java index 2061c144..ad6c480a 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/util/AriaServiceLoader.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/util/AriaServiceLoader.java @@ -78,7 +78,7 @@ public class AriaServiceLoader { private Class service; private ClassLoader loader; private Enumeration configs = null; - private Iterator pending = null; + private List pending = null; private LazyLoader(Class service, ClassLoader loader) { this.service = service; @@ -103,7 +103,7 @@ public class AriaServiceLoader { // If an I/O error occurs while reading from the given URL, or // if a configuration-file format error is detected // - private Iterator parse(Class service, URL u) throws ServiceConfigurationError { + private List parse(Class service, URL u) throws ServiceConfigurationError { InputStream in = null; BufferedReader r = null; ArrayList names = new ArrayList<>(); @@ -122,7 +122,7 @@ public class AriaServiceLoader { fail(service, "Error closing configuration file", y); } } - return names.iterator(); + return names; } private void fail(Class service, String msg, Throwable cause) @@ -177,8 +177,8 @@ public class AriaServiceLoader { } private S loadService(String serviceName) { - while (pending.hasNext()) { - if (pending.next().equals(serviceName)) { + for (String s : pending) { + if (s.equals(serviceName)) { Class c = null; try { c = Class.forName(serviceName, false, loader); @@ -224,7 +224,7 @@ public class AriaServiceLoader { fail(service, "Error locating configuration files", x); } } - while ((pending == null) || !pending.hasNext()) { + while ((pending == null) || pending.isEmpty()) { if (!configs.hasMoreElements()) { return; } diff --git a/PublicComponent/src/main/java/com/arialyy/aria/util/CommonUtil.java b/PublicComponent/src/main/java/com/arialyy/aria/util/CommonUtil.java index d3800a8f..9edf1b1c 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/util/CommonUtil.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/util/CommonUtil.java @@ -16,6 +16,7 @@ package com.arialyy.aria.util; +import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -23,6 +24,7 @@ import android.net.Uri; import android.os.Environment; import android.text.TextUtils; import android.util.Base64; +import android.util.Log; import com.arialyy.aria.core.AriaConfig; import com.arialyy.aria.core.FtpUrlEntity; import dalvik.system.DexFile; @@ -34,6 +36,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.math.BigDecimal; @@ -60,6 +64,101 @@ public class CommonUtil { private static final String TAG = "CommonUtil"; public static final String SERVER_CHARSET = "ISO-8859-1"; private static long lastClickTime; + /** + * android、androidx、support的fragment、dialogFragment类名 + */ + private static List mFragmentClassName = new ArrayList<>(); + private static List 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) diff --git a/PublicComponent/src/main/java/com/arialyy/aria/util/ComponentUtil.java b/PublicComponent/src/main/java/com/arialyy/aria/util/ComponentUtil.java index 286fcbe0..962f12af 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/util/ComponentUtil.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/util/ComponentUtil.java @@ -106,7 +106,6 @@ public class ComponentUtil { * @return 返回任务工具 */ public synchronized IUtil buildUtil(AbsTaskWrapper wrapper, IEventListener listener) { - utilLoader.reload(); int requestType = wrapper.getRequestType(); String className = null; switch (requestType) { diff --git a/app/src/androidTest/java/com/example/arial/downloaddemo/ApiTest.kt b/app/src/androidTest/java/com/example/arial/downloaddemo/ApiTest.kt index 2495d5cc..4c8597a3 100644 --- a/app/src/androidTest/java/com/example/arial/downloaddemo/ApiTest.kt +++ b/app/src/androidTest/java/com/example/arial/downloaddemo/ApiTest.kt @@ -4,11 +4,23 @@ import androidx.test.runner.AndroidJUnit4 import com.arialyy.aria.util.CommonUtil import org.junit.Test import org.junit.runner.RunWith +import java.net.URLDecoder +import java.net.URLEncoder import kotlin.math.pow @RunWith(AndroidJUnit4::class) 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 fun testSpeed() { val speed = 1024.0.pow(4.0) * 2 diff --git a/app/src/main/java/com/arialyy/simple/core/download/m3u8/M3U8VodDLoadActivity.java b/app/src/main/java/com/arialyy/simple/core/download/m3u8/M3U8VodDLoadActivity.java index 97b10bc7..37567992 100644 --- a/app/src/main/java/com/arialyy/simple/core/download/m3u8/M3U8VodDLoadActivity.java +++ b/app/src/main/java/com/arialyy/simple/core/download/m3u8/M3U8VodDLoadActivity.java @@ -311,8 +311,9 @@ public class M3U8VodDLoadActivity extends BaseActivity { //.setMergeHandler(new TsMergeHandler()); option.setUseDefConvert(false); option.setKeyUrlConverter(new KeyUrlConverter()); + option.setVodTsUrlConvert(new VodTsUrlConverter()); option.setBandWidthUrlConverter(new BandWidthUrlConverter()); - option.setUseDefConvert(true); + //option.setUseDefConvert(true); return option; } @@ -329,18 +330,19 @@ public class M3U8VodDLoadActivity extends BaseActivity { @Override public List convert(String m3u8Url, List tsUrls) { Uri uri = Uri.parse(m3u8Url); //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/"; //int index = m3u8Url.lastIndexOf("/"); //String parentUrl = m3u8Url.substring(0, index + 1); //String parentUrl = "https://v1.szjal.cn/20190819/Ql6UD1od/"; //String parentUrl = "http://" + uri.getHost() + "/"; - List newUrls = new ArrayList<>(); - for (String url : tsUrls) { - newUrls.add(parentUrl + url); - } + //List newUrls = new ArrayList<>(); + //for (String url : tsUrls) { + // newUrls.add(parentUrl + url); + //} - return newUrls; + //return newUrls; + return tsUrls; } } diff --git a/app/src/main/java/com/arialyy/simple/core/download/m3u8/M3U8VodModule.java b/app/src/main/java/com/arialyy/simple/core/download/m3u8/M3U8VodModule.java index f2199622..f0d974e9 100644 --- a/app/src/main/java/com/arialyy/simple/core/download/m3u8/M3U8VodModule.java +++ b/app/src/main/java/com/arialyy/simple/core/download/m3u8/M3U8VodModule.java @@ -34,7 +34,8 @@ public class M3U8VodModule extends BaseViewModule { // 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 = "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 = "https://cn7.kankia.com/hls/20200108/e1eaec074274c64fe46a3bdb5d2ba487/1578488360/index.m3u8";