您的位置:首页 > 移动开发 > Android开发

Android利用WindowsManager悬浮窗播放视频广告开发分屏应用

2018-01-20 14:07 661 查看
由于项目要求需要做一款分屏显示的App。首先拿到这个项目需求的时候第一反应相信大家跟我一样都会想到利用fragment去做。其实之前做过一版demo给另外一个项目的客户体验,就是用fragment去实现分屏显示。其实用fragment去实现分屏也是很容易的事情,但是我总感觉操作体验上给人不是很舒服的,而且需要开发者对很多事件进行重写来确保在体验上与Activity的体验相差无异。

在这次项目开始之前就开始查阅相关资料,寻找能实现分屏显示的另外一种途径,当时一个朋友跟我提出可以使用WindowsManager来做一个悬浮窗应用来遮罩在主APP上,这样既可以实现分屏显示还减少了开发量。并且由于我的项目是由横屏项目改成一个竖屏的项目来做分屏,也大大降低了我的工作量。因为我只需要在原有项目上添加一块被遮罩的空布局放在BaseActivity中并微调我的界面适配即可。

首先我们来说WindowsManager,我做了个简易的demo来实现WindowsManager悬浮窗播放广告视频。

1.必要的权限

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.GET_TASKS" />
<!-- SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 向SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>


2.视频播放控件(VideoView系统控件,需要做自定义,涉及到适配屏幕无法充满的问题)

public class CosVideoView extends VideoView{
public CosVideoView (Context context) {
super(context);

}
public CosVideoView (Context context, AttributeSet attrs) {
super(context, attrs);

}
public CosVideoView (Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);

}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//主要方法在这里
int width = getDefaultSize(0, widthMeasureSpec);
int height = getDefaultSize(0, heightMeasureSpec);
setMeasuredDimension(width, height);
}
@Override
public void setOnPreparedListener(MediaPlayer.OnPreparedListener l) {
super.setOnPreparedListener(l);
}

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return super.onKeyDown(keyCode, event);
}
}


3.悬浮窗布局float_window_big

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/big_window_layout"
android:layout_width="match_parent"
android:layout_height="300dip"
android:background="@color/colorAccent"
android:orientation="vertical">

<com.example.zhawe.windowsmanagerdemo.CosVideoView
android:id="@+id/video_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true" />

</LinearLayout>


4.承载悬浮窗布局的自定义view

public class FloatWindowBigView  extends LinearLayout {

/**
* 记录大悬浮窗的宽度
*/
public static int viewWidth;

/**
* 记录大悬浮窗的高度
*/
public static int viewHeight;
private final CosVideoView videoView;

public FloatWindowBigView(final Context context) {
super(context);
LayoutInflater.from(context).inflate(R.layout.float_window_big, this);
View view = findViewById(R.id.big_window_layout);
viewWidth = view.getLayoutParams().width;
viewHeight = view.getLayoutParams().height;

videoView = this.findViewById(R.id.video_view);
videoView.setVideoPath("/mnt/sdcard/video.3gp");
videoView.setZOrderOnTop(true);
videoView.setZOrderMediaOverlay(true);
videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
videoView.start();
}
});
videoView.start();
}
}


5.悬浮窗布局管理器

public class MyWindowManager {

/**
* 大悬浮窗View的实例
*/
private static FloatWindowBigView bigWindow;

/**
* 大悬浮窗View的参数
*/
private static WindowManager.LayoutParams bigWindowParams;

/**
* 用于控制在屏幕上添加或移除悬浮窗
*/
private static WindowManager mWindowManager;

/**
* 创建一个大悬浮窗。位置为屏幕正中间。
*
* @param context 必须为应用程序的Context.
*/
public static void createBigWindow(Context context) {

WindowManager windowManager = (WindowManager) context.getApplicationContext().getSystemService("window");
int screenWidth = windowManager.getDefaultDisplay().getWidth();
int screenHeight = windowManager.getDefaultDisplay().getHeight();
if (bigWindow == null) {
bigWindow = new FloatWindowBigView(context);
if (bigWindowParams == null) {
bigWindowParams = new WindowManager.LayoutParams();
bigWindowParams.x = 0;
bigWindowParams.y = 0;
bigWindowParams.type = WindowManager.LayoutParams.TYPE_PHONE;
bigWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE |
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
bigWindowParams.format = PixelFormat.RGBA_8888;
bigWindowParams.gravity = Gravity.LEFT | Gravity.TOP;
bigWindowParams.width = screenWidth;
bigWindowParams.height = screenHeight / 2;
}
bigWindow.setFitsSystemWindows(true);
bigWindow.getWindowToken();

windowManager.addView(bigWindow, bigWindowParams);
}
}

/**
* 将大悬浮窗从屏幕上移除。
*
* @param context 必须为应用程序的Context.
*/
public static void removeBigWindow(Context context) {
if (bigWindow != null) {
WindowManager windowManager = getWindowManager(context);
windowManager.removeView(bigWindow);
bigWindow = null;
}
}

/**
* 是否有悬浮窗(包括小悬浮窗和大悬浮窗)显示在屏幕上。
*
* @return 有悬浮窗显示在桌面上返回true,没有的话返回false。
*/
public static boolean isWindowShowing() {
return bigWindow != null;
}

/**
* 如果WindowManager还未创建,则创建一个新的WindowManager返回。否则返回当前已创建的WindowManager。
*
* @param context 必须为应用程序的Context.
* @return WindowManager的实例,用于控制在屏幕上添加或移除悬浮窗。
*/
private static WindowManager getWindowManager(Context context) {
if (mWindowManager == null) {
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
}
return mWindowManager;
}

}


6.后台常住执行视频播放的service

public class FloatWindowService extends Service {

/**
* 用于在线程中创建或移除悬浮窗。
*/
private Handler handler = new Handler();

/**
* 定时器,定时进行检测当前应该创建还是移除悬浮窗。
*/
private Timer timer;

@Override
public IBinder onBind(Intent intent) {
return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 开启定时器,每隔0.5秒刷新一次
if (timer == null) {
timer = new Timer();
timer.scheduleAtFixedRate(new RefreshTask(), 0, 500);
}
return super.onStartCommand(intent, flags, startId);
}

@Override
public void onDestroy() {
super.onDestroy();
// Service被终止的同时也停止定时器继续运行
timer.cancel();
timer = null;
}

class RefreshTask extends TimerTask {

@Override
public void run() {
// 当前界面是桌面,且没有悬浮窗显示,则创建悬浮窗。
if (!MyWindowManager.isWindowShowing()) {
handler.post(new Runnable() {
@Override
public void run() {
MyWindowManager.createBigWindow(MainActivity.getInstance());
}
});
}
}

}
}


7.MainActivity

public class MainActivity extends Activity {
private static MainActivity instance;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
instance = this;
setContentView(R.layout.activity_main);
Button startFloatWindow = (Button) findViewById(R.id.start_float_window);
startFloatWindow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
Intent intent = new Intent(MainActivity.this, FloatWindowService.class);
startService(intent);
}
});
}

public static synchronized MainActivity getInstance() {
return instance;
}


其实整个项目比较简单,实现起来也比较容易。但是在开发中发现一个问题,就是这个videoView需要传递Activity的token,但是看了几篇博客还是比较懵,所以我选择了在启动悬浮窗的时候并没有销毁当前的Activity,而是需要手动点击home键来退出主页面。

demo: http://download.csdn.net/download/d38825/10215427
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Android WindowsManager
相关文章推荐