Android 扩展屏幕 实现主屏副屏同步或者异步显示

android的扩展屏幕是通过Presentation 类实现的。

Presentation继承自  Dialog。

 

  • 主屏显示的代码
  • 主屏播放一个video3的视频 。video3在项目的 assets文件里 可以随便拷贝一个放进去。
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaRouter;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageButton;
import com.xinyintai.guoruiyibushow.R;
import java.io.IOException;

/**
 * 用于测试   android 异步播放。
 * <p>
 * 主界面 lvds 信号播放的界面。
 */

public class MainActivity extends Activity {
    private MediaRouter mMediaRouter;
    private DemoPresentation mPresentation;
    int flag = 2;//   1 绿色同步 2 蓝色异步

    private SurfaceView surfaceView;
    private MediaPlayer mediaPlayer1;
    ImageButton bt;
    String TAG = "MainActivity";


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 得到media router service.
        mMediaRouter = (MediaRouter) getSystemService(Context.MEDIA_ROUTER_SERVICE);
        setContentView(R.layout.activity_main);
        //监听media rotues的改变
        mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_LIVE_VIDEO, mMediaRouterCallback);
        initMainPlay();//主屏幕
        updatePresentation();//扩展屏幕
    }

    //主屏幕播放 video3视频
    private void initMainPlay() {
        mediaPlayer1 = new MediaPlayer();
        surfaceView = this.findViewById(R.id.surface1);
        bt = findViewById(R.id.iv_state);
        surfaceView.getHolder().setKeepScreenOn(true);
        surfaceView.getHolder().addCallback(new SurfaceViewLis());
        mediaPlayer1.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                play();
            }
        });

        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (flag == 1) {//绿色异步
                    try {
                        mPresentation.show();//异步让这个dialog展示
                    } catch (WindowManager.InvalidDisplayException ex) {
                        // Log.w(TAG, "Couldn't show presentation!  Display was removed in "+ "the meantime.", ex);
                        mPresentation = null;
                    }
                    bt.setBackground(getResources().getDrawable(R.drawable.circle_blue));
                    flag = 2;
                } else if (flag == 2) {//蓝色同步
                    mPresentation.dismiss();//同步让presentation消失
                    bt.setBackground(getResources().getDrawable(R.drawable.circle_green));
                    flag = 1;
                }
            }
        });
    }


    public void play() {
        mediaPlayer1.reset();
        mediaPlayer1.setAudioStreamType(AudioManager.STREAM_MUSIC);

        try {
            mediaPlayer1.setDataSource(this, Uri.parse("android.resource://" + "com.xinyintai.guoruiyibushow" + "/" + R.raw.video3));
            // 把视频输出到SurfaceView上
            mediaPlayer1.setDisplay(surfaceView.getHolder());
            mediaPlayer1.prepare();
            mediaPlayer1.start();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private class SurfaceViewLis implements SurfaceHolder.Callback {
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                                   int height) {
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {

            try {
                play();
                mediaPlayer1.seekTo(0);
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (SecurityException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalStateException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {

        }

    }


    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
    }

    private final MediaRouter.SimpleCallback mMediaRouterCallback =
            new MediaRouter.SimpleCallback() {
                @Override
                public void onRouteSelected(MediaRouter router, int type, MediaRouter.RouteInfo info) {
                    Log.e(TAG, "onRouteSelected: type=" + type + ", info=" + info);
                    updatePresentation();
                }

                @Override
                public void onRouteUnselected(MediaRouter router, int type, MediaRouter.RouteInfo info) {
                    Log.e(TAG, "onRouteeUnselected: type=" + type + ", info=" + info);
                    updatePresentation();
                }

                @Override
                public void onRoutePresentationDisplayChanged(MediaRouter router, MediaRouter.RouteInfo info) {
                    Log.e(TAG, "onRoutePresentationDisplayChanged: info=" + info);
                    updatePresentation();
                }
            };


    //准备异步的界面
    private void updatePresentation() {
        // Get the current route and its presentation display.
        MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(MediaRouter.ROUTE_TYPE_LIVE_VIDEO);
        Display presentationDisplay = route != null ? route.getPresentationDisplay() : null;

        // 如果屏幕显示改变了 让当前的扩展屏消失
        if (mPresentation != null && mPresentation.getDisplay() != presentationDisplay) {
            //Log.i(TAG, "Dismissing presentation because the current route no longer "+ "has a presentation display.");
            mPresentation.dismiss();
            mPresentation = null;
        }

        //创建一个扩展屏
        if (mPresentation == null && presentationDisplay != null) {
            Log.e(TAG, "Showing presentation on display: " + presentationDisplay);
            mPresentation = new DemoPresentation(this, presentationDisplay);
            mPresentation.setOnDismissListener(mOnDismissListener);
            mPresentation.show();
        }

        updateContents();
    }


    //更新主界面中的内容
    private void updateContents() {

    }

    /**
     * 监听 副屏界面的消失 更新主界面。
     */
    private final DialogInterface.OnDismissListener mOnDismissListener =
            new DialogInterface.OnDismissListener() {
                @Override
                public void onDismiss(DialogInterface dialog) {
                    if (dialog == mPresentation) {
                        //Log.i(TAG, "Presentation was dismissed.");mPresentation = null;
                        updateContents();
                    }
                }
            };

}
  • 主界面的布局 一个surfaceview用来播放视频。imagebutton用来切换同步异步的按钮。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:tools="http://schemas.android.com/tools"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    tools:context=".demo.MainActivity" >

   <SurfaceView  
        android:id="@+id/surface1"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:layout_centerInParent="true" />


   <!--切换同步异步的按钮的小按钮-->
   <ImageButton
       android:id="@+id/iv_state"
       android:visibility="visible"
       android:layout_alignParentLeft="true"
       android:layout_alignParentBottom="true"
       android:layout_marginLeft="5dp"
       android:layout_marginBottom="5dp"
       android:background="@drawable/circle_green"
       android:layout_width="50dp"
       android:layout_height="50dp" />
   
</RelativeLayout> 

*imagebutton的按钮background的背景。改一个绿色和蓝色的颜色即可

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval"
    android:useLevel="false"
    >
    <size android:width="21dp"
        android:height="21dp" />
    <stroke
        android:width="0dp"
        android:color="@android:color/white" />
    <solid
        android:color="@color/colorPrimaryDark" />
</shape>

 

  • 副屏的展示界面
  • 副屏是用HDMI给的信号。
  • 副屏的播放一个video的视频 。video在项目的 assets文件里 可以随便拷贝一个放进去。
import android.app.Presentation;
import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import com.xinyintai.guoruiyibushow.R;
import java.io.IOException;
import static android.content.ContentValues.TAG;

/**
 * 用于测试   android 异步播放。
 * <p>
 * 副屏界面   hdmi信号口
 */

public class DemoPresentation extends Presentation {
    private SurfaceView surfaceView;
    private MediaPlayer mediaPlayer1;
    boolean isLeave = true;


    public DemoPresentation(Context context, Display display) {
        super(context, display);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.presentation_content);
        // Set up the surface view for visual interest.
        mediaPlayer1 = new MediaPlayer();
        surfaceView = this.findViewById(R.id.surface2);
        surfaceView.getHolder().setKeepScreenOn(true);
        surfaceView.getHolder().addCallback(new SurfaceViewLis());

        mediaPlayer1.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                if (isLeave) {
                    play("android.resource://" + "com.xinyintai.guoruiyibushow" + "/" + R.raw.video);
                }
            }
        });
    }


    public void pause() {
        mediaPlayer1.pause();
    }

    public void play(String path) {
        if (surfaceView != null) {
            mediaPlayer1.reset();
            mediaPlayer1.setAudioStreamType(AudioManager.STREAM_MUSIC);
            try {
                mediaPlayer1.setDataSource(getContext(), Uri.parse(path));
                // 把视频输出到SurfaceView上
                mediaPlayer1.setDisplay(surfaceView.getHolder());
                mediaPlayer1.prepare();
                mediaPlayer1.start();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    private class SurfaceViewLis implements SurfaceHolder.Callback {
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                                   int height) {
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            Log.e(TAG, "surfaceCreated: surfaceivew产生了");
            try {
                play("android.resource://" + "com.xinyintai.guoruiyibushow" + "/" + R.raw.video);
                mediaPlayer1.seekTo(0);
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (SecurityException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalStateException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {

        }

    }

    @Override
    public void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        isLeave = false;
        Log.e(TAG, "onDetachedFromWindow: 副屏消失了");
    }

    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();
        Log.e(TAG, "onAttachedToWindow: 副屏显示了");
        isLeave = true;
    }

    @Override
    protected void onStop() {
        super.onStop();
    }
}

 

  • 副屏的布局只有一个surfaceview用来播放视频
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:tools="http://schemas.android.com/tools"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    tools:context=".demo.MainActivity" >

   <SurfaceView  
        android:id="@+id/surface2"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:layout_centerInParent="true" />   
   
</RelativeLayout> 

 

这样就实现了主屏和副屏同时播放视频。可以在主屏通过按钮。切换同步或者异步播放的功能。

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
要在Android屏幕上直接使用Surface显示内容,可以使用SurfaceView类。以下是一些简单的步骤: 1. 在布局文件中添加SurfaceView组件: ```xml <SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="match_parent"/> ``` 2. 在Activity类中获取SurfaceView并设置SurfaceHolder.Callback: ```java public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback { private SurfaceView surfaceView; private SurfaceHolder surfaceHolder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); surfaceView = findViewById(R.id.surfaceView); surfaceHolder = surfaceView.getHolder(); surfaceHolder.addCallback(this); } // 实现SurfaceHolder.Callback接口的三个方法 @Override public void surfaceCreated(SurfaceHolder holder) { // Surface创建后立即回调,可以在这里开始绘制 } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // Surface尺寸发生变化时回调,可以在这里重置绘制内容 } @Override public void surfaceDestroyed(SurfaceHolder holder) { // Surface销毁时回调,可以在这里释放资源 } } ``` 3. 在SurfaceHolder.Callback的方法中进行绘制操作: ```java @Override public void surfaceCreated(SurfaceHolder holder) { Canvas canvas = holder.lockCanvas(); // 获取Canvas对象 // 在Canvas上进行绘制操作 Paint paint = new Paint(); paint.setColor(Color.RED); canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), paint); holder.unlockCanvasAndPost(canvas); // 提交绘制结果 } ``` 以上是一个简单的例子,实际应用中可能需要使用线程或异步任务来进行复杂的绘制操作,以避免在主线程中卡顿。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

留白的云

感谢鼓励。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值