欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

在状态栏StatusBar中添加网速实时显示

程序员文章站 2022-05-01 14:46:17
...

本篇文章教大家如何在状态栏中加入网速实时监控,效果如下图所示

在状态栏StatusBar中添加网速实时显示

上图就是要实现的效果,我们可以通过自定义一个View,让它继承TextView,然后在该View内部添加获取实时网络并显示出来的逻辑,废话不多说,看一下代码

首先,在frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\phone下新建一个NetShowView,让它继承TextView

private long lastTotalRxBytes = 0;//上一次获取的总消耗流量  
    private long lastTimeStamp = 0;//记录上一次时间
    private String mSpeed="";
    private Paint mPaint;
    private Rect mBound;
	  private Context mContext;
	  private SettingsValueChangeContentObserver mContentOb;//监控数据库,是否打开网速显示
	  private NetworkConnectReceiver mNetReceiver;
	  private boolean mIsConn;//判断当前是否有网络连接
	  
	  public NetShowView(Context context, AttributeSet attrs) {
		super(context, attrs);
		setPaint(context);
	}
	
	
	private void setPaint(Context context){
		mContext=context;
		mPaint=new Paint();
        mPaint.setAntiAlias(true);
		mPaint.setColor(this.getCurrentTextColor());
		mPaint.setTextSize(getTextSize());
		mBound = new Rect();
		checkNetConnInit();
	}

 @Override
	protected void onDraw(Canvas canvas) {
	   super.onDraw(canvas);
	   mPaint.getTextBounds(mSpeed, 0, mSpeed.length(), mBound);
	   canvas.drawText(mSpeed, getWidth() - mBound.width()-10, getHeight() / 2 + mBound.height() / 2, mPaint);
	}

首先在该类里定义一些变量,在构造方法中初始化一些Paint的属性,并在onDraw方法中将网速mSpeed显示上去,以上内容比较简单,不再详述,我们看到在setPaint方法中有一个checkNetConnInit()方法,我们来看一下它的具体实现

	private void checkNetConnInit(){
	 	if(mContentOb==null){
            mContentOb = new SettingsValueChangeContentObserver();
	          mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(Settings.Global.NETWORK_SPEED),true, mContentOb);
        }
		if(mNetReceiver==null){
				mNetReceiver= new NetworkConnectReceiver();
	    	IntentFilter filter = new IntentFilter();
	    	filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
			  filter.addAction(NetSpeedService.SEND_ACTION);
	    	mContext.registerReceiver(mNetReceiver, filter);
		}


该类分别作了两个操作,初始化SettingsValueChangeContentObserver为其注册监听,然后初始化NetworkConnectReceiver为其注册事件,为其添加了两个action,分别为ConnectivityManager.CONNECTIVITY_ACTION和NetSpeedService.SEND_ACTION,ConnectivityManager.CONNECTIVITY_ACTION这个action是用来监听网络是否连接的,NetSpeedService.SEND_ACTION这个暂时先不看,稍后分析,我们来看一下SettingsValueChangeContentObserver和NetworkConnectReceiver的具体实现

class SettingsValueChangeContentObserver extends ContentObserver {
		 
        public SettingsValueChangeContentObserver() {
            super( new Handler());
        }
 
        @Override
        public void onChange(boolean selfChange) {
            super.onChange(selfChange);
			if(mIsConn){
				int state=Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.NETWORK_SPEED,0);
				if(state==1){
					start();//开始显示网速
				}else{
					stop();//停止显示网速
				}
        	}
		}  
    }
	
	

 
class NetworkConnectReceiver extends BroadcastReceiver {
	@Override
	public void onReceive(Context context, Intent intent) {
		if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
			NetworkInfo info = intent
					.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
			if (info != null) {
				if (NetworkInfo.State.CONNECTED == info.getState()) {
					mIsConn = true;
					boolean isOpen = Settings.Global.getInt(
							context.getContentResolver(),
							Settings.Global.NETWORK_SPEED, 0) == 1;
					if (isOpen) {
						start();
					} else {
						stop();
					}
				} else {
					mIsConn = false;
					stop();
				}
			}
		}
		if (intent.getAction().equals(NetSpeedService.SEND_ACTION)) {
			showNetSpeed();
		}
	}
}



SettingsValueChangeContentObserver这个内容观察者监听Settings.Global.NETWORK_SPEED的值变化,这个是我们在SettingProvider中自定义的一个全局变量,我们用它来为网速显示提供一个控制开关,当Settings.Global.NETWORK_SPEED值为1显示网速,为0则关闭网速显示,默认关闭


NetworkConnectReceiver中定义了两个action,我们首先来看一下ConnectivityManager.CONNECTIVITY_ACTION这个action,当NetworkConnectReceiver接收到这个事件后,代表当前打开了数据流量或者连上了WiFi,然后经过一系列判断后,我们根据网络状态和Settings.Global.NETWORK_SPEED的值调用start()方法和stop()方法,下面我们来看一下这两个方法做了什么操作

private void start(){
		lastTotalRxBytes = TrafficStats.getTotalRxBytes();  
        lastTimeStamp = System.currentTimeMillis();
		mContext.startService(new Intent(mContext, NetSpeedService.class));
		setVisibility(View.VISIBLE);
	}

	private void stop(){
		mContext.stopService(new Intent(mContext, NetSpeedService.class));
		setVisibility(View.GONE);
	}     

start()方法中通过TrafficStats.getTotalRxBytes()获取了总接收流量,并赋予lastTotalRxBytes,开启了服务NetSpeedService,设置当前Visble为可见,stop方法调用了NetSpeedService的停止方法以及设置当前Visble为不可见,两个方法都比较简单,回过头来我们看一下NetworkConnectReceiver的另一个事件NetSpeedService.SEND_ACTION,这里调用了showNetSpeed()方法,这个方法就是计算显示网速的方法,我们来看一下具体实现

private void showNetSpeed() {  
       long nowTotalRxBytes = TrafficStats.getTotalRxBytes();  
       long nowTimeStamp = System.currentTimeMillis();
	   //modify by wxc on 20180111
	   long difTime=nowTimeStamp - lastTimeStamp;
	   if(difTime<=0){
	   		mSpeed="0B/s";
	   }else{	
       		String endTotal;
			long speedTotal=(nowTotalRxBytes-lastTotalRxBytes)*1000/difTime; 
			if(speedTotal<1000){
    	   		mSpeed=speedTotal+"B/s";
       		}else if(speedTotal<1000*1024){
       			endTotal=String.valueOf(speedTotal % 1024);
       			speedTotal=speedTotal/1024;
       			if(endTotal.length()>1){
       				endTotal=endTotal.substring(0, 1);
       			}
       			mSpeed=speedTotal+"."+endTotal+"K/s";
       		}else{
	   			endTotal=String.valueOf(speedTotal% (1024*1024));
       			speedTotal=speedTotal/1024/1024;
       			if(endTotal.length()>1){
       				endTotal=endTotal.substring(0, 1);
       			}
       			mSpeed=speedTotal+"."+endTotal+"M/s";
			}
       }
       lastTimeStamp = nowTimeStamp;
       lastTotalRxBytes = nowTotalRxBytes;
       invalidate();
   }

以上就是showNetSpeed方法,该方法主要计算了当前网速,并将网速赋值给mSpeed,通过invalidate()方法刷新当前view显示,过程不难,不再详述,这里我们回过头来看一下NetSpeedService这个服务,该服务主要通过scheduledExecutor.scheduleWithFixedDelay方法进行一个周期任务,每隔一秒发送一个NetSpeedService.SEND_ACTION广播,当NetworkConnectReceiver接收到该广播就调用showNetSpeed()方法来刷新网速显示,以下是NetSpeedService的全部代码

public class NetSpeedService extends Service{
    public static final String SEND_ACTION="SEND_ACTION";
    private ScheduledExecutorService scheduledExecutor;
    @Override
    public void onCreate() {
        super.onCreate();
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
		stopAddOrSubtract();
		updateAddOrSubtract();
        return START_STICKY;
    }
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        stopAddOrSubtract();
    }
    private void updateAddOrSubtract() {
        if(scheduledExecutor==null){
            scheduledExecutor = Executors.newSingleThreadScheduledExecutor();
            scheduledExecutor.scheduleWithFixedDelay(new Runnable() {
                @Override
                public void run() {
                    Intent sendIntent = new Intent(SEND_ACTION);
                    getApplicationContext().sendBroadcast(sendIntent);
                }
            }, 0, 1, TimeUnit.SECONDS);
        }
    }
    
    private void stopAddOrSubtract() {
        if (scheduledExecutor != null) {
            scheduledExecutor.shutdownNow();
            scheduledExecutor = null;
        }
    }
}

以上内容完成后自定义的NetShowView就完成了,这时候我们需要将其添加到如图所示的StatusBar上,打开frameworks\base\packages\SystemUI\res\layout\system_icons.xml文件,在此文件中添加该view,大小位置可以自己调节,同时我们可以在Setting中添加一个网速显示的switch开关,通过设置Settings.Global.NETWORK_SPEED的值来实现功能

<com.android.systemui.statusbar.phone.NetShowView
             android:id="@+id/net_show_text"
             android:layout_width="56dp"
             android:layout_height="match_parent"
             android:textColor="#ffffff"
             android:visibility="gone"
             android:textSize="12dip"
            />
OK,通过以上的步骤就可以在状态栏添加实时网速监控了,感兴趣的可以自己试试