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,我只是把里面的关键步骤给注释了一下,首先来看一下我们的效果,如图(电脑 ...
随机推荐
- 逻辑回归原理(python代码实现)
Logistic Regression Classifier逻辑回归主要思想就是用最大似然概率方法构建出方程,为最大化方程,利用牛顿梯度上升求解方程参数. 优点:计算代价不高,易于理解和实现. 缺点: ...
- git merge 和 git merge --no-ff
根据这张图片可以看出 git merge –no-ff 可以保存你之前的分支历史.能够更好的查看 merge历史,以及branch 状态. git merge 则不会显示 feature,只保留单条分 ...
- eclipse卡死在search for main types 20 files to index
run as application时,提示search for main types 20 files to index (*/*/*.jar)某个maven依赖jar出了问题,找不到main方法 ...
- scala IDE for Eclipse开发Spark程序
1.开发环境准备 scala IDE for Eclipse:版本(4.6.1) 官网下载:http://scala-ide.org/download/sdk.html 百度云盘下载:链接:http: ...
- 多线程练习,深刻体会了一次变量的BUG.
package ltb20180106; public class TestBankThread { private int deposit=0;//注意全局变量的摆放. public TestBan ...
- pytest.9.使用fixture参数化接口入参
From: http://www.testclass.net/pytest/test_api_using_params/ 背景 接上一节v2ex网站的查看论坛节点信息的api.具体如下: 节点信息 获 ...
- 测试教程网.unittest教程.5. 实例: 找出所有是弱密码的用户
From: http://www.testclass.net/pyunit/test_example_3/ 背景 当我们的测试数据是下面这些的时候,我们的用例是有问题的. [ {"name& ...
- ALGO-143_蓝桥杯_算法训练_字符串变换
问题描述 相信经过这个学期的编程训练,大家对于字符串的操作已经掌握的相当熟练了.今天,徐老师想测试一下大家对于字符串操作的掌握情况.徐老师自己定义了1,,,,5这5个参数分别指代不同的5种字符串操作, ...
- 如何查看java对象的大小
有时需要查看java对象占用了多少内存(对象大小),lucene为我们提供了一个很好的工具类,操作简单,如下: int[] s = new int[1024]; System.out.println( ...
- Hadoop概念学习系列之再谈hadoop集群里的本地模式、伪分布模式和全分布模式(三十七)
能看懂博主我此博文,相信你已经有了一定基础了. 对于本地模式.伪分布模式和全分布模式的概念,这里,我不多赘述.太多资料和博客,随便在网上一搜就好. 比如<hadoop实战 第二版>陆嘉恒老 ...