自己最近再做Android相关的项目,所以闲下来的时候摸索了一下悬浮窗播放视频。
# 1【准备工作
## 1.1 MediaPlayer的使用
既然是悬浮窗播放视频,那么首先就要了解Android怎么播放视频。这里做简单的介绍。
视频播放的调用步骤:
(1). 装载播放资源 MediaPlayer.setDataSource() , 也何以使用 MediaPlay.oncreate(context, R.raw.video);
(2). 在layout.xml中创建surfaceView;
(3). 调用MediaPlayer.setDisplay()设置surfaceHolder, surfaceHolder可以通过surfaceView.getHolder()方法获得;
(4). 调用MediaPlayer.prepare()来准备;
(5). 调用MediaPlayer.start()来播放视频。
在第三步之前要确保surfaceHolder已经准备好。因此 需要给surfaceHolder设置一个callBack,调用addCallback(),调用addCallBack()方法. callBack有三个回调函数:

         SurfaceHolder.Callback {@Override// 待surfaceCreated回调,做MediaPlayer.setDisplay()public void surfaceCreated(SurfaceHolder holder) {MediaPlayer.setDisplay();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {}}
以上是准备工作,简介介绍,如果看不懂可以参考  https://www.cnblogs.com/yxx123/p/5720907.html, 也可以后面看源码。

实现原理
1.1 设计思想:
悬浮窗画面需要继承Service,而不是Activity,一旦Activity退出就onStop掉了,所以需要继承Service后台运行。
1.2 权限设置和申请:
在Android 6.0之后大部分权限都是需要自行申请的,不能随意获取。我们这里需要申请两个权限,一个是启动悬浮窗 ,另一个由于我们播放的是网络资源,需要权限 。
1.3 悬浮窗口设置:
这个是Android 8.0之后的又一个坑,需要对不同版本的Android系统进行适配
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
}
在Android 8.0之前,悬浮窗口设置可以为TYPE_PHONE,这种类型是用于提供用户交互操作的非应用窗口。
而Android 8.0对系统和API行为做了修改,包括使用SYSTEM_ALERT_WINDOW权限的应用无法再使用以下窗口类型来在其他应用和窗口上方显示提醒窗口。

  • TYPE_PHONE
  • TYPE_PRIORITY_PHONE
  • TYPE_SYSTEM_ALERT
  • TYPE_SYSTEM_OVERLAY
  • TYPE_SYSTEM_ERROR
    如果需要实现在其他应用和窗口上方显示提醒窗口,那么必须该为TYPE_APPLICATION_OVERLAY的新类型。
      如果在Android 8.0以上版本仍然使用TYPE_PHONE类型的悬浮窗口,则会出现如下异常信息
      android.view.WindowManagerBadTokenException:Unabletoaddwindowandroid.view.ViewRootImplBadTokenException: Unable to add window android.view.ViewRootImplBadTokenException:Unabletoaddwindowandroid.view.ViewRootImplW@f8ec928 – permission denied for window type 2006
    具体实现
    3.1 在MainActivity中启动悬浮窗并开启权限
public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 获取权限。如果当前获取了权限,直接就启动悬浮窗画面FloatingWindowService.classif (!Settings.canDrawOverlays(this)) {Toast.makeText(this, "当前无权限,请授权", Toast.LENGTH_SHORT);startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), 1111);} else {startService(new Intent(MainActivity.this, FloatingWindowService.class));}// 炮灰activity,启动悬浮窗之后就退掉finish();}
}@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {// 判断获取权限是否成功if (requestCode == 1111) {if (!Settings.canDrawOverlays(this)) {Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show();} else {Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();startService(new Intent(MainActivity.this, FloatingService.class));}}

3.2 悬浮窗画面

public class FloatingWindowService extends Service {private WindowManager windowManager;private WindowManager.LayoutParams layoutParams;private View display;private SurfaceHolder surfaceHolder;private SurfaceView surfaceView;public FloatingWindowService() {}@Overridepublic void onCreate() {super.onCreate();windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);layoutParams = new WindowManager.LayoutParams();Log.d("悬浮窗", "Build.VERSION.SDK_INT" + Build.VERSION.SDK_INT);if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) {// android 8.0及以后使用layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;} else {// android 8.0以前使用layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;}layoutParams.gravity = Gravity.LEFT | Gravity.TOP;//该flags描述的是窗口的模式,是否可以触摸,可以聚焦等layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;// 设置视频的播放窗口大小layoutParams.width = 800;layoutParams.height = 450;layoutParams.x = 300;layoutParams.y = 300;}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {showFloatingWindow();return super.onStartCommand(intent, flags, startId);}@Overridepublic IBinder onBind(Intent intent) {// TODO: Return the communication channel to the service.return null;}private void showFloatingWindow(){if (Settings.canDrawOverlays(this)) {LayoutInflater layoutInflater = LayoutInflater.from(this);display = layoutInflater.inflate(R.layout.video_display, null);surfaceView = display.findViewById(R.id.videoplayer_display);// 获取surfaceView的sourfaceHoldersurfaceHolder = surfaceView.getHolder();final MediaPlayer mediaPlayer = new MediaPlayer();// 设置视频播放流类型mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);// 视频资源网址Uri uri = Uri.parse("https://raw.githubusercontent.com/dongzhong/ImageAndVideoStore/master/Bruno%20Mars%20-%20Treasure.mp4");try {// 设置视频播放资源,这里如果前面调用了MediaPlayer.create(contex, R.raw.video),就不用再次调用了mediaPlayer.setDataSource(this,uri);} catch (IOException e) {e.printStackTrace();}surfaceHolder.addCallback(new SurfaceHolder.Callback() {@Overridepublic void surfaceCreated(SurfaceHolder holder) {// 视频播放设置mediaPlayer.setDisplay(surfaceHolder);}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {}});mediaPlayer.prepareAsync();mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {@Overridepublic void onPrepared(MediaPlayer mp) {// 待视频资源准备好了,回调中播放视频资源,mediaPlayer.start();//循环播放mediaPlayer.setLooping(true);}});windowManager.addView(display, layoutParams);display.setOnTouchListener(new FloatingOnTouchListener());}}// touch移动视频窗口private class FloatingOnTouchListener implements View.OnTouchListener {private int x;private int y;@Overridepublic boolean onTouch(View view, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:x = (int) event.getRawX();y = (int) event.getRawY();break;case MotionEvent.ACTION_MOVE:int nowX = (int) event.getRawX();int nowY = (int) event.getRawY();int movedX = nowX - x;int movedY = nowY - y;Log.d("悬浮窗", "movedX = " + movedX + ", movedY =" + movedY);x = nowX;y = nowY;layoutParams.x = layoutParams.x + movedX;layoutParams.y = layoutParams.y + movedY;windowManager.updateViewLayout(view, layoutParams);break;default:break;}return false;}}
}

3.3 AndroidManifest.xml

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /><uses-permission android:name="android.permission.INTERNET"></uses-permission><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><serviceandroid:name=".FloatingWindowService"android:enabled="true"android:exported="true"></service></application>

3.4 video_display.xml

 <FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><SurfaceViewandroid:id="@+id/videoplayer_display"android:layout_width="wrap_content"android:layout_height="wrap_content" />
</FrameLayout>

以上就是主要代码
完整代码,可直接执行 https://download.csdn.net/download/lisiwei1994/10751626
参考借鉴 https://blog.csdn.net/dongzhong1990/article/details/80512706

[Android] (Android 视频悬浮窗)相关推荐

  1. android悬浮动态权限,android应用内悬浮窗-自动贴边,不需要权限!

    简单基于注释的API来处理运行时6.0权限配置 热门度(没变化) 10.0/10 (没变化) ">10.0 活跃度(没变化) 0.8/10 (没变化) ">0.8 Wa ...

  2. Android Demo : 悬浮窗

    Android Demo : 悬浮窗 搬砖自:简书 链接:https://www.jianshu.com/p/ac63c57d2555 设计思路分析 本Demo的设计思路如下: 一个MainActiv ...

  3. android悬浮窗口播放动画,Android视频悬浮窗

    这个悬浮窗是一个类似于微信通话的小屏视频框,利于Service开启和保持.悬浮是利用WindowManager实现 创建FloatingWindowService服务类 public class Fl ...

  4. android qq视频悬浮窗口,手机QQ浏览器浮窗视频实现边看视频边操作

    我们在使用手机浏览器的时候,可能都会有这样的体会.那就是当您需要开启一个在线视频观看时,就很难以去实现如同PC电脑平台那样,边看视频边在浏览器上进行其他的冲浪操作.这个功能其实所涉及到的,如果在PC平 ...

  5. Android WindowManager实现悬浮窗效果 (一)——与当前Activity绑定

    最近有学生做毕业设计,想使用悬浮窗这种效果,其实很简单,我们可以通过系统服务WindowManager来实现此功能,本章我们来试验一下在当前Activity之上创建一个悬浮的view. 第一步:认识W ...

  6. android 8.0 悬浮窗 最简demo

    MainActivity.java文件 package com.example.performance;import android.app.Activity; import android.cont ...

  7. Android——超简单悬浮窗使用教程

    完全自定义悬浮窗,保证100%学会的超简单悬浮窗 先看看效果图: 图1                                                 图2               ...

  8. Android 全屏悬浮窗适配(悬浮窗沉浸式)

    前言 由于Android 高版本的类型限制,如果我们使用WindowsManager 做悬浮窗,会被限制在当前窗口内容中.而当前窗口大小会限制在状态栏和导航栏之间,所以会导致悬浮窗沉浸不了状态栏. 高 ...

  9. Android中自定义悬浮窗

    有时候,我们可能会需要制作一个始终悬浮的窗口显示一些关键信息.它独立于我们的页面,可以在不妨碍用户操作的情况下显示信息.这里我们就学习一下悬浮窗的做法. 1.WindowManager的常用方法 ge ...

最新文章

  1. 关于Office 365 域名绑定问题
  2. IETester-IE兼容性测试工具
  3. git提交时支持文件名大小写的修改
  4. webclient下载文件 带进度条
  5. php实现多商家开发,Thinkphp5.0实战-仿百度糯米开发多商家电商平台学习注意事项...
  6. php二维数组拆分成字符串,PHP二维数组切割为字符串并去除重复的值
  7. Android多媒体开发-- android中OpenMax的实现整体框架
  8. 网上读书关于软件测试,【读书笔记】之软件测试
  9. KP-ABE基于属性的加密加解密算法及Access Tree构建
  10. linux搭建交叉编译器,手把手教你一步一步搭建mips-linux-gcc-4.4.0交叉编译工具
  11. 北京文化:目前《你好李焕英》贡献营收约6000万至6500万元
  12. python append函数 循环_Python中循环后使用list.append数据被覆盖问题的解决
  13. cad lisp 画梯形_Lisp自动画梯形_CAD lisp 求助一段代码实现自动画弧!
  14. oblog商业版本4.6注射漏洞,直接拿管理员
  15. Java中的23种设计模式的介绍
  16. 11.4王者荣耀服务器维护中,4月11日全服不停机更新公告
  17. 常见各国插头标准图示
  18. mysql slow query_Mysql 开启 Slow 慢查询
  19. 技嘉B360M AORUS PRO 小雕+8400 黑苹果安装 EFI 10.13.6-10.15.4
  20. OpenCV-Python计算机视觉开发利器

热门文章

  1. CopyMemory Move使用笔记
  2. 爬取豆瓣TOP250电影排行榜
  3. 企业发展理论(八):知识理论
  4. 设定BoundField的DataFormatString
  5. dvi是什么意思_DVI接口是什么?DVI接口详解
  6. Oracle Golden Gate 使用小结:Windows下的Oracle – Linux下Kafka的数据同步
  7. 服务器操作系统有哪些
  8. CSS3新增属性和新增规则总结
  9. html自动适配手机,PC网站自动适配手机网页的方法技巧
  10. 安装SilverLight4 SDK报错问题