Android悬浮框,在Service中打开悬浮窗;在Service中打开Dialog;
文章介绍了如何在Service中显示悬浮框,在Service中弹出Dialog,在Service中做耗时的轮询操作;
背景需求:
公司的项目现在的逻辑是这样的:发送一个指令,然后3秒一次轮询去查询这个指令是否成功,在这期间界面有遮盖不可操作;
然后需求改了,因为遮盖界面不让用户操作体验不好;现在的需求是:这个轮询查询指令是否成功的操作在后端进行,界面有一个悬浮框用来提示用户正在查询指令;
嗯,在后端查询指令让用户无感,可以用Service实现,然后悬浮框使用WindowMessage实现,轮询查询指令使用Handler或IntentService实现;大致就是这样,先来个Demo;
1、开启服务:需要的信息由Activity使用Intent传递给Service;
Intent intent = new Intent(this,MyService.class);
intent.putExtra("args","晨");
startService(intent);
public class MyService extends Service {
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
args = intent.getStringExtra("args");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
Service中的onCreate只在创建的时候执行一次,onStartCommand()每次开启这个Service都会执行;同时别忘记这个注册:
<service
android:name=".MyService"
android:enabled="true"
android:exported="true" />
2、在Service开启成功后创建悬浮框,
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
args = intent.getStringExtra("args");
initView();
return super.onStartCommand(intent, flags, startId);
}
/**
* 使用系统级别的WindowManager展示悬浮框,需要6.0以上的权限;
*/
private void initView() {
if (Build.VERSION.SDK_INT >= 23) {
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setData(Uri.parse( "package:"+"com.example.administrator.xuanfudemo")); //应用的包名,可直接跳转到这个应用的悬浮窗设置;
startActivity(intent);
} else {
openWindow();
}
}else {
openWindow();
}
}
private void openWindow(){
windowManager = (WindowManager) this.getSystemService(WINDOW_SERVICE);
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
// layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
// layoutParams.token = this.getWindow().getDecorView().getWindowToken(); //这样设置,在activity中打开悬浮框可绕过权限;
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
layoutParams.format = PixelFormat.TRANSLUCENT; //透明
layoutParams.gravity = Gravity.TOP | Gravity.RIGHT; //右上角显示
view = LayoutInflater.from(this).inflate(R.layout.view_win,null);
windowManager.addView(view,layoutParams);
}
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
悬浮框需要权限,而且这个权限属于危险级权限,API23以上需要用户手动开启;
3、使用Handler轮询查询指令;
查询到指令后弹框提示,弹出Dialog。在Service中弹出Dialog需要设置下方代码,同时还要有弹窗权限;
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
private Handler mHandler = new Handler(){
@Override
public void dispatchMessage(Message msg) {
super.dispatchMessage(msg);
switch (msg.what){
case HANDLERSIGN:
Log.i(TAG, "dispatchMessage: "+args+(++num));
mHandler.sendEmptyMessageDelayed(HANDLERSIGN,HANDLERTIME);
if (num == 5){
AlertDialog.Builder builder = new AlertDialog.Builder(MyService.this);
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
MyService.this.stopSelf();
}
});
AlertDialog dialog = builder.create();
dialog.setMessage("我的计数"+num);
dialog.setTitle("提示");
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
dialog.show();
}
break;
}
}
};
private final String TAG = "ccb";
private String args;
private int num;
private final int HANDLERSIGN = 10;
private final int HANDLERTIME = 2010;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
args = intent.getStringExtra("args");
initView();
initData();
return super.onStartCommand(intent, flags, startId);
}
private void initData() {
mHandler.sendEmptyMessageDelayed(HANDLERSIGN,HANDLERTIME);
}
4、在服务销毁时,清空Handler信息关闭悬浮框;
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy: 啊,ByKill");
mHandler.removeCallbacksAndMessages(null);
if (windowManager != null) windowManager.removeView(view);
}
全部的Service代码:
悬浮框我使用了两种,另外一种是FloatWindow,有兴趣的可以去GitHub查一下;
package com.example.administrator.xuanfudemo;
import android.Manifest;
import android.app.AlertDialog;
import android.app.Service;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.provider.Settings;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import com.yhao.floatwindow.FloatWindow;
import com.yhao.floatwindow.PermissionListener;
import com.yhao.floatwindow.Screen;
import com.yhao.floatwindow.ViewStateListener;
public class MyService extends Service {
private WindowManager windowManager;
private View view;
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
super.onCreate();
}
private Handler mHandler = new Handler(){
@Override
public void dispatchMessage(Message msg) {
super.dispatchMessage(msg);
switch (msg.what){
case HANDLERSIGN:
Log.i(TAG, "dispatchMessage: "+args+(++num));
mHandler.sendEmptyMessageDelayed(HANDLERSIGN,HANDLERTIME);
if (num == 5){
AlertDialog.Builder builder = new AlertDialog.Builder(MyService.this);
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
MyService.this.stopSelf();
// if (windowManager != null) windowManager.removeView(view);
}
});
AlertDialog dialog = builder.create();
dialog.setMessage("我的计数"+num);
dialog.setTitle("提示");
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
dialog.show();
}
break;
}
}
};
private final String TAG = "ccb";
private String args;
private int num;
private final int HANDLERSIGN = 10;
private final int HANDLERTIME = 2010;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
args = intent.getStringExtra("args");
// initView();
initView2();
initData();
return super.onStartCommand(intent, flags, startId);
}
/**
* FloatWindow使用FloatWindow库展示悬浮框;可拖拽
*/
private void initView2() {
FloatWindow
.with(getApplicationContext())
.setView(LayoutInflater.from(this).inflate(R.layout.view_win,null))
.setWidth(100) //设置控件宽高
.setHeight(Screen.height,0.2f)
.setX(100) //设置控件初始位置
.setY(Screen.height,0.3f)
.setDesktopShow(true) //桌面显示
.setViewStateListener(new ViewStateListener() {
@Override
public void onPositionUpdate(int i, int i1) {
}
@Override
public void onShow() {
}
@Override
public void onHide() {
}
@Override
public void onDismiss() {
}
@Override
public void onMoveAnimStart() {
}
@Override
public void onMoveAnimEnd() {
}
@Override
public void onBackToDesktop() {
}
})
.setPermissionListener(new PermissionListener() {
@Override
public void onSuccess() {
}
@Override
public void onFail() {
}
})
.build();
FloatWindow.get().show();
}
/**
* 使用系统级别的WindowManager展示悬浮框,需要6.0以上的权限;
*/
private void initView() {
if (Build.VERSION.SDK_INT >= 23) {
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setData(Uri.parse( "package:"+"com.example.administrator.xuanfudemo"));
startActivity(intent);
} else {
openWindow();
}
}else {
openWindow();
}
}
private void openWindow(){
windowManager = (WindowManager) this.getSystemService(WINDOW_SERVICE);
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
// layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
// layoutParams.token = this.getWindow().getDecorView().getWindowToken();
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
layoutParams.format = PixelFormat.TRANSLUCENT;
layoutParams.gravity = Gravity.TOP | Gravity.RIGHT;
view = LayoutInflater.from(this).inflate(R.layout.view_win,null);
windowManager.addView(view,layoutParams);
}
private void initData() {
mHandler.sendEmptyMessageDelayed(HANDLERSIGN,HANDLERTIME);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy: 啊,ByKill");
mHandler.removeCallbacksAndMessages(null);
if (windowManager != null) windowManager.removeView(view);
FloatWindow.destroy();
}
}
Android悬浮框,在Service中打开悬浮窗;在Service中打开Dialog;的更多相关文章
- Android音视频通话过程中最小化成悬浮框的实现(类似Android8.0画中画效果)
关于音视频通话过程中最小化成悬浮框这个功能的实现,网络上类似的文章很多,但是好像还没看到解释的较为清晰的,这里因为项目需要实现了这样的一个功能,今天我把它记录下来,一方面为了以后用到便于自己查阅,一方 ...
- Android仿360手机卫士悬浮窗效果
请看下图: 首先是一个小的悬浮窗显示的是当前使用了百分之多少的内存,点击一下小悬浮窗,就会弹出一个大的悬浮窗,可以一键加速.好,我们现在就来模拟实现一下 ...
- android桌面悬浮窗实现
首先是一个小的悬浮窗显示的是当前使用了百分之多少的内存,点击一下小悬浮窗,就会弹出一个大的悬浮窗,可以一键加速.好,我们现在就来模拟实现一下类似的效果. ...
- Android 桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果
首先是一个小的悬浮窗显示的是当前使用了百分之多少的内存,点击一下小悬浮窗,就会弹出一个大的悬浮窗,可以一键加速.好,我们现在就来模拟实现一下类似的效果. 先谈一下基本的实现原理,这种桌面悬浮窗的效果很 ...
- Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果
大家好,今天给大家带来一个仿360手机卫士悬浮窗效果的教程,在开始之前请允许我说几句不相干的废话. 不知不觉我发现自己接触Android已有近三个年头了,期间各种的成长少不了各位高手的帮助,总是有很多 ...
- Android 悬浮窗、悬浮球开发
原文:Android 悬浮窗.悬浮球开发 1.权限管理 直接看我另外一篇博客吧,传送门: https://my.oschina.net/u/1462828/blog/1933162 2.Base类Ba ...
- 微信小程序中悬浮窗功能的实现(主要探讨和解决在原生组件上的拖动)
问题场景 所谓悬浮窗就是图中微信图标的按钮,采用fixed定位,可拖动和点击. 这算是一个比较常见的实现场景了. 为什么要用cover-view做悬浮窗?原生组件出来背锅了~ 最初我做悬浮窗用的不是c ...
- 自制悬浮框,愉快地查看栈顶 Activity
接手陌生模块时,如何快速了解每个页面对应的类,以及它们之间的跳转逻辑.总不能在代码里一个一个地找startActivity()吧? 有时候,又想查看别人的 app 的页面组织(像淘宝.微信啊),总不能 ...
- Android -- 使用WindowManager实现悬浮框效果
1,原文在这里http://blog.csdn.net/qq_17250009/article/details/52908791,我只是把里面的关键步骤给注释了一下,首先来看一下我们的效果,如图(电脑 ...
随机推荐
- openstack--6--控制节点和计算节点安装配置neutron
Neutron相关介绍 早期的时候是没有neutron,早期所使用的网络的nova-network,经过版本改变才有个neutron. quantum是因为商标和别的公司重名了,又改成的Neutron ...
- 关于TP5的一对一、一对多同时存在的关联查询
主表SQL(tp_member) CREATE TABLE `tp_member` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id', `us ...
- makedepend: command not found(转)
makedepend: command not found 解决方案: 修改Makefile MAKEDEPEND=$(CC) -M 参考: When I set CROSS_COMPILE, `MA ...
- NET设计模式 第二部分 创建型模式(5):原型模式(Prototype Pattern)
原型模式(Prototype Pattern) ——.NET设计模式系列之六 Terrylee,2006年1月 概述 在软件系统中,有时候面临的产品类是动态变化的,而且这个产品类具有一定的等级结构.这 ...
- 【python】多线程详解
一.进程与线程关系 一个进程至少包含一个线程. 二.线程基础 1.线程的状态 线程有5种状态,状态转换的过程如下图所示: 2.线程同步(锁) 多线程的优势在于可以同时运行多个任务(至少感觉起来是这样) ...
- SDI工程时钟路径分析
SDI工程时钟路径分析 //------------- Receive Ports - RX Fabric Output Control Ports ------------- output rxou ...
- 【Java】线程转储分析 ThreadDump
[[TOC]] 通过分析 ThreadDump 来查询Java程序运行情况 获取线程转储文件 有多种方式可以获取转储文件,可参考链接HOW TO TAKE THREAD DUMPS? – 8 OPTI ...
- elastic-job 新手指南&官网指南
elastic-job 新手指南 Elastic-Job——分布式定时任务框架 官网帮助文档
- 廖雪峰Java4反射与泛型-1反射-4调用构造方法
1.Class.newInstance()只能调用public的无参数构造方法 public class Main { public static void main(String[] args) t ...
- openstack云主机硬盘复制查询
假定客户在自己的电脑上创建文件后 #宿主机查看客户使用的是哪个磁盘 [root@compute1 ~]# lvs LV VG Attr LSize Pool Origin Data% Meta ...