Android实现双屏异显(附带源码)

Android实现双屏异显——完整项目详解与代码实现

一、项目介绍

1.1 什么是双屏异显

双屏异显,顾名思义,是指在一台Android设备连接两个屏幕(如主屏和副屏)时,主屏与副屏可以显示不同的内容,而不是镜像显示。此功能广泛应用于如下场景:

  • 商业广告机:主屏为操控界面,副屏为广告显示;

  • 车载系统:主屏控制导航、娱乐,副屏用于乘客互动;

  • 会议展示:主屏用于演讲控制,副屏用于投屏展示;

  • POS机系统:主屏用于商家操作,副屏展示支付二维码等内容。

1.2 项目目标

本项目旨在实现以下目标:

  • 利用 Android 的 Presentation 类实现双屏异显;

  • 实现主副屏独立加载不同的布局和功能;

  • 支持动态识别副屏插拔;

  • 提供完整的可运行源码,方便学习与拓展。


二、实现双屏异显所需的相关技术与知识

2.1 Android 多屏显示原理

Android 中支持多显示屏,底层通过 DisplayManager 管理显示设备。多个显示设备可以通过 HDMI、USB、WiFi(无线投屏)等方式连接到 Android 设备上。

2.2 Presentation 类介绍

Presentation 是 Android 提供的用于在不同显示屏上显示内容的类。它继承自 Dialog,本质上是一个运行在另一个 Display 上的窗口。

  • 每个 Display 都有自己的 Context

  • Presentation 可以使用独立布局;

  • 可响应生命周期事件:onCreate()onDismiss()等。

2.3 显示设备监听

  • 使用 DisplayManager.DisplayListener 监听副屏连接与断开;

  • 判断副屏是否可用;

  • 在副屏可用时启动 Presentation


三、项目实现思路

3.1 项目结构说明

  • MainActivity: 主屏界面;

  • SecondScreenPresentation: 副屏显示界面;

  • 通过 DisplayManager 获取外接屏幕信息;

  • 动态创建并显示 Presentation 实例;

  • 实现屏幕插拔监听与自动处理。


四、项目完整代码

// ==================== MainActivity.java ====================

package com.example.dualscreendemo;

import android.app.Activity;
import android.content.Context;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {

    private static final String TAG = "MainActivity";
    private DisplayManager mDisplayManager;
    private SecondScreenPresentation mPresentation;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); // 主屏布局

        // 初始化 DisplayManager
        mDisplayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);

        // 获取所有连接的显示设备(包括内置和外接)
        Display[] displays = mDisplayManager.getDisplays();

        for (Display display : displays) {
            // 忽略默认屏幕(Display.DEFAULT_DISPLAY = 0)
            if (display.getDisplayId() != Display.DEFAULT_DISPLAY) {
                showPresentation(display);
                break;
            }
        }

        // 注册屏幕监听器,监控外接屏幕插拔
        mDisplayManager.registerDisplayListener(new DisplayManager.DisplayListener() {
            @Override
            public void onDisplayAdded(int displayId) {
                Log.d(TAG, "外接显示器连接: " + displayId);
                Display display = mDisplayManager.getDisplay(displayId);
                showPresentation(display);
            }

            @Override
            public void onDisplayRemoved(int displayId) {
                Log.d(TAG, "外接显示器断开: " + displayId);
                if (mPresentation != null && mPresentation.getDisplay().getDisplayId() == displayId) {
                    mPresentation.dismiss();
                    mPresentation = null;
                }
            }

            @Override
            public void onDisplayChanged(int displayId) {
                Log.d(TAG, "显示器状态变化: " + displayId);
            }
        }, null);

        // 主屏按钮控制
        Button btn = findViewById(R.id.btn_change_text);
        btn.setOnClickListener(v -> {
            if (mPresentation != null) {
                mPresentation.updateText("副屏内容已更新!");
            }
        });
    }

    // 显示副屏内容
    private void showPresentation(Display display) {
        if (mPresentation != null) {
            mPresentation.dismiss();
        }
        mPresentation = new SecondScreenPresentation(this, display);
        mPresentation.show();
    }
}

// ==================== SecondScreenPresentation.java ====================

package com.example.dualscreendemo;

import android.app.Presentation;
import android.content.Context;
import android.os.Bundle;
import android.view.Display;
import android.view.Window;
import android.widget.TextView;

public class SecondScreenPresentation extends Presentation {

    private TextView tv;

    public SecondScreenPresentation(Context outerContext, Display display) {
        super(outerContext, display);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE); // 去标题栏
        setContentView(R.layout.presentation_second); // 副屏布局

        tv = findViewById(R.id.tv_second_screen);
    }

    // 提供更新副屏内容的方法
    public void updateText(String content) {
        if (tv != null) {
            tv.setText(content);
        }
    }
}

// ==================== activity_main.xml (主屏布局) ====================

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    android:background="#ffffff">

    <TextView
        android:id="@+id/tv_main"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="主屏显示"
        android:textSize="24sp"
        android:textColor="#000000" />

    <Button
        android:id="@+id/btn_change_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="修改副屏内容" />
</LinearLayout>

<!-- ==================== presentation_second.xml (副屏布局) ==================== -->

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/second_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    android:background="#ffcc00">

    <TextView
        android:id="@+id/tv_second_screen"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="副屏内容"
        android:textSize="28sp"
        android:textColor="#000000" />
</LinearLayout>

五、代码解读

  • onCreate():主Activity生命周期方法,初始化 UI,检查副屏是否存在。

  • showPresentation():创建并显示 Presentation 实例到副屏。

  • updateText():用于从主屏控制副屏文字更新。

  • DisplayManager.registerDisplayListener():监听副屏插拔状态。

  • SecondScreenPresentation.onCreate():副屏界面初始化。


六、项目总结与拓展

6.1 实现效果回顾

  • 成功实现在副屏显示独立内容;

  • 主屏可以动态控制副屏内容;

  • 支持副屏插拔检测;

  • 代码结构清晰,方便拓展。

6.2 实践中的注意事项

  • 部分设备不支持双屏异显(需硬件支持);

  • HDMI 插拔可能导致 Activity 重启,需处理状态恢复;

  • 多副屏支持需遍历所有非主屏 Display。

6.3 可扩展方向

  • 多媒体播放:副屏播放视频、广告;

  • 触摸互动:副屏支持触摸输入(如USB触控屏);

  • 多副屏支持:支持两个以上的 Display;

  • 数据同步:主副屏之间通过 Broadcast/EventBus 通信;

  • 使用 Jetpack Compose 版本实现:提高现代化体验;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值