Android多屏适配:如何在Marshmallow实现ActivityOptions.setLaunchDisplayId(1)?
Hey there! Let's work through your multi-display app launch problem, covering everything from Lollipop up to the latest Android versions. I'll also specifically address the Marshmallow compatibility question you had.
Step 1: Fix Flag Compatibility
First, let's correct the flag handling in your existing code. The FLAG_ACTIVITY_LAUNCH_ADJACENT was added in Android Nougat (API 24), so we need to conditionally add it only for supported versions to avoid crashes on older devices:
Intent launchApp = MyApplication.getInstance().getActivity() .getPackageManager() .getLaunchIntentForPackage(packageInfo.packageName); // Add mandatory NEW_TASK flag for cross-app launch launchApp.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // Add ADJACENT flag only for API 24+ (Nougat and above) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { launchApp.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT); }
Step 2: Check for Second Display Existence
Before attempting to launch to a second screen, always verify that the target display (usually ID 1) exists. This prevents errors when no external display is connected:
DisplayManager displayManager = (DisplayManager) MyApplication.getInstance().getActivity() .getSystemService(Context.DISPLAY_SERVICE); Display[] displays = displayManager.getDisplays(); boolean hasSecondDisplay = false; int targetDisplayId = 1; for (Display display : displays) { if (display.getDisplayId() == targetDisplayId) { hasSecondDisplay = true; break; } } if (!hasSecondDisplay) { // Fallback: launch on the default display MyApplication.getInstance().getActivity().startActivity(launchApp); return; }
Step 3: Version-Specific Launch Logic
Now we'll handle each Android version range with appropriate methods tailored to the system's capabilities:
API 26+ (Oreo and Above)
Use the official public setLaunchDisplayId() method as you already implemented:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(targetDisplayId); MyApplication.getInstance().getActivity().startActivity(launchApp, options.toBundle()); }
API 23-25 (Marshmallow to Nougat)
The setLaunchDisplayId() method exists in these versions but is hidden from the public API. We can use reflection to call it, with a fallback to an intent extra if reflection fails (e.g., on custom ROMs):
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { try { ActivityOptions options = ActivityOptions.makeBasic(); // Reflect to access the hidden setLaunchDisplayId method Method setLaunchDisplayIdMethod = ActivityOptions.class.getMethod("setLaunchDisplayId", int.class); setLaunchDisplayIdMethod.invoke(options, targetDisplayId); MyApplication.getInstance().getActivity().startActivity(launchApp, options.toBundle()); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { // Fallback: use intent extra to specify display ID launchApp.putExtra("android.intent.extra.DISPLAY_ID", targetDisplayId); MyApplication.getInstance().getActivity().startActivity(launchApp); } }
API 21-22 (Lollipop)
For Lollipop, use the android.intent.extra.DISPLAY_ID intent extra to direct the app to launch on the second display:
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { launchApp.putExtra("android.intent.extra.DISPLAY_ID", targetDisplayId); MyApplication.getInstance().getActivity().startActivity(launchApp); }
Putting It All Together
Here's the complete combined code that covers all versions from Lollipop to the latest Android release:
// Get launch intent for the target app Intent launchApp = MyApplication.getInstance().getActivity() .getPackageManager() .getLaunchIntentForPackage(packageInfo.packageName); // Set necessary launch flags launchApp.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { launchApp.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT); } // Verify second display exists DisplayManager displayManager = (DisplayManager) MyApplication.getInstance().getActivity() .getSystemService(Context.DISPLAY_SERVICE); Display[] displays = displayManager.getDisplays(); boolean hasSecondDisplay = false; int targetDisplayId = 1; for (Display display : displays) { if (display.getDisplayId() == targetDisplayId) { hasSecondDisplay = true; break; } } if (!hasSecondDisplay) { MyApplication.getInstance().getActivity().startActivity(launchApp); return; } // Launch on second screen with version-specific logic if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(targetDisplayId); MyApplication.getInstance().getActivity().startActivity(launchApp, options.toBundle()); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { try { ActivityOptions options = ActivityOptions.makeBasic(); Method setLaunchDisplayIdMethod = ActivityOptions.class.getMethod("setLaunchDisplayId", int.class); setLaunchDisplayIdMethod.invoke(options, targetDisplayId); MyApplication.getInstance().getActivity().startActivity(launchApp, options.toBundle()); } catch (Exception e) { launchApp.putExtra("android.intent.extra.DISPLAY_ID", targetDisplayId); MyApplication.getInstance().getActivity().startActivity(launchApp); } } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { launchApp.putExtra("android.intent.extra.DISPLAY_ID", targetDisplayId); MyApplication.getInstance().getActivity().startActivity(launchApp); }
Key Notes for Marshmallow (API 23-25)
- The
setLaunchDisplayId()method is hidden in Marshmallow, so reflection is the only way to access it without relying on unofficial workarounds. - Always include a fallback (like the intent extra) to handle edge cases where reflection fails—this is especially important for custom ROMs that may modify hidden system methods.
- This approach leverages the underlying multi-display functionality already present in Marshmallow while maintaining stability.
内容的提问来源于stack exchange,提问作者Siddu M S

