Android开发中如何在副屏上销毁或重启Activity
问题根因
多屏场景下每个Display对应独立的Activity任务栈,当前写法存在两个核心问题:
- 第一次在副屏启动
MainActivity2后,实例会驻留在副屏任务栈中,默认启动模式下重复调用startActivity既不会销毁原有实例,也不会创建新实例,自然无法接收新传入的参数,也不会重启。 - 代码中没有建立主屏与副屏Activity的通信通道,既无法主动触发副屏Activity销毁,也不能在不重启的前提下更新内容。
实现方案
根据需求可以选择两种实现方式,优先推荐无重启的通信方案,性能更好。
方案1:不重启Activity,直接通信更新内容(推荐)
不需要每次传数据都重启Activity,通过静态持有副屏Activity实例的方式,直接调用更新方法即可,同时支持主动销毁副屏页面。
- 修改
MainActivity2代码,增加实例管理和对外更新接口:
public class MainActivity2 extends AppCompatActivity { private ActivityMain2Binding binding; // 静态持有当前副屏Activity实例 private static MainActivity2 currentInstance; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityMain2Binding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); currentInstance = this; // 处理首次启动传入的参数 processIntent(getIntent()); } @Override protected void onDestroy() { super.onDestroy(); // 销毁时清空引用,避免内存泄漏 if (currentInstance == this) { currentInstance = null; } } // 对外暴露的数据更新方法 public void updateContent(String data) { binding.viewData.setText(data); } private void processIntent(Intent intent) { Bundle extras = intent.getExtras(); if (extras != null) { String data = extras.getString("data"); binding.viewData.setText(data); } } // 对外暴露获取实例的方法 public static MainActivity2 getCurrentInstance() { return currentInstance; } }
- 修改主屏
MainActivity的传参逻辑,副屏Activity已存在时直接更新数据,不存在时才执行启动逻辑:
private void showSecondDisplayWithData(){ DisplayManager displayManager = (DisplayManager)getSystemService(Context.DISPLAY_SERVICE); // 过滤真实外接副屏设备,避免取到系统虚拟Display Display[] displays = displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); if(displays.length > 0){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { MainActivity2 secondActivity = MainActivity2.getCurrentInstance(); // 副屏页面已存在,直接更新数据,无需重启 if (secondActivity != null) { secondActivity.updateContent("this is new data"); return; } // 副屏页面不存在才走启动流程 ActivityOptions options = ActivityOptions.makeBasic(); options.setLaunchDisplayId(displays[0].getDisplayId()); Intent intent = new Intent(this, MainActivity2.class); intent.putExtra("data", "this is data"); startActivity(intent, options.toBundle()); } }else{ Toast.makeText(this,"No second display", Toast.LENGTH_SHORT).show(); } }
- 如果需要主动销毁副屏Activity,直接调用实例的finish方法即可:
// 例如绑定关闭按钮的点击事件 binding.btnCloseScreen.setOnClickListener(v -> { MainActivity2 secondActivity = MainActivity2.getCurrentInstance(); if (secondActivity != null) { secondActivity.finish(); } });
销毁后再调用启动方法,就可以正常创建新的副屏Activity实例。
方案2:强制销毁重启(适合必须重建实例的场景)
如果业务要求每次传参必须重建Activity,通过添加启动Flag+配置启动模式实现:
- 修改启动副屏的Intent,添加清除任务栈的Flag:
private void showSecondDisplayWithData(){ DisplayManager displayManager = (DisplayManager)getSystemService(Context.DISPLAY_SERVICE); Display[] displays = displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); if(displays.length > 0){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { ActivityOptions options = ActivityOptions.makeBasic(); options.setLaunchDisplayId(displays[0].getDisplayId()); Intent intent = new Intent(this, MainActivity2.class); // 添加Flag,启动前清空副屏对应任务栈的原有实例 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); intent.putExtra("data", "this is new data " + System.currentTimeMillis()); startActivity(intent, options.toBundle()); } }else{ Toast.makeText(this,"No second display", Toast.LENGTH_SHORT).show(); } }
- 在
AndroidManifest.xml中给MainActivity2配置启动模式:
<activity android:name=".MainActivity2" android:launchMode="singleTask" android:exported="false" />
配置后每次调用startActivity都会自动销毁副屏上已存在的MainActivity2实例,再创建新实例接收参数,实现重启效果。
注意事项
- 不要直接取
displays[1]作为副屏设备,部分设备会把主屏放在索引0、虚拟Display放在索引1,用DISPLAY_CATEGORY_PRESENTATION过滤才能拿到真实外接的副屏。 - 安卓12及以上版本,跨屏启动Activity需要声明
android.permission.START_ACTIVITIES_FROM_BACKGROUND权限,否则会启动失败。 - 静态持有Activity时必须在
onDestroy生命周期清空引用,否则会造成内存泄漏。
内容的提问来源于stack exchange,提问作者CL So
相关产品推荐
相关产品推荐

