Android 实现Service悬浮窗监听实时网速

        我们都知道Android 的Service一般情况下是没有界面的,也就是运行在后台看不见的地方,实际上Service也可以是可见的,这篇文章简单记录一下如何让Service可见。

        在安卓8以后显示悬浮窗需要动态申请“在其他应用上显示悬浮窗”权限,所以我们首先需要申请这一个权限,在manifest文件中添加一下权限:

       接下来是在APP启动时申请显示悬浮窗的权限,当检查到没有权限的时候会自动跳转到系统设置界面:

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);
                startActivityForResult(intent, 1);
            } else {
                Log.e("TAG", "H");
                //TODO do something you need
            }
        }

      接下来就是Service的创建,在onCreate()方法中创建对应的弹窗布局,并显示:


    private NetSpeedTask netSpeedTask;
    private Timer timer;
    private NetSpeedUtil netSpeedUtil;
    private LinearLayout linearLayout;
    private TextView textView;
    private WindowManager windowManager;
    private MyHandler myHandler;
 @Override
    public void onCreate() {
        super.onCreate();
        netSpeedTask = new NetSpeedTask();
        timer = new Timer();
        netSpeedUtil = new NetSpeedUtil();
        myHandler = new MyHandler(Looper.getMainLooper(), this);
        linearLayout = (LinearLayout) LayoutInflater.from(getApplicationContext()).inflate(R.layout.layout_net_speed, null);
        textView = linearLayout.findViewById(R.id.net_speed);
        windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        windowManager.addView(linearLayout, getParams(0));
    }
private WindowManager.LayoutParams getParams(int y) {
        WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
        mParams.width = android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
        mParams.height = android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            mParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            mParams.type = WindowManager.LayoutParams.TYPE_PHONE;
        }
        mParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;//悬浮在应用之上
        mParams.format = PixelFormat.TRANSPARENT;
        mParams.gravity = Gravity.TOP | Gravity.LEFT;
        mParams.x = 0;
        mParams.y = y;
        return mParams;
    }

    通过startService()开启服务后就会在手机上显示一个悬浮窗,到这里“让Service可见的工作就完成了”,接下来是网速监听部分实现:

   首先我们需要一个定时器,按照一定的频率获取当前实时网速,由于在子线程是不能直接更新UI的,这里我们使用Handler实现在子线程中更新UI,进而实时显示网速,但滥用Handler容易导发生内存泄露,防止发生内存泄露的方法之一就是使用弱引用对象,创建自定义的MyHadler继承Handler:

private static class MyHandler extends Handler {
        private final WeakReference weakReference;

        public MyHandler(@NonNull Looper looper, NetSpeedService netSpeedService) {
            super(looper);
            this.weakReference = new WeakReference<>(netSpeedService);
        }

        @SuppressLint("SetTextI18n")
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            NetSpeedService netSpeedService = weakReference.get();
            if (msg.what == 1001) {
                String speed = msg.obj.toString();
                netSpeedService.textView.setText("当前网速 ---->" + speed);
            }
        }
    }

计时器:

 private class NetSpeedTask extends TimerTask {
        @Override
        public void run() {
            Message message = new Message();
            message.what = 1001;
            message.obj = netSpeedUtil.getNetSpeed(getApplicationInfo().uid);
            myHandler.sendMessage(message);
        }
    }
NetSpeedUtil工具类:
/**
 * 网速获取工具
 */
public class NetSpeedUtil {

    private long lastTotalRxBytes = 0;
    private long lastTimeStamp = 0;

    public String getNetSpeed(int uid) {
        long nowTotalRxBytes = getTotalRxBytes(uid);
        long nowTimeStamp = System.currentTimeMillis();
        long speed = ((nowTotalRxBytes - lastTotalRxBytes) * 100 / (nowTimeStamp - lastTimeStamp));//毫秒转换
        lastTimeStamp = nowTimeStamp;
        lastTotalRxBytes = nowTotalRxBytes;
        return speed + " Kb/s";
    }

    public long getTotalRxBytes(int uid) {
        return TrafficStats.getUidRxBytes(uid) == TrafficStats.UNSUPPORTED ? 0 : (TrafficStats.getTotalRxBytes() / 1024);//转为KB
    }
}

最后在服务的onStartCommand()方法中调用:

 private void startTimer() {
        netSpeedTask = null;
        netSpeedTask = new NetSpeedTask();
        timer.schedule(netSpeedTask, 500, 500);
    }

你可能感兴趣的:(android,java,开发语言)