private MediaPlayer mediaPlayer;
private MediaPlayer mediaPlayer2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//如果判断有刘海屏不让填充到状态栏
if (DisplayUtil.hasNotchScreen(this)) {
getWindow().addFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
} else {
getWindow().addFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
}
setContentView(R.layout.activity_main);
llCallContainer = findViewById(R.id.ll_call_container);
rlRemote = findViewById(R.id.rl_remote);
surfaceviewRemote = findViewById(R.id.surfaceview_remote);
rlLocal = findViewById(R.id.rl_local);
surfaceviewLocal = findViewById(R.id.surfaceview_local);
surfaceviewRemote.setOnClickListener(this);
surfaceviewLocal.setOnClickListener(this);
//初始化视频源
mediaPlayer = new MediaPlayer();
mediaPlayer2 = new MediaPlayer();
SurfaceHolder remoteHolder = surfaceviewRemote.getHolder();
remoteHolder.setFormat(PixelFormat.TRANSPARENT);
remoteHolder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
play2();
LogUtils.e(“Remote + surfaceCreated”);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
LogUtils.e( “Remote + surfaceChanged”);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
pause2();
LogUtils.e( “Remote + surfaceDestroyed”);
}
});
surfaceviewLocal.setZOrderOnTop(true);
surfaceviewLocal.setZOrderMediaOverlay(true);
SurfaceHolder localHolder = surfaceviewLocal.getHolder();
localHolder.setFormat(PixelFormat.TRANSPARENT);
localHolder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
play();
LogUtils.e( “Local + surfaceCreated”);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
LogUtils.e(“Local + surfaceChanged”);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
pause();
LogUtils.e( “Local + surfaceDestroyed”);
}
});
defaultLocalMargin = DisplayUtil.dip2px(this, defaultLocalMargin);
defaultLocalwidth = DisplayUtil.dip2px(this, defaultLocalwidth);
defaultLocalHeight = (int) (DisplayUtil.getScreenHeight(this) / (float) DisplayUtil.getScreenWidth(this) * defaultLocalwidth);
zoomOpera(rlRemote, surfaceviewRemote, rlLocal, surfaceviewLocal);
uiHandler = new Handler();
postDelayedCloseBtn();
}
@Override
protected void onDestroy() {
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
if (mediaPlayer2 != null) {
mediaPlayer2.stop();
mediaPlayer2.release();
mediaPlayer2 = null;
}
if (uiHandler != null) {
uiHandler.removeCallbacksAndMessages(null);
}
super.onDestroy();
}
/**
- 播放源
*/
private void play() {
try {
//添加播放视频的路径与配置MediaPlayer
AssetFileDescriptor fileDescriptor = getResources().openRawResourceFd(R.raw.video4);
mediaPlayer.reset();
//给mMediaPlayer添加预览的SurfaceHolder,将播放器和SurfaceView关联起来
mediaPlayer.setDisplay(surfaceviewLocal.getHolder());
mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),
fileDescriptor.getStartOffset(),
fileDescriptor.getLength());
//设置视频输出到SurfaceView
// mediaPlayer.setDisplay(surfaceviewLocal.getHolder());
mediaPlayer.prepare();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mediaPlayer.start();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
/**
- 播放源2
*/
private void play2() {
try {
//添加播放视频的路径与配置MediaPlayer
AssetFileDescriptor fileDescriptor = getResources().openRawResourceFd(R.raw.video5);
mediaPlayer2.reset();
//给mMediaPlayer添加预览的SurfaceHolder,将播放器和SurfaceView关联起来
mediaPlayer2.setDisplay(surfaceviewRemote.getHolder());
mediaPlayer2.setDataSource(fileDescriptor.getFileDescriptor(),
fileDescriptor.getStartOffset(),
fileDescriptor.getLength());
//设置视频输出到SurfaceView
// mediaPlayer2.setDisplay(surfaceviewRemote.getHolder());
mediaPlayer2.prepare();
mediaPlayer2.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mediaPlayer2.start();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
/**
- 暂停1
*/
private void pause() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
} else {
mediaPlayer.start();
}
}
/**
- 暂停1
*/
private void pause2() {
if (mediaPlayer2.isPlaying()) {
mediaPlayer2.pause();
} else {
mediaPlayer2.start();
}
}
/**
- 停止
*/
private void stop() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
/**
- 停止
*/
private void stop2() {
if (mediaPlayer2 != null && mediaPlayer.isPlaying()) {
mediaPlayer2.stop();
mediaPlayer2.release();
}
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.surfaceview_local:
LogUtils.d(" onClick surfaceview_local: " + mSate);
if (mSate) {
zoomOpera(rlLocal, surfaceviewLocal, rlRemote, surfaceviewRemote);
mSate = false;
} else {
changeStatus();
}
break;
case R.id.surfaceview_remote:
LogUtils.d(" onClick surfaceview_remote: " + mSate);
if (!mSate) {
zoomOpera(rlRemote, surfaceviewRemote, rlLocal, surfaceviewLocal);
mSate = true;
} else {
changeStatus();
}
break;
default:
break;
}
}
/**
- 改变转态烂的显示隐藏
*/
protected void changeStatus() {
if (llCallContainer.getVisibility() == View.GONE) {
llCallContainer.setVisibility(View.VISIBLE);
showStatusBar();
postDelayedCloseBtn();
} else {
llCallContainer.setVisibility(View.GONE);
hideStatusBar();
}
}
/**
-
大小视图切换 (小视图在前面、大视图在后面)
-
@param sourcView 之前相对布局大小
-
@param beforeview 之前surfaceview
-
@param detView 之后相对布局大小
-
@param afterview 之后的surfaceview
*/
private void zoomOpera(View sourcView, SurfaceView beforeview,
View detView, SurfaceView afterview) {
RelativeLayout paretview = (RelativeLayout) sourcView.getParent();
paretview.removeView(detView);
paretview.removeView(sourcView);
//设置远程大视图RelativeLayout 的属性
RelativeLayout.LayoutParams params1 = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.MATCH_PARENT);
params1.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
beforeview.setZOrderMediaOverlay(true);
beforeview.getHolder().setFormat(PixelFormat.TRANSPARENT);
sourcView.setLayoutParams(params1);
//设置本地小视图RelativeLayout 的属性
params1 = new RelativeLayout.LayoutParams(defaultLocalwidth, defaultLocalHeight);
params1.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
params1.setMargins(0, defaultLocalMargin, defaultLocalMargin, 0);
//在调用setZOrderOnTop(true)之后调用了setZOrderMediaOverlay(true) 遮挡问题
afterview.setZOrderOnTop(true);
afterview.setZOrderMediaOverlay(true);
afterview.getHolder().setFormat(PixelFormat.TRANSPARENT);
detView.setLayoutParams(params1);
paretview.addView(sourcView);
paretview.addView(detView);
}
/**
- 开启取消延时动画
*/
private void postDelayedCloseBtn() {
uiHandler.removeCallbacksAndMessages(null);
uiHandler.postDelayed(new Runnable() {
@Override
public void run() {
llCallContainer.setVisibility(View.GONE);
hideStatusBar();
}
}, 5000);
}
/**
- 隐藏标题栏
*/
private void hideStatusBar() {
WindowManager.LayoutParams attrs = getWindow().getAttributes();
attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
getWindow().setAttributes(attrs);
}
/**
- 显示标题栏
*/
private void showStatusBar() {
WindowManager.LayoutParams attrs = getWindow().getAttributes();
attrs.flags &= ~WindowManager.LayoutParams.FLAG_FULLSCREEN;
getWindow().setAttributes(attrs);
}
}
1.2、activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android=“http://schemas.android.com/apk/res/android”
android:layout_width=“match_parent”
android:layout_height=“match_parent”>
<RelativeLayout
android:layout_width=“match_parent”
android:layout_height=“match_parent”>
<RelativeLayout
android:id=“@+id/rl_remote”
android:layout_width=“match_parent”
android:layout_height=“wrap_content”>
<SurfaceView
android:id=“@+id/surfaceview_remote”
android:layout_width=“match_parent”
android:layout_height=“match_parent”/>
<RelativeLayout
android:id=“@+id/rl_local”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:layout_alignParentRight=“true”>
<SurfaceView
android:id=“@+id/surfaceview_local”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”/>
<LinearLayout
android:id=“@+id/ll_call_container”
android:layout_width=“match_parent”
android:layout_height=“wrap_content”
android:layout_gravity=“bottom”
android:layout_marginBottom=“25dp”
android:gravity=“center_horizontal”
android:orientation=“horizontal”>
<TextView
android:id=“@+id/tv_call_quiet”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:layout_weight=“1”
android:drawablePadding=“10dp”
android:drawableTop=“@mipmap/chat_video_change_voice_img”
android:gravity=“center_horizontal”
android:text=“切到语音聊天”
android:textColor=“#ffffff”
android:textSize=“12sp”/>
<TextView
android:id=“@+id/tv_handup_call”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:layout_weight=“1”
android:drawablePadding=“10dp”
android:drawableTop=“@mipmap/chat_video_guaduan_img_normal”
android:gravity=“center_horizontal”
android:text=“挂断”
android:textColor=“#ffffff”
android:textSize=“12sp”/>
<TextView
android:id=“@+id/tv_change_camera”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:layout_weight=“1”
android:drawablePadding=“10dp”
android:drawableTop=“@mipmap/chat_video_change_camera_img”
android:gravity=“center_horizontal”
android:text=“转换摄像头”
android:textColor=“#ffffff”
android:textSize=“12sp”/>
1.3、DisplayUtil.java
public class DisplayUtil {
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://img-blog.csdnimg.cn/img_convert/767866fabbc92df015b2ecfe99670b3b.jpeg)
尾声
在我的博客上很多朋友都在给我留言,需要一些系统的面试高频题目。之前说过我的复习范围无非是个人技术博客还有整理的笔记,考虑到笔记是手写版不利于保存,所以打算重新整理并放到网上,时间原因这里先列出面试问题,题解详见:
展示学习笔记
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
。**
[外链图片转存中…(img-08uPk240-1712914898279)]
[外链图片转存中…(img-04ZQcj0u-1712914898280)]
[外链图片转存中…(img-7BXGaMGs-1712914898280)]
[外链图片转存中…(img-qKxU4xeo-1712914898280)]
[外链图片转存中…(img-DnNWMPsl-1712914898281)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://img-blog.csdnimg.cn/img_convert/767866fabbc92df015b2ecfe99670b3b.jpeg)
尾声
在我的博客上很多朋友都在给我留言,需要一些系统的面试高频题目。之前说过我的复习范围无非是个人技术博客还有整理的笔记,考虑到笔记是手写版不利于保存,所以打算重新整理并放到网上,时间原因这里先列出面试问题,题解详见:
[外链图片转存中…(img-dMxAt4lM-1712914898281)]
展示学习笔记
[外链图片转存中…(img-IAv9g8T9-1712914898281)]
[外链图片转存中…(img-JxfTfjSE-1712914898281)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!