文章介绍了如何在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都会执行;同时别忘记这个注册:
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); }
悬浮框需要权限,而且这个权限属于危险级权限,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(); }}