优化基础窗口管理类。

This commit is contained in:
2026-01-13 15:25:01 +08:00
parent 7ee79a44c7
commit 504b78c04e
11 changed files with 405 additions and 301 deletions

View File

@@ -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

View File

@@ -3,6 +3,9 @@
xmlns:android="http://schemas.android.com/apk/res/android"
package="cc.winboll.studio.aes">
<!-- 对正在运行的应用重新排序 -->
<uses-permission android:name="android.permission.REORDER_TASKS"/>
<application
android:name=".App"
android:allowBackup="true"

View File

@@ -3,20 +3,29 @@ package cc.winboll.studio.aes;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toolbar;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.aes.R;
import cc.winboll.studio.libaes.activitys.BaseWinBoLLActivity;
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.models.APPInfo;
import cc.winboll.studio.libappbase.views.AboutView;
/**
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
* @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";

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -6,7 +6,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.widget.Toolbar
<cc.winboll.studio.libaes.views.ASupportToolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/toolbar"/>

View File

@@ -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

View File

@@ -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<zhangsken@qq.com>
* @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;
}
}

View File

@@ -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) {

View File

@@ -1,18 +1,24 @@
package cc.winboll.studio.libaes.interfaces;
import android.app.Activity;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @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();
}

View File

@@ -1,17 +1,12 @@
package cc.winboll.studio.libaes.utils;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @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<zhangsken@qq.com>
* @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<String, IWinBoLLActivity> mActivityListMap; // 私有不可变
private static volatile WinBoLLUI_TYPE sWinBoLLUI_TYPE = WinBoLLUI_TYPE.SERVICE;
GlobalApplication mGlobalApplication;
volatile static WinBoLLActivityManager _mIWinBoLLActivityManager;
Map<String, IWinBoLLActivity> 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<String, IWinBoLLActivity>();
mActivityListMap = new HashMap<>(); // 菱形泛型简化
}
/**
* 初始化管理器必须在Application onCreate中调用
*/
public static <T extends GlobalApplication> 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 <T extends GlobalApplication> 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 <T extends IWinBoLLActivity> 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 <T extends IWinBoLLActivity> 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 <T extends IWinBoLLActivity> void startWinBoLLActivity(Context context, Class<T> 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 <T extends IWinBoLLActivity> void startWinBoLLActivity(Context context, Intent intent, Class<T> 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 <T extends IWinBoLLActivity> 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 <T extends IWinBoLLActivity> boolean resumeActivity(Class<T> 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 <T extends IWinBoLLActivity> boolean resumeActivity(String tag) {
Activity activity = getActivityByTag(tag);
if (activity != null) {
return resumeActivity(activity);
}
return false;
}
//
// 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台
//
public <T extends IWinBoLLActivity> 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 <T extends IWinBoLLActivity> 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<String, IWinBoLLActivity> 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 <T extends IWinBoLLActivity> boolean registeRemove(T iWinBoLLActivity) {
IWinBoLLActivity iWinBoLLActivityTest = mActivityListMap.get(iWinBoLLActivity.getTag());
if (iWinBoLLActivityTest != null) {
mActivityListMap.remove(iWinBoLLActivity.getTag());
/**
* 移除指定Activity销毁时调用
*/
public <T extends IWinBoLLActivity> 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<Map.Entry<String, IWinBoLLActivity>> iterator = mActivityListMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, IWinBoLLActivity> 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 <T extends IWinBoLLActivity> void startWinBoLLActivity(@NonNull Context context, @NonNull Class<T> clazz) {
if (!resumeActivity(clazz)) {
Intent intent = new Intent(context, clazz);
setMultiTaskFlags(intent);
context.startActivity(intent);
}
}
/**
* 带Intent参数启动WinBoLLActivity
*/
public <T extends IWinBoLLActivity> void startWinBoLLActivity(@NonNull Context context, @NonNull Intent intent, @NonNull Class<T> 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 <T extends IWinBoLLActivity> boolean resumeActivity(@NonNull Class<T> 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<Map.Entry<String, IWinBoLLActivity>> 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 <T extends IWinBoLLActivity> 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<String, IWinBoLLActivity> 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<String, IWinBoLLActivity> entry : mActivityListMap.entrySet()) {
sb.append("Tag: ").append(entry.getKey())
.append(" | Activity: ").append(entry.getValue().getActivity().getClass().getSimpleName())
.append("\n");
}
LogUtils.d(TAG, sb.toString());
}
}