diff --git a/aes/build.properties b/aes/build.properties
index 95b9d36..0104250 100644
--- a/aes/build.properties
+++ b/aes/build.properties
@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
-#Tue Jan 13 11:19:26 HKT 2026
+#Tue Jan 13 07:24:01 GMT 2026
stageCount=3
libraryProject=libaes
baseVersion=15.15
publishVersion=15.15.2
-buildCount=0
+buildCount=25
baseBetaVersion=15.15.3
diff --git a/aes/src/main/AndroidManifest.xml b/aes/src/main/AndroidManifest.xml
index c0ca77d..c732afa 100644
--- a/aes/src/main/AndroidManifest.xml
+++ b/aes/src/main/AndroidManifest.xml
@@ -3,6 +3,9 @@
xmlns:android="http://schemas.android.com/apk/res/android"
package="cc.winboll.studio.aes">
+
+
+
- * @Date 2026/01/11 15:16
+ * @Date 2026/01/13 11:25
* @Describe 应用介绍窗口
*/
-public class AboutActivity extends Activity {
+public class AboutActivity extends BaseWinBoLLActivity {
public static final String TAG = "AboutActivity";
+
+ private Toolbar mToolbar;
+
+ @Override
+ public String getTag() {
+ return TAG;
+ }
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -24,21 +33,33 @@ public class AboutActivity extends Activity {
setContentView(R.layout.activity_about);
// 设置工具栏
- Toolbar toolbar = findViewById(R.id.toolbar);
- setActionBar(toolbar);
- getActionBar().setSubtitle(TAG);
- getActionBar().setDisplayHomeAsUpEnabled(true);
- toolbar.setNavigationOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- finish(); // 点击导航栏返回按钮,触发 finish()
- }
- });
+ initToolbar();
AboutView aboutView = findViewById(R.id.aboutview);
aboutView.setAPPInfo(genDefaultAppInfo());
}
+ private void initToolbar() {
+ LogUtils.d(TAG, "initToolbar() 开始初始化");
+ mToolbar = findViewById(R.id.toolbar);
+ if (mToolbar == null) {
+ LogUtils.e(TAG, "initToolbar() | Toolbar未找到");
+ return;
+ }
+ setSupportActionBar(mToolbar);
+ mToolbar.setSubtitle(getTag());
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ LogUtils.d(TAG, "导航栏 点击返回按钮");
+ WinBoLLActivityManager.getInstance().resumeActivity(MainActivity.class);
+ WinBoLLActivityManager.getInstance().finish(AboutActivity.this);
+ }
+ });
+ LogUtils.d(TAG, "initToolbar() 配置完成");
+ }
+
private APPInfo genDefaultAppInfo() {
LogUtils.d(TAG, "genDefaultAppInfo() 调用");
String branchName = "aes";
diff --git a/aes/src/main/java/cc/winboll/studio/aes/MainActivity.java b/aes/src/main/java/cc/winboll/studio/aes/MainActivity.java
index 5360023..927c852 100644
--- a/aes/src/main/java/cc/winboll/studio/aes/MainActivity.java
+++ b/aes/src/main/java/cc/winboll/studio/aes/MainActivity.java
@@ -30,7 +30,7 @@ import cc.winboll.studio.libappbase.LogUtils;
import com.a4455jkjh.colorpicker.ColorPickerDialog;
import java.util.ArrayList;
-public class MainActivity extends DrawerFragmentActivity implements IWinBoLLActivity {
+public class MainActivity extends DrawerFragmentActivity {
public static final String TAG = "MainActivity";
@@ -38,11 +38,6 @@ public class MainActivity extends DrawerFragmentActivity implements IWinBoLLActi
TestAButtonFragment mTestAButtonFragment;
TestViewPageFragment mTestViewPageFragment;
- @Override
- public Activity getActivity() {
- return this;
- }
-
@Override
public String getTag() {
return TAG;
@@ -188,8 +183,9 @@ public class MainActivity extends DrawerFragmentActivity implements IWinBoLLActi
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
} else if (nItemId == R.id.item_about) {
- Intent intent = new Intent(this, AboutActivity.class);
- startActivity(intent);
+// Intent intent = new Intent(this, AboutActivity.class);
+// startActivity(intent);
+ WinBoLLActivityManager.getInstance().startWinBoLLActivity(this, AboutActivity.class);
}
diff --git a/aes/src/main/java/cc/winboll/studio/aes/WinBoLLActivity.java b/aes/src/main/java/cc/winboll/studio/aes/WinBoLLActivity.java
index 76005db..bc45765 100644
--- a/aes/src/main/java/cc/winboll/studio/aes/WinBoLLActivity.java
+++ b/aes/src/main/java/cc/winboll/studio/aes/WinBoLLActivity.java
@@ -55,6 +55,6 @@ public class WinBoLLActivity extends AppCompatActivity implements IWinBoLLActivi
@Override
protected void onDestroy() {
super.onDestroy();
- WinBoLLActivityManager.getInstance().registeRemove(this);
+ WinBoLLActivityManager.getInstance().finish(this);
}
}
diff --git a/aes/src/main/res/layout/activity_about.xml b/aes/src/main/res/layout/activity_about.xml
index bfd02eb..e003607 100644
--- a/aes/src/main/res/layout/activity_about.xml
+++ b/aes/src/main/res/layout/activity_about.xml
@@ -6,7 +6,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
-
diff --git a/libaes/build.properties b/libaes/build.properties
index b5fe9cf..0104250 100644
--- a/libaes/build.properties
+++ b/libaes/build.properties
@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
-#Tue Jan 13 11:19:15 HKT 2026
+#Tue Jan 13 07:24:01 GMT 2026
stageCount=3
libraryProject=libaes
baseVersion=15.15
publishVersion=15.15.2
-buildCount=0
+buildCount=25
baseBetaVersion=15.15.3
diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java
new file mode 100644
index 0000000..00e49f0
--- /dev/null
+++ b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/BaseWinBoLLActivity.java
@@ -0,0 +1,59 @@
+package cc.winboll.studio.libaes.activitys;
+
+import android.app.Activity;
+import android.os.Bundle;
+import androidx.appcompat.app.AppCompatActivity;
+import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity;
+import cc.winboll.studio.libaes.models.AESThemeBean;
+import cc.winboll.studio.libaes.utils.AESThemeUtil;
+import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
+import cc.winboll.studio.libappbase.ToastUtils;
+
+/**
+ * @Author 豆包&ZhanGSKen
+ * @Date 2026/01/13 14:22
+ * @Describe BaseWinBollActivity
+ */
+public abstract class BaseWinBoLLActivity extends AppCompatActivity implements IWinBoLLActivity {
+ public static final String TAG = "BaseWinBoLLActivity";
+
+ protected volatile AESThemeBean.ThemeType mThemeType;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ mThemeType = getThemeType();
+ setThemeStyle();
+ super.onCreate(savedInstanceState);
+ WinBoLLActivityManager.getInstance().add(this);
+ ToastUtils.show(getTag() + ": onCreate");
+ }
+
+ AESThemeBean.ThemeType getThemeType() {
+ /*SharedPreferences sharedPreferences = getSharedPreferences(
+ SHAREDPREFERENCES_NAME, MODE_PRIVATE);
+ return AESThemeBean.ThemeType.values()[((sharedPreferences.getInt(DRAWER_THEME_TYPE, AESThemeBean.ThemeType.DEFAULT.ordinal())))];
+ */
+ return AESThemeBean.getThemeStyleType(AESThemeUtil.getThemeTypeID(getApplicationContext()));
+ }
+
+ void setThemeStyle() {
+ //setTheme(AESThemeBean.getThemeStyle(getThemeType()));
+ setTheme(AESThemeUtil.getThemeTypeID(getApplicationContext()));
+ }
+
+ @Override
+ protected void onDestroy() {
+ WinBoLLActivityManager.getInstance().registeRemove(this);
+ super.onDestroy();
+ }
+
+ // 子类必须实现getTag(),确保唯一标识
+ @Override
+ public abstract String getTag();
+
+ @Override
+ public Activity getActivity() {
+ return this;
+ }
+}
+
diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java
index 430e4fd..1bbd12a 100644
--- a/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java
+++ b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java
@@ -34,7 +34,7 @@ import cc.winboll.studio.libappbase.LogUtils;
import com.baoyz.widget.PullRefreshLayout;
import java.util.ArrayList;
-public abstract class DrawerFragmentActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
+public abstract class DrawerFragmentActivity extends BaseWinBoLLActivity implements AdapterView.OnItemClickListener {
public static final String TAG = "DrawerFragmentActivity";
@@ -62,14 +62,19 @@ public abstract class DrawerFragmentActivity extends AppCompatActivity implement
@Override
protected void onCreate(Bundle savedInstanceState) {
//mContext = this;
- mThemeType = getThemeType();
- setThemeStyle();
+// mThemeType = getThemeType();
+// setThemeStyle();
super.onCreate(savedInstanceState);
mActivityType = initActivityType();
initRootView();
LogUtils.d(TAG, "onCreate end.");
}
+ @Override
+ public String getTag() {
+ return TAG;
+ }
+
@Override
protected void onDestroy() {
super.onDestroy();
@@ -157,22 +162,22 @@ public abstract class DrawerFragmentActivity extends AppCompatActivity implement
super.onBackPressed();
}
- void setThemeStyle() {
- //setTheme(AESThemeBean.getThemeStyle(getThemeType()));
- setTheme(AESThemeUtil.getThemeTypeID(getApplicationContext()));
- }
+// void setThemeStyle() {
+// //setTheme(AESThemeBean.getThemeStyle(getThemeType()));
+// setTheme(AESThemeUtil.getThemeTypeID(getApplicationContext()));
+// }
- boolean checkThemeStyleChange() {
- return mThemeType != getThemeType();
- }
+// boolean checkThemeStyleChange() {
+// return mThemeType != getThemeType();
+// }
- AESThemeBean.ThemeType getThemeType() {
- /*SharedPreferences sharedPreferences = getSharedPreferences(
- SHAREDPREFERENCES_NAME, MODE_PRIVATE);
- return AESThemeBean.ThemeType.values()[((sharedPreferences.getInt(DRAWER_THEME_TYPE, AESThemeBean.ThemeType.DEFAULT.ordinal())))];
- */
- return AESThemeBean.getThemeStyleType(AESThemeUtil.getThemeTypeID(getApplicationContext()));
- }
+// AESThemeBean.ThemeType getThemeType() {
+// /*SharedPreferences sharedPreferences = getSharedPreferences(
+// SHAREDPREFERENCES_NAME, MODE_PRIVATE);
+// return AESThemeBean.ThemeType.values()[((sharedPreferences.getInt(DRAWER_THEME_TYPE, AESThemeBean.ThemeType.DEFAULT.ordinal())))];
+// */
+// return AESThemeBean.getThemeStyleType(AESThemeUtil.getThemeTypeID(getApplicationContext()));
+// }
@Override
public boolean onOptionsItemSelected(MenuItem item) {
@@ -190,9 +195,9 @@ public abstract class DrawerFragmentActivity extends AppCompatActivity implement
@Override
protected void onResume() {
super.onResume();
- if (checkThemeStyleChange()) {
- recreate();
- }
+// if (checkThemeStyleChange()) {
+// recreate();
+// }
ADsBannerView adsBannerView = findViewById(R.id.adsbanner);
if (adsBannerView != null) {
diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/interfaces/IWinBoLLActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/interfaces/IWinBoLLActivity.java
index aa4805b..9760d2b 100644
--- a/libaes/src/main/java/cc/winboll/studio/libaes/interfaces/IWinBoLLActivity.java
+++ b/libaes/src/main/java/cc/winboll/studio/libaes/interfaces/IWinBoLLActivity.java
@@ -1,18 +1,24 @@
package cc.winboll.studio.libaes.interfaces;
+import android.app.Activity;
+
/**
* @Author ZhanGSKen
* @Date 2025/05/10 09:34
- * @Describe WinBoLL 窗口操作接口
+ * @Describe WinBoll 窗口操作接口(规范定义,职责单一)
*/
- import android.app.Activity;
-
-public abstract interface IWinBoLLActivity {
+public interface IWinBoLLActivity {
+ String TAG = "IWinBoLLActivity";
+ String ACTION_BIND = IWinBoLLActivity.class.getName() + ".ACTION_BIND";
- public static final String TAG = "IWinBoLLActivity";
+ /**
+ * 获取当前Activity实例
+ */
+ Activity getActivity();
- public static final String ACTION_BIND = IWinBoLLActivity.class.getName() + ".ACTION_BIND";
-
- public Activity getActivity();
- public String getTag();
+ /**
+ * 获取Activity唯一标识(建议使用类名+UUID或固定唯一字符串)
+ */
+ String getTag();
}
+
diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/utils/WinBoLLActivityManager.java b/libaes/src/main/java/cc/winboll/studio/libaes/utils/WinBoLLActivityManager.java
index c95d302..cac2157 100644
--- a/libaes/src/main/java/cc/winboll/studio/libaes/utils/WinBoLLActivityManager.java
+++ b/libaes/src/main/java/cc/winboll/studio/libaes/utils/WinBoLLActivityManager.java
@@ -1,17 +1,12 @@
package cc.winboll.studio.libaes.utils;
-/**
- * @Author ZhanGSKen
- * @Date 2025/05/10 10:02
- * @Describe 应用活动窗口管理器
- * 参考 :
- * android 类似微信小程序多任务窗口 及 设置 TaskDescription 修改 icon 和 label
- * https://blog.csdn.net/qq_29364417/article/details/109379915?app_version=6.4.2&code=app_1562916241&csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22109379915%22%2C%22source%22%3A%22weixin_38986226%22%7D&uLinkId=usr1mkqgl919blen&utm_source=app
- */
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
+import android.os.Build;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity;
import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.libappbase.LogActivity;
@@ -20,273 +15,292 @@ import cc.winboll.studio.libappbase.ToastUtils;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
+import java.util.Objects;
+/**
+ * @Author ZhanGSKen
+ * @Date 2025/05/10 10:02
+ * @Describe 应用活动窗口管理器(改进版)
+ * 核心能力:多任务窗口管理、Activity栈维护、任务前台恢复、批量关闭、前后Activity切换
+ * 参考 :android 类似微信小程序多任务窗口 及 设置 TaskDescription 修改 icon 和 label
+ */
public class WinBoLLActivityManager {
public static final String TAG = "WinBoLLActivityManager";
-
public static final String EXTRA_TAG = "EXTRA_TAG";
+ public enum WinBoLLUI_TYPE { APPLICATION, SERVICE } // 规范命名 大写开头
- public enum WinBoLLUI_TYPE { Aplication, Service }
+ private GlobalApplication mGlobalApplication;
+ private static volatile WinBoLLActivityManager sInstance; // 单例命名规范
+ private final Map mActivityListMap; // 私有不可变
+ private static volatile WinBoLLUI_TYPE sWinBoLLUI_TYPE = WinBoLLUI_TYPE.SERVICE;
- GlobalApplication mGlobalApplication;
- volatile static WinBoLLActivityManager _mIWinBoLLActivityManager;
- Map mActivityListMap;
-
- volatile static WinBoLLUI_TYPE _WinBoLLUI_TYPE = WinBoLLUI_TYPE.Service;
- public static void setWinBoLLUI_TYPE(WinBoLLUI_TYPE winBoLLUI_TYPE) {
- _WinBoLLUI_TYPE = winBoLLUI_TYPE;
- }
-
- public static WinBoLLUI_TYPE getWinBoLLUI_TYPE() {
- return _WinBoLLUI_TYPE;
- }
-
- WinBoLLActivityManager(GlobalApplication application) {
+ // 私有构造 杜绝外部实例化
+ private WinBoLLActivityManager(@NonNull GlobalApplication application) {
mGlobalApplication = application;
- mActivityListMap = new HashMap();
+ mActivityListMap = new HashMap<>(); // 菱形泛型简化
}
+ /**
+ * 初始化管理器(必须在Application onCreate中调用)
+ */
+ public static void init(@NonNull T application) {
+ if (sInstance == null) {
+ synchronized (WinBoLLActivityManager.class) {
+ if (sInstance == null) {
+ sInstance = new WinBoLLActivityManager(application);
+ }
+ }
+ }
+ }
+
+ /**
+ * 获取单例(需先调用init初始化,否则抛异常)
+ */
+ @NonNull
public static WinBoLLActivityManager getInstance() {
- return _mIWinBoLLActivityManager;
- }
-
- public static synchronized void init(T application) {
- if (_mIWinBoLLActivityManager == null) {
- _mIWinBoLLActivityManager = new WinBoLLActivityManager(application);
+ if (sInstance == null) {
+ throw new IllegalStateException("WinBoLLActivityManager 未初始化,请先在Application中调用 init()");
}
+ return sInstance;
+ }
+
+ // ===================== 基础配置 =====================
+ public static void setWinBoLLUI_TYPE(@NonNull WinBoLLUI_TYPE winBoLLUI_TYPE) {
+ sWinBoLLUI_TYPE = winBoLLUI_TYPE;
+ }
+
+ @NonNull
+ public static WinBoLLUI_TYPE getWinBoLLUI_TYPE() {
+ return sWinBoLLUI_TYPE;
+ }
+
+ // ===================== Activity 增删查 =====================
+ /**
+ * 把Activity添加到管理中(自动去重)
+ */
+ public void add(@NonNull T activity) {
+ String tag = activity.getTag();
+ if (isActivityActive(tag)) {
+ LogUtils.d(TAG, String.format("Activity[%s] 已处于活跃状态,无需重复添加", tag));
+ return;
+ }
+ mActivityListMap.put(tag, activity);
+ LogUtils.d(TAG, String.format("添加Activity:%s,当前管理数量:%d", tag, mActivityListMap.size()));
}
/**
- * 把Activity添加到管理中
+ * 判断指定Tag的Activity是否活跃
*/
- public void add(T activity) {
- if (isActivityActive(activity.getTag())) {
- LogUtils.d(TAG, String.format("add(...) %s is active.", activity.getTag()));
- } else {
- mActivityListMap.put(activity.getTag(), activity);
- LogUtils.d(TAG, String.format("Add activity : %s\n_mapActivityList.size() : %d", activity.getTag(), mActivityListMap.size()));
- }
- }
-
- //
- // activity: 为 null 时,
- // intent.putExtra 函数 "tag" 参数为 tag
- // activity: 不为 null 时,
- // intent.putExtra 函数 "tag" 参数为 activity.getTag()
- //
- public void startWinBoLLActivity(Context context, Class clazz) {
- // 如果窗口已存在就重启窗口
- if (!resumeActivity(clazz)) {
- // 新建一个任务窗口
- Intent intent = new Intent(context, clazz);
- //打开多任务窗口 flags
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
- intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- //intent.putExtra("tag", tag);
- context.startActivity(intent);
- }
- }
-
- public void startWinBoLLActivity(Context context, Intent intent, Class clazz) {
- // 如果窗口已存在就重启窗口
- if (!resumeActivity(clazz)) {
- // 新建一个任务窗口
- //Intent intent = new Intent(context, clazz);
- //打开多任务窗口 flags
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
- intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- //intent.putExtra("tag", tag);
- context.startActivity(intent);
- }
- }
-
- public void startLogActivity(Context context) {
- // 如果窗口已存在就重启窗口
- //if (!resumeActivity(LogActivity.class)) {
- // 新建一个任务窗口
- Intent intent = new Intent(context, LogActivity.class);
- //打开多任务窗口 flags
- // Define the bounds.
-// Rect bounds = new Rect(0, 0, 800, 200);
-// // Set the bounds as an activity option.
-// ActivityOptions options = ActivityOptions.makeBasic();
-// options.setLaunchBounds(bounds);
- intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
- intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
-
- //intent.putExtra(EXTRA_TAG, tag);
-
- //context.startActivity(intent, options.toBundle());
- context.startActivity(intent);
- //}
- }
-
- //
- // 判断 tag 绑定的 Activity 是否已经创建
- //
- public boolean isActivityActive(String tag) {
- return mActivityListMap.get(tag) != null;
- }
-
- Activity getActivityByTag(String tag) {
- return (mActivityListMap.get(tag) == null) ?null: mActivityListMap.get(tag).getActivity();
- }
-
-
- //
- // 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台
- //
- public boolean resumeActivity(Class clazz) {
- try {
- Activity activity = getActivityByTag(clazz.newInstance().getTag());
- if (activity != null) {
- return resumeActivity(activity);
- }
- } catch (InstantiationException | IllegalAccessException e) {
- LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
- }
- return false;
- }
-
- //
- // 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台
- //
- public boolean resumeActivity(String tag) {
- Activity activity = getActivityByTag(tag);
- if (activity != null) {
- return resumeActivity(activity);
- }
- return false;
- }
-
- //
- // 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台
- //
- public boolean resumeActivity(Activity activity) {
- ActivityManager am = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
- //返回启动它的根任务(home 或者 MainActivity)
- //Intent intent = new Intent(mContext, activity.getClass());
- //TaskStackBuilder stackBuilder = TaskStackBuilder.create(mContext);
- //stackBuilder.addNextIntentWithParentStack(intent);
- //stackBuilder.startActivities();
- am.moveTaskToFront(activity.getTaskId(), ActivityManager.MOVE_TASK_NO_USER_ACTION);
- //ToastUtils.show("resumeActivity");
- return true;
- }
-
-
- /**
- * 结束所有 Activity
- */
- public void finishAll() {
- try {
- //ToastUtils.show(String.format("finishAll() size : %d", _mIWinBoLLActivityList.size()));
- for (int i = mActivityListMap.size() - 1; i > -1; i--) {
- IWinBoLLActivity iWinBoLLActivity = mActivityListMap.get(i);
- ToastUtils.show("finishAll() activity");
- if (iWinBoLLActivity != null && iWinBoLLActivity.getActivity() != null && !iWinBoLLActivity.getActivity().isFinishing() && !iWinBoLLActivity.getActivity().isDestroyed()) {
- //ToastUtils.show("activity != null ...");
- if (getWinBoLLUI_TYPE() == WinBoLLUI_TYPE.Service) {
- // 结束窗口和最近任务栏, 建议前台服务类应用使用,可以方便用户再次调用 UI 操作。
- iWinBoLLActivity.getActivity().finishAndRemoveTask();
- //ToastUtils.show("finishAll() activity.finishAndRemoveTask();");
- } else if (getWinBoLLUI_TYPE() == WinBoLLUI_TYPE.Aplication) {
- // 结束窗口保留最近任务栏,建议前台服务类应用使用,可以保持应用的系统自觉性。
- iWinBoLLActivity.getActivity().finish();
- //ToastUtils.show("finishAll() activity.finish();");
- } else {
- ToastUtils.show("WinBollApplication.WinBollUI_TYPE error.");
- }
- }
- }
- } catch (Exception e) {
- LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
- }
+ public boolean isActivityActive(@NonNull String tag) {
+ return mActivityListMap.containsKey(tag) && mActivityListMap.get(tag) != null;
}
/**
- * 结束指定Activity
+ * 根据Tag获取Activity(空安全)
*/
- public void finish(T iWinBoLLActivity) {
- try {
- if (iWinBoLLActivity != null && iWinBoLLActivity.getActivity() != null && !iWinBoLLActivity.getActivity().isFinishing() && !iWinBoLLActivity.getActivity().isDestroyed()) {
- //根据tag 移除 MyActivity
- //String tag= activity.getTag();
- //_mIWinBoLLActivityList.remove(tag);
- //ToastUtils.show("remove");
- //ToastUtils.show("_mIWinBoLLActivityArrayMap.size() " + Integer.toString(_mIWinBoLLActivityArrayMap.size()));
-
- // 窗口回调规则:
- // [] 当前窗口位置 >> 调度出的窗口位置
- // ★:[0] 1 2 3 4 >> 1
- // ★:0 1 [2] 3 4 >> 1
- // ★:0 1 2 [3] 4 >> 2
- // ★:0 1 2 3 [4] >> 3
- // ★:[0] >> 直接关闭当前窗口
- Activity preActivity = getPreActivity(iWinBoLLActivity);
- iWinBoLLActivity.getActivity().finish();
- if (preActivity != null) {
- resumeActivity(preActivity);
- }
- }
-
- } catch (Exception e) {
- LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
+ @Nullable
+ public Activity getActivityByTag(@NonNull String tag) {
+ IWinBoLLActivity winBoLLActivity = mActivityListMap.get(tag);
+ if (winBoLLActivity == null) return null;
+ Activity activity = winBoLLActivity.getActivity();
+ // 过滤已销毁/已结束的Activity
+ if (activity == null || activity.isFinishing() || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed())) {
+ registeRemove(winBoLLActivity);
+ return null;
}
+ return activity;
}
- Activity getPreActivity(IWinBoLLActivity iWinBoLLActivity) {
- try {
- boolean bingo = false;
- IWinBoLLActivity preIWinBoLLActivity = null;
- for (Map.Entry entity : mActivityListMap.entrySet()) {
- if (entity.getKey().equals(iWinBoLLActivity.getTag())) {
- bingo = true;
- LogUtils.d(TAG, "bingo");
- break;
- }
- preIWinBoLLActivity = entity.getValue();
- }
-
- if (bingo) {
- return preIWinBoLLActivity.getActivity();
- }
- } catch (Exception e) {
- LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
- }
-
- return null;
- }
-
- public boolean registeRemove(T iWinBoLLActivity) {
- IWinBoLLActivity iWinBoLLActivityTest = mActivityListMap.get(iWinBoLLActivity.getTag());
- if (iWinBoLLActivityTest != null) {
- mActivityListMap.remove(iWinBoLLActivity.getTag());
+ /**
+ * 移除指定Activity(销毁时调用)
+ */
+ public boolean registeRemove(@NonNull T iWinBoLLActivity) {
+ String tag = iWinBoLLActivity.getTag();
+ if (mActivityListMap.containsKey(tag)) {
+ mActivityListMap.remove(tag);
+ LogUtils.d(TAG, String.format("移除Activity:%s,剩余管理数量:%d", tag, mActivityListMap.size()));
return true;
}
return false;
}
- public void printAvtivityListInfo() {
- if (!mActivityListMap.isEmpty()) {
- StringBuilder sb = new StringBuilder("Map entries : " + Integer.toString(mActivityListMap.size()));
- Iterator> iterator = mActivityListMap.entrySet().iterator();
- while (iterator.hasNext()) {
- Map.Entry entry = iterator.next();
- sb.append("\nKey: " + entry.getKey() + ", \nValue: " + entry.getValue().getTag());
- //ToastUtils.show("\nKey: " + entry.getKey() + ", Value: " + entry.getValue().getTag());
- }
- sb.append("\nMap entries end.");
- LogUtils.d(TAG, sb.toString());
- } else {
- LogUtils.d(TAG, "The map is empty.");
+ // ===================== Activity 启动 =====================
+ /**
+ * 启动WinBoLLActivity(存在则前台恢复,不存在则新建多任务窗口)
+ */
+ public void startWinBoLLActivity(@NonNull Context context, @NonNull Class clazz) {
+ if (!resumeActivity(clazz)) {
+ Intent intent = new Intent(context, clazz);
+ setMultiTaskFlags(intent);
+ context.startActivity(intent);
}
}
+
+ /**
+ * 带Intent参数启动WinBoLLActivity
+ */
+ public void startWinBoLLActivity(@NonNull Context context, @NonNull Intent intent, @NonNull Class clazz) {
+ if (!resumeActivity(clazz)) {
+ setMultiTaskFlags(intent);
+ context.startActivity(intent);
+ }
+ }
+
+ /**
+ * 启动日志页面(固定多任务模式)
+ */
+ public void startLogActivity(@NonNull Context context) {
+ Intent intent = new Intent(context, LogActivity.class);
+ setMultiTaskFlags(intent);
+ intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT); // 分屏相关
+ context.startActivity(intent);
+ }
+
+ /**
+ * 设置多任务窗口通用Flags
+ */
+ private void setMultiTaskFlags(@NonNull Intent intent) {
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+ intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ }
+
+ // ===================== Activity 前台恢复 =====================
+ /**
+ * 根据Activity类 恢复前台(反射获取Tag,需保证无参构造)
+ */
+ public boolean resumeActivity(@NonNull Class clazz) {
+ try {
+ T instance = clazz.newInstance();
+ return resumeActivity(instance.getTag());
+ } catch (InstantiationException | IllegalAccessException e) {
+ LogUtils.e(TAG, "恢复Activity失败,类需提供无参构造", e);
+ }
+ return false;
+ }
+
+ /**
+ * 根据Tag 恢复Activity前台
+ */
+ public boolean resumeActivity(@NonNull String tag) {
+ Activity activity = getActivityByTag(tag);
+ return activity != null && resumeActivity(activity);
+ }
+
+ /**
+ * 恢复指定Activity到前台(适配高版本权限)
+ */
+ @SuppressWarnings("deprecation")
+ public boolean resumeActivity(@NonNull Activity activity) {
+ if (activity.isFinishing() || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed())) {
+ return false;
+ }
+ try {
+ ActivityManager am = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
+ if (am == null) {
+ LogUtils.w(TAG, "获取ActivityManager失败,无法恢复前台");
+ return false;
+ }
+ // Android 11+ 限制,低版本正常使用
+ am.moveTaskToFront(activity.getTaskId(), ActivityManager.MOVE_TASK_NO_USER_ACTION);
+ //ToastUtils.show(String.format("Activity[%s] 已恢复到前台", activity.getClass().getSimpleName()));
+ LogUtils.d(TAG, String.format("Activity[%s] 已恢复到前台", activity.getClass().getSimpleName()));
+ return true;
+ } catch (SecurityException e) {
+ //ToastUtils.show("恢复Activity前台失败,缺少权限或系统限制 :" + e.getMessage());
+ LogUtils.e(TAG, "恢复Activity前台失败,缺少权限或系统限制", e);
+ //ToastUtils.show("窗口恢复失败,请手动打开");
+ return false;
+ }
+ }
+
+ // ===================== Activity 关闭 =====================
+ /**
+ * 结束所有管理的Activity(按UI类型选择关闭策略)
+ */
+ public void finishAll() {
+ if (mActivityListMap.isEmpty()) {
+ LogUtils.d(TAG, "当前无管理的Activity,无需结束");
+ return;
+ }
+ LogUtils.d(TAG, String.format("开始结束所有Activity,共%d个", mActivityListMap.size()));
+ Iterator> iterator = mActivityListMap.entrySet().iterator();
+ while (iterator.hasNext()) {
+ IWinBoLLActivity winBoLLActivity = iterator.next().getValue();
+ Activity activity = winBoLLActivity.getActivity();
+ if (activity == null) {
+ iterator.remove();
+ continue;
+ }
+ // 安全关闭,避免重复操作
+ if (!activity.isFinishing() && !(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed())) {
+ if (sWinBoLLUI_TYPE == WinBoLLUI_TYPE.SERVICE) {
+ activity.finishAndRemoveTask(); // 结束+移除最近任务
+ } else if (sWinBoLLUI_TYPE == WinBoLLUI_TYPE.APPLICATION) {
+ activity.finish(); // 仅结束页面
+ }
+ }
+ iterator.remove(); // 移除已处理的项
+ }
+ LogUtils.d(TAG, "所有Activity结束完成");
+ }
+
+ /**
+ * 结束指定Activity,自动恢复上一个Activity前台
+ */
+ public void finish(@NonNull T iWinBoLLActivity) {
+ Activity currentActivity = iWinBoLLActivity.getActivity();
+ if (currentActivity == null || currentActivity.isFinishing() || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && currentActivity.isDestroyed())) {
+ registeRemove(iWinBoLLActivity);
+ return;
+ }
+
+ // 先获取上一个Activity,再关闭当前
+ Activity preActivity = getPreActivity(iWinBoLLActivity);
+ currentActivity.finish();
+ registeRemove(iWinBoLLActivity); // 关闭后移除管理
+
+ // 恢复上一个Activity前台
+ if (preActivity != null) {
+ resumeActivity(preActivity);
+ }
+ }
+
+ /**
+ * 获取当前Activity的上一个栈内Activity(修复原遍历逻辑错误)
+ */
+ @Nullable
+ private Activity getPreActivity(@NonNull IWinBoLLActivity currentActivity) {
+ String currentTag = currentActivity.getTag();
+ IWinBoLLActivity preWinBoLLActivity = null;
+ for (Map.Entry entry : mActivityListMap.entrySet()) {
+ String tag = entry.getKey();
+ if (Objects.equals(tag, currentTag)) {
+ break; // 找到当前Activity,循环终止,pre即为上一个
+ }
+ preWinBoLLActivity = entry.getValue();
+ }
+ return preWinBoLLActivity != null ? preWinBoLLActivity.getActivity() : null;
+ }
+
+ // ===================== 调试辅助 =====================
+ /**
+ * 打印所有管理的Activity信息(调试用)
+ */
+ public void printActivityListInfo() {
+ if (mActivityListMap.isEmpty()) {
+ LogUtils.d(TAG, "当前管理的Activity列表为空");
+ return;
+ }
+ StringBuilder sb = new StringBuilder(String.format("Activity管理列表(总数:%d)\n", mActivityListMap.size()));
+ for (Map.Entry entry : mActivityListMap.entrySet()) {
+ sb.append("Tag: ").append(entry.getKey())
+ .append(" | Activity: ").append(entry.getValue().getActivity().getClass().getSimpleName())
+ .append("\n");
+ }
+ LogUtils.d(TAG, sb.toString());
+ }
}