在状态栏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,通过以上的步骤就可以在状态栏添加实时网速监控了,感兴趣的可以自己试试