中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

一個(gè)簡(jiǎn)單的網(wǎng)速顯示懸浮窗

2018-07-20    來(lái)源:編程學(xué)習(xí)網(wǎng)

容器云強(qiáng)勢(shì)上線!快速搭建集群,上萬(wàn)Linux鏡像隨意使用

2016轉(zhuǎn)眼就要過(guò)去了,剛剛參加完學(xué)院舉辦的元旦晚會(huì),看了看系里的大牛的各種事跡,內(nèi)心感慨萬(wàn)分;貋(lái)繼續(xù)安心做我的小碼農(nóng),順便更一下將近一個(gè)月沒(méi)有更新的博客。

這次帶來(lái)的是一個(gè)懸浮窗網(wǎng)速顯示計(jì),先看下效果:

demo

這里主要是在桌面上顯示一個(gè)懸浮窗,利用了WindowManager以及Service,接下來(lái)看看如何實(shí)現(xiàn)這樣一個(gè)效果:

首先APP必須獲得在桌面上顯示懸浮窗的機(jī)會(huì),很多第三方ROM都限制了這一權(quán)限,我們首先就是要申請(qǐng)改權(quán)限,代碼如下:

public boolean checkDrawOverlayPermission() {
        if (!Settings.canDrawOverlays(this)) {
            Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                    Uri.parse("package:" + getPackageName()));
            startActivityForResult(intent, REQUEST_CODE);
            return false;
        }
        return true;
    }

該函數(shù)首先檢查APP是否有顯示懸浮窗的權(quán)限,如果沒(méi)有,就跳轉(zhuǎn)到該APP設(shè)置懸浮窗權(quán)限的界面,如下圖所示:

然后先編寫我們的懸浮窗,布局很簡(jiǎn)單,就是兩個(gè)TextView:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#88000000">


    <TextView
        android:layout_marginLeft="3dp"
        android:layout_marginRight="3dp"
        android:id="@+id/speed_up"
        android:text="upload speed"
        android:gravity="left"
        android:textSize="10dp"
        android:layout_centerHorizontal="true"
        android:textColor="@android:color/white"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:layout_marginLeft="3dp"
        android:layout_marginRight="3dp"
        android:id="@+id/speed_down"
        android:layout_below="@id/speed_up"
        android:text="download speed"
        android:gravity="left"
        android:textSize="10dp"
        android:layout_centerHorizontal="true"
        android:textColor="@android:color/white"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>

SpeedView:

public class SpeedView extends FrameLayout {
    private Context mContext;
    public TextView downText;
    public TextView upText;
    private WindowManager windowManager;
    private int statusBarHeight;
    private float preX,preY,x,y;

    public SpeedView(Context context) {
        super(context);
        mContext=context;
        init();
    }

    private void init() {
        statusBarHeight=WindowUtil.statusBarHeight;
        windowManager= (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        //a view inflate itself, that's funny
        inflate(mContext,R.layout.speed_layout,this);
        downText= (TextView) findViewById(R.id.speed_down);
        upText= (TextView) findViewById(R.id.speed_up);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                preX=event.getRawX();preY=event.getRawY()-statusBarHeight;
                return true;
            case MotionEvent.ACTION_MOVE:
                x=event.getRawX();y=event.getRawY()-statusBarHeight;
                WindowManager.LayoutParams params= (WindowManager.LayoutParams) getLayoutParams();
                params.x+=x-preX;
                params.y+=y-preY;
                windowManager.updateViewLayout(this,params);
                preX=x;preY=y;
                return true;
            default:
                break;

        }
        return super.onTouchEvent(event);
    }

在SpeedView里我們重寫了onTouchEvent事件,這樣就能響應(yīng)我們的拖拽事件了,注意這里更新SpeedView的位置是通過(guò)改變WindowManager.LayoutParam的x和y來(lái)實(shí)現(xiàn)的,調(diào)用 windowManager.updateViewLayout(this,params) 來(lái)更新位置。

因?yàn)槲覀兊木W(wǎng)速顯示懸浮窗要脫離于Activity的生命周期而獨(dú)立存在,因此需要通過(guò)Service來(lái)實(shí)現(xiàn):

public class SpeedCalculationService extends Service {
    private WindowUtil windowUtil;
    private boolean changed=false;

    @Override
    public void onCreate() {
        super.onCreate();
        WindowUtil.initX= (int) SharedPreferencesUtils.getFromSpfs(this,INIT_X,0);
        WindowUtil.initY= (int) SharedPreferencesUtils.getFromSpfs(this,INIT_Y,0);
        windowUtil=new WindowUtil(this);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        changed=intent.getBooleanExtra(MainActivity.CHANGED,false);
        if(changed){
            windowUtil.onSettingChanged();
        }else{
            if(!windowUtil.isShowing()){
                windowUtil.showSpeedView();
            }
            SharedPreferencesUtils.putToSpfs(this,MainActivity.IS_SHOWN,true);
        }
        //return super.onStartCommand(intent, flags, startId);
        return START_STICKY;
    }



    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        WindowManager.LayoutParams params= (WindowManager.LayoutParams) windowUtil.speedView.getLayoutParams();
        SharedPreferencesUtils.putToSpfs(this, INIT_X,params.x);
        SharedPreferencesUtils.putToSpfs(this, INIT_Y,params.y);
        if(windowUtil.isShowing()){
            windowUtil.closeSpeedView();
            SharedPreferencesUtils.putToSpfs(this,MainActivity.IS_SHOWN,false);
        }
        Log.d("yjw","service destroy");
    }
}

這里的WindowUtil其實(shí)就是一個(gè)工具類,幫助我們控制懸浮窗SpeedView的顯示與隱藏:

public class WindowUtil {
    public static int statusBarHeight=0;
    //記錄懸浮窗的位置
    public static int initX,initY;
    private WindowManager windowManager;
    public SpeedView speedView;
    private WindowManager.LayoutParams params;
    private Context context;

    public boolean isShowing() {
        return isShowing;
    }

    private boolean isShowing=false;

    public static final int INTERVAL=2000;
    private long preRxBytes,preSeBytes;
    private long rxBytes,seBytes;
    private Handler handler=new Handler(){
        @Override
        public void dispatchMessage(Message msg) {
            super.dispatchMessage(msg);
            calculateNetSpeed();
            sendEmptyMessageDelayed(0,INTERVAL);
        }
    };

    public void onSettingChanged(){
        String setting= (String) SharedPreferencesUtils.getFromSpfs(context,MainActivity.SETTING,MainActivity.BOTH);
        if(setting.equals(MainActivity.BOTH)){
            speedView.upText.setVisibility(View.VISIBLE);
            speedView.downText.setVisibility(View.VISIBLE);
        }else if(setting.equals(MainActivity.UP)){
            speedView.upText.setVisibility(View.VISIBLE);
            speedView.downText.setVisibility(View.GONE);
        }else{
            speedView.upText.setVisibility(View.GONE);
            speedView.downText.setVisibility(View.VISIBLE);
        }
    }

    private void calculateNetSpeed() {
        rxBytes=TrafficStats.getTotalRxBytes();
        seBytes=TrafficStats.getTotalTxBytes()-rxBytes;
        double downloadSpeed=(rxBytes-preRxBytes)/2;
        double uploadSpeed=(seBytes-preSeBytes)/2;
        preRxBytes=rxBytes;
        preSeBytes=seBytes;
        //根據(jù)范圍決定顯示單位
        String upSpeed=null;
        String downSpeed=null;

        NumberFormat df= java.text.NumberFormat.getNumberInstance();
        df.setMaximumFractionDigits(2);

        if(downloadSpeed>1024*1024){
            downloadSpeed/=(1024*1024);
            downSpeed=df.format(downloadSpeed)+"MB/s";
        }else if(downloadSpeed>1024){
            downloadSpeed/=(1024);
            downSpeed=df.format(downloadSpeed)+"B/s";
        }else{
            downSpeed=df.format(downloadSpeed)+"B/s";
        }

        if(uploadSpeed>1024*1024){
            uploadSpeed/=(1024*1024);
            upSpeed=df.format(uploadSpeed)+"MB/s";
        }else if(uploadSpeed>1024){
            uploadSpeed/=(1024);
            upSpeed=df.format(uploadSpeed)+"kB/s";
        }else{
            upSpeed=df.format(uploadSpeed)+"B/s";
        }

        updateSpeed("↓ "+downSpeed,"↑ "+upSpeed);
    }

    public WindowUtil(Context context) {
        this.context = context;
        windowManager= (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        speedView=new SpeedView(context);
        params=new WindowManager.LayoutParams();
        params=new WindowManager.LayoutParams();
        params.x=initX;
        params.y=initY;
        params.width=params.height=WindowManager.LayoutParams.WRAP_CONTENT;
        params.type=WindowManager.LayoutParams.TYPE_PHONE;
        params.gravity= Gravity.LEFT|Gravity.TOP;
        params.format= PixelFormat.RGBA_8888;
        params.flags=WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
                //設(shè)置懸浮窗可以拖拽至狀態(tài)欄的位置
//        | WindowManager.LayoutParams.FLAG_FULLSCREEN| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;

    }

    public void showSpeedView(){
        windowManager.addView(speedView,params);
        isShowing=true;
        preRxBytes= TrafficStats.getTotalRxBytes();
        preSeBytes=TrafficStats.getTotalTxBytes()-preRxBytes;
        handler.sendEmptyMessage(0);
    }

    public void closeSpeedView(){
        windowManager.removeView(speedView);
        isShowing=false;
    }

    public void updateSpeed(String downSpeed,String upSpeed){
        speedView.upText.setText(upSpeed);
        speedView.downText.setText(downSpeed);
    }
}

WindowUtil類中也包含了一個(gè)很重要的方法,那就是計(jì)算網(wǎng)速。這里計(jì)算網(wǎng)速的方法很簡(jiǎn)單,Android提供了一個(gè)類 TrafficStats ,這個(gè)類里面為我們提供了好多接口,我們用到了其中的兩個(gè):

1.public static long getTotalTxBytes ()
Return number of bytes transmitted since device boot. Counts packets across all network interfaces, and always increases monotonically since device boot. Statistics are measured at the network layer, so they include both TCP and UDP usage.
2.public static long getTotalRxPackets ()
Return number of packets received since device boot. Counts packets across all network interfaces, and always increases monotonically since device boot. Statistics are measured at the network layer, so they include both TCP and UDP usage.

可以看出,getTotalTxBytes()方法返回系統(tǒng)自開(kāi)機(jī)到現(xiàn)在為止所一共傳輸?shù)臄?shù)據(jù)的字節(jié)數(shù),包括上傳的數(shù)據(jù)和下載的數(shù)據(jù);而getTotalRxPackets()方法返回的是系統(tǒng)自開(kāi)機(jī)到現(xiàn)在為止所一共接收到也就是下載的數(shù)據(jù)的字節(jié)數(shù),用getTotalTxBytes()-getTotalRxPackets()自然就是系統(tǒng)開(kāi)機(jī)到現(xiàn)在為止所上傳的數(shù)據(jù)的字節(jié)數(shù)。

這樣每隔一定時(shí)間,我們計(jì)算一下系統(tǒng)自開(kāi)機(jī)到目前所接受的數(shù)據(jù)包的字節(jié)數(shù)和所發(fā)送的數(shù)據(jù)的字節(jié)數(shù)的變化量,用變化量除以時(shí)間,就是這段時(shí)間的平均網(wǎng)速了。

為了每個(gè)一段時(shí)間計(jì)算一下網(wǎng)速,我們利用了一個(gè)Handler來(lái)實(shí)現(xiàn)這個(gè)定時(shí)任務(wù)

private Handler handler=new Handler(){
        @Override
        public void dispatchMessage(Message msg) {
            super.dispatchMessage(msg);
            calculateNetSpeed();
            sendEmptyMessageDelayed(0,INTERVAL);
        }
    };

這里要注意將SpeedView添加到屏幕上,也就是添加到WindowManager里的時(shí)候,這個(gè)WindowManager.LayoutParams十分重要,其參數(shù)都是有用的,這里就不細(xì)講了,詳細(xì)介紹請(qǐng)移步 官方文檔 .

最后要將我們的懸浮窗設(shè)置為開(kāi)機(jī)自啟動(dòng)的,利用一個(gè)BroadcastReceiver就可以了:

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("yjw","receiver receive boot broadcast");
        boolean isShown= (boolean) SharedPreferencesUtils.getFromSpfs(context,MainActivity.IS_SHOWN,false);
        if(isShown){
            context.startService(new Intent(context,SpeedCalculationService.class));
        }
    }
}

在Manifest里這樣注冊(cè)我們的BroadcastReceiver:

<receiver android:name="me.mrrobot97.netspeed.MyBroadcastReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <category android:name="android.intent.category.HOME" />
            </intent-filter>
        </receiver>

這樣當(dāng)系統(tǒng)啟動(dòng)完成,就會(huì)開(kāi)啟我們的Service。注意這里<intent-filter>中的<category>不可省略,親測(cè)省略后BroadcastReceiver無(wú)法接收到系統(tǒng)廣播。

最后還有一點(diǎn),在Manifest的MainActivity條目中加一個(gè)屬性: android:excludeFromRecents="true"

這樣我們的ManiActivity就不會(huì)顯示在最近任務(wù)列表,防止用戶清空任務(wù)列表時(shí)將我們的Sercvice進(jìn)程終結(jié)了。

 

 

標(biāo)簽: isp 代碼 權(quán)限

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請(qǐng)聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請(qǐng)與原作者聯(lián)系。

上一篇:10個(gè)技巧,讓你在 2017 年成為更好的Node開(kāi)發(fā)者

下一篇:一只優(yōu)雅的小爬蟲誕生記