1. 程式人生 > >Android懸浮框,在Service中開啟懸浮窗;在Service中開啟Dialog;

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();
    }
}