Android Java如何实现跨Activity的应用内持久通知?
Android Java 实现跨Activity的应用内通知解决方案
问题根源
当前应用内通知绑定在单个Activity的View层级中,切换Activity时原Activity进入onPause/onStop状态,通知View被销毁,导致通知提前消失。要实现跨Activity持续显示,核心是让通知的生命周期不依赖单个Activity。
方案一:全局悬浮窗(Overlay)实现
这是最贴合Instagram/Twitter体验的方案,通知属于系统窗口层级,不依附任何Activity,切换页面完全无感知。
实现步骤
申请权限
在AndroidManifest.xml中声明权限:<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />Android 6.0+需动态引导用户开启权限:
if (!Settings.canDrawOverlays(this)) { Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); startActivityForResult(intent, 1001); }全局通知管理单例
创建单例类统一处理通知的显示、隐藏和计时逻辑:public class InAppNotificationManager { private static InAppNotificationManager instance; private WindowManager windowManager; private View notificationView; private Handler handler = new Handler(Looper.getMainLooper()); private Runnable hideRunnable; private InAppNotificationManager(Context context) { windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); } public static synchronized InAppNotificationManager getInstance(Context context) { if (instance == null) { instance = new InAppNotificationManager(context.getApplicationContext()); } return instance; } public void showNotification(String content, long duration) { // 移除已有通知 hideNotification(); // 加载自定义通知布局 notificationView = LayoutInflater.from(windowManager.getContext()) .inflate(R.layout.in_app_notification, null); TextView contentTv = notificationView.findViewById(R.id.tv_content); contentTv.setText(content); // 配置窗口参数 WindowManager.LayoutParams params = new WindowManager.LayoutParams(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; } else { params.type = WindowManager.LayoutParams.TYPE_PHONE; } params.format = PixelFormat.TRANSLUCENT; params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; params.width = WindowManager.LayoutParams.MATCH_PARENT; params.height = WindowManager.LayoutParams.WRAP_CONTENT; params.gravity = Gravity.TOP; // 添加到系统窗口 windowManager.addView(notificationView, params); // 计时自动隐藏 hideRunnable = this::hideNotification; handler.postDelayed(hideRunnable, duration); } public void hideNotification() { if (notificationView != null && windowManager != null) { handler.removeCallbacks(hideRunnable); windowManager.removeView(notificationView); notificationView = null; } } }调用方式
在任意Activity或组件中直接调用:InAppNotificationManager.getInstance(this).showNotification("您有一条新消息", 3000);
方案二:BaseActivity统一管理+状态保存
若不想申请悬浮窗权限,可通过BaseActivity统一处理通知的重建,兼容性更好,仅存在切换页面时短暂的重绘过程。
实现步骤
通知状态管理单例
保存通知的内容、剩余时长和激活状态:public class NotificationStateManager { private static NotificationStateManager instance; private String currentContent; private long startTime; private long totalDuration; private boolean isActive; private NotificationStateManager() {} public static synchronized NotificationStateManager getInstance() { if (instance == null) { instance = new NotificationStateManager(); } return instance; } public void activateNotification(String content, long duration) { currentContent = content; totalDuration = duration; startTime = System.currentTimeMillis(); isActive = true; } public void deactivateNotification() { isActive = false; currentContent = null; } public boolean hasActiveNotification() { return isActive && (System.currentTimeMillis() - startTime) < totalDuration; } public String getContent() { return currentContent; } public long getRemainingDuration() { if (!hasActiveNotification()) return 0; return totalDuration - (System.currentTimeMillis() - startTime); } }BaseActivity统一处理
所有业务Activity继承该BaseActivity,在onResume时检查并重建通知:public abstract class BaseActivity extends AppCompatActivity { private View notificationView; private Handler handler = new Handler(Looper.getMainLooper()); private Runnable hideRunnable; @Override protected void onResume() { super.onResume(); checkAndRestoreNotification(); } @Override protected void onPause() { super.onPause(); removeNotificationView(); } private void checkAndRestoreNotification() { NotificationStateManager stateManager = NotificationStateManager.getInstance(); if (stateManager.hasActiveNotification()) { showNotification(stateManager.getContent(), stateManager.getRemainingDuration()); } } private void showNotification(String content, long remainingDuration) { removeNotificationView(); // 加载通知布局并添加到当前Activity根布局 notificationView = LayoutInflater.from(this) .inflate(R.layout.in_app_notification, findViewById(android.R.id.content), false); TextView contentTv = notificationView.findViewById(R.id.tv_content); contentTv.setText(content); findViewById(android.R.id.content).addView(notificationView); // 计时隐藏并更新状态 hideRunnable = () -> { removeNotificationView(); NotificationStateManager.getInstance().deactivateNotification(); }; handler.postDelayed(hideRunnable, remainingDuration); } private void removeNotificationView() { if (notificationView != null) { handler.removeCallbacks(hideRunnable); ((ViewGroup) notificationView.getParent()).removeView(notificationView); notificationView = null; } } }调用方式
在任意Activity中触发通知:NotificationStateManager.getInstance().activateNotification("新通知提醒", 3000);
方案对比
| 方案 | 优点 | 缺点 |
|---|---|---|
| 全局悬浮窗 | 体验完美,无页面切换感知 | 需要申请SYSTEM_ALERT_WINDOW权限,兼容性略差 |
| BaseActivity | 无需特殊权限,兼容性好 | 切换页面时通知会短暂消失后重建 |
内容的提问来源于stack exchange,提问作者KZMKBL
相关产品推荐
相关产品推荐

