很多安全卫士类软件都实现了网速监测功能,也算是一个比较实用的功能。Android下,TrafficStats类实现了对流量的统计。
static long getMobileRxBytes()//获取通过Mobile连接收到的字节总数,但不包含WiFi static long getMobileRxPackets()//获取Mobile连接收到的数据包总数 static long getMobileTxBytes()//Mobile发送的总字节数 static long getMobileTxPackets()//Mobile发送的总数据包数 static long getTotalRxBytes()//获取总的接受字节数,包含Mobile和WiFi等 static long getTotalRxPackets()//总的接受数据包数,包含Mobile和WiFi等 static long getTotalTxBytes()//总的发送字节数,包含Mobile和WiFi等 static long getTotalTxPackets()//发送的总数据包数,包含Mobile和WiFi等 static long getUidRxBytes(int uid)//获取某个网络UID的接受字节数 static long getUidTxBytes(intuid) //获取某个网络UID的发送字节数
这些就是TrafficStats提供的一些接口。那么,我们首先要创建一个桌面悬浮窗,用于显示网速。然后再Service里面,显示悬浮窗。
import android.app.Service; import android.content.Intent; import android.graphics.PixelFormat; import android.os.Binder; import android.os.IBinder; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnTouchListener; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.widget.LinearLayout; import android.widget.TextView; import com.yyh.utils.WidgetUtils; public class ManagerService extends Service { private static final String TAG = "ManagerService"; public LinearLayout mFloatLayout; public WindowManager.LayoutParams wmParams; public WindowManager mWindowManager; public TextView mFloatView; private ServiceBinder binder = new ServiceBinder(); @Override public void onCreate() { super.onCreate(); createFloatView(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return START_STICKY_COMPATIBILITY; } @Override public IBinder onBind(Intent intent) { return binder; } @Override public void onTrimMemory(int level) { Log.i("test", " onTrimMemory..."); } /** 创建悬浮窗 */ private void createFloatView() { wmParams = new WindowManager.LayoutParams(); mWindowManager = (WindowManager) getApplication().getSystemService(getApplication().WINDOW_SERVICE); wmParams.type = LayoutParams.TYPE_SYSTEM_ALERT;// 设置window // type为TYPE_SYSTEM_ALERT wmParams.format = PixelFormat.RGBA_8888;// 设置图片格式,效果为背景透明 wmParams.flags = LayoutParams.FLAG_NOT_FOCUSABLE;// 设置浮动窗口不可聚焦(实现操作除浮动窗口外的其他可见窗口的操作) wmParams.gravity = Gravity.LEFT | Gravity.TOP;// 默认位置:左上角 wmParams.width = WidgetUtils.dpToPx(getApplicationContext(), 65); wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT; wmParams.x = (WidgetUtils.getScreenWidth(getApplicationContext()) - wmParams.width) / 2;// 设置x、y初始值,相对于gravity wmParams.y = 10; // 获取浮动窗口视图所在布局 LayoutInflater inflater = LayoutInflater.from(getApplication()); mFloatLayout = (LinearLayout) inflater.inflate(R.layout.float_layout, null); mWindowManager.addView(mFloatLayout, wmParams);// 添加mFloatLayout mFloatView = (TextView) mFloatLayout.findViewById(R.id.speed); mFloatLayout.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); // 设置监听浮动窗口的触摸移动 mFloatView.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // getRawX是触摸位置相对于屏幕的坐标,getX是相对于按钮的坐标 wmParams.x = (int) event.getRawX() - mFloatView.getMeasuredWidth() / 2; Log.i(TAG, "RawX" + event.getRawX()); Log.i(TAG, "X" + event.getX()); wmParams.y = (int) event.getRawY() - mFloatView.getMeasuredHeight() / 2 - 25;// 减25为状态栏的高度 Log.i(TAG, "RawY" + event.getRawY()); Log.i(TAG, "Y" + event.getY()); mWindowManager.updateViewLayout(mFloatLayout, wmParams);// 刷新 return false; // 此处必须返回false,否则OnClickListener获取不到监听 } }); mFloatView.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { // do something... 跳转到应用 } }); } public void setSpeed(String str) { mFloatView.setText(str.toString()); } @Override public void onDestroy() { super.onDestroy(); if (mFloatLayout != null && mWindowManager != null) { mWindowManager.removeView(mFloatLayout);// 移除悬浮窗口 } startService(new Intent(this, ManagerService.class)); } class ServiceBinder extends Binder { public ManagerService getService() { return ManagerService.this; } } }然后构造一个网速监测的工具类,用于获取流量变化信息。
import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.math.BigDecimal; import java.util.Timer; import java.util.TimerTask; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.net.TrafficStats; import android.os.Handler; import android.os.Message; import android.util.Log; /** * 应用的流量信息 * @author yuyuhang */ public class TrafficInfo { private static final int UNSUPPORTED = -1; private static final String LOG_TAG = "test"; private static TrafficInfo instance; static int uid; private long preRxBytes = 0; private Timer mTimer = null; private Context mContext; private Handler mHandler; /** 更新频率(每几秒更新一次,至少1秒) */ private final int UPDATE_FREQUENCY = 1; private int times = 1; public TrafficInfo(Context mContext, Handler mHandler, int uid) { this.mContext = mContext; this.mHandler = mHandler; this.uid = uid; } public TrafficInfo(Context mContext, Handler mHandler) { this.mContext = mContext; this.mHandler = mHandler; } public static TrafficInfo getInstant(Context mContext, Handler mHandler) { if (instance == null) { instance = new TrafficInfo(mContext, mHandler); } return instance; } /** * 获取总流量 */ public long getTrafficInfo() { long rcvTraffic = UNSUPPORTED; // 下载流量 long sndTraffic = UNSUPPORTED; // 上传流量 rcvTraffic = getRcvTraffic(); sndTraffic = getSndTraffic(); if (rcvTraffic == UNSUPPORTED || sndTraffic == UNSUPPORTED) return UNSUPPORTED; else return rcvTraffic + sndTraffic; } /** * 获取下载流量 某个应用的网络流量数据保存在系统的/proc/uid_stat/$UID/tcp_rcv | tcp_snd文件中 */ public long getRcvTraffic() { long rcvTraffic = UNSUPPORTED; // 下载流量 rcvTraffic = TrafficStats.getUidRxBytes(uid); if (rcvTraffic == UNSUPPORTED) { // 不支持的查询 return UNSUPPORTED; } Log.i("test", rcvTraffic + "--1"); RandomAccessFile rafRcv = null, rafSnd = null; // 用于访问数据记录文件 String rcvPath = "/proc/uid_stat/" + uid + "/tcp_rcv"; try { rafRcv = new RandomAccessFile(rcvPath, "r"); rcvTraffic = Long.parseLong(rafRcv.readLine()); // 读取流量统计 } catch (FileNotFoundException e) { Log.e(LOG_TAG, "FileNotFoundException: " + e.getMessage()); rcvTraffic = UNSUPPORTED; } catch (IOException e) { Log.e(LOG_TAG, "IOException: " + e.getMessage()); e.printStackTrace(); } finally { try { if (rafRcv != null) rafRcv.close(); if (rafSnd != null) rafSnd.close(); } catch (IOException e) { Log.w(LOG_TAG, "Close RandomAccessFile exception: " + e.getMessage()); } } Log.i("test", rcvTraffic + "--2"); return rcvTraffic; } /** * 获取上传流量 */ public long getSndTraffic() { long sndTraffic = UNSUPPORTED; // 上传流量 sndTraffic = TrafficStats.getUidTxBytes(uid); if (sndTraffic == UNSUPPORTED) { // 不支持的查询 return UNSUPPORTED; } RandomAccessFile rafRcv = null, rafSnd = null; // 用于访问数据记录文件 String sndPath = "/proc/uid_stat/" + uid + "/tcp_snd"; try { rafSnd = new RandomAccessFile(sndPath, "r"); sndTraffic = Long.parseLong(rafSnd.readLine()); } catch (FileNotFoundException e) { Log.e(LOG_TAG, "FileNotFoundException: " + e.getMessage()); sndTraffic = UNSUPPORTED; } catch (IOException e) { Log.e(LOG_TAG, "IOException: " + e.getMessage()); e.printStackTrace(); } finally { try { if (rafRcv != null) rafRcv.close(); if (rafSnd != null) rafSnd.close(); } catch (IOException e) { Log.w(LOG_TAG, "Close RandomAccessFile exception: " + e.getMessage()); } } return sndTraffic; } /** * 获取当前下载流量总和 */ public static long getNetworkRxBytes() { return TrafficStats.getTotalRxBytes(); } /** * 获取当前上传流量总和 */ public static long getNetworkTxBytes() { return TrafficStats.getTotalTxBytes(); } /** * 获取当前网速,小数点保留一位 */ public double getNetSpeed() { long curRxBytes = getNetworkRxBytes(); if (preRxBytes == 0) preRxBytes = curRxBytes; long bytes = curRxBytes - preRxBytes; preRxBytes = curRxBytes; //int kb = (int) Math.floor(bytes / 1024 + 0.5); double kb = (double)bytes / (double)1024; BigDecimal bd = new BigDecimal(kb); return bd.setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue(); } /** * 开启流量监控 */ public void startCalculateNetSpeed() { preRxBytes = getNetworkRxBytes(); if (mTimer != null) { mTimer.cancel(); mTimer = null; } if (mTimer == null) { mTimer = new Timer(); mTimer.schedule(new TimerTask() { @Override public void run() { if(times == UPDATE_FREQUENCY){ Message msg = new Message(); msg.what = 1; //msg.arg1 = getNetSpeed(); msg.obj = getNetSpeed(); mHandler.sendMessage(msg); times = 1; } else { times++; } } }, 1000, 1000); // 每秒更新一次 } } public void stopCalculateNetSpeed() { if (mTimer != null) { mTimer.cancel(); mTimer = null; } } /** * 获取当前应用uid */ public int getUid() { try { PackageManager pm = mContext.getPackageManager(); ApplicationInfo ai = pm.getApplicationInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES); return ai.uid; } catch (NameNotFoundException e) { e.printStackTrace(); } return -1; } }
import java.util.List; import android.app.ActivityManager; import android.app.ActivityManager.RunningAppProcessInfo; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.support.v7.app.ActionBarActivity; import android.util.Log; import android.widget.TextView; import com.yyh.utils.TrafficInfo; public class MainActivity extends ActionBarActivity { private ActivityManager mActivityManager; private TextView mTextView; Handler mHandler; TrafficInfo speed; ManagerService service; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mActivityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); mTextView = (TextView) findViewById(R.id.tv); try { mHandler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == 1) { mTextView.setText(msg.obj + "kb/s"); if(service != null) service.setSpeed(msg.obj+"kb/s"); // 设置网速 } super.handleMessage(msg); } }; speed = new TrafficInfo(this,mHandler,TrafficInfo.getUid()); speed.startCalculateNetSpeed(); // 开启网速监测 } catch (Exception e) { e.printStackTrace(); } Log.i("test","总流量="+speed.getTrafficInfo()); Intent intent = new Intent(MainActivity.this, ManagerService.class); bindService(intent, conn, Context.BIND_AUTO_CREATE); } private ServiceConnection conn = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder binder) { service = ((ManagerService.ServiceBinder) binder).getService(); } public void onServiceDisconnected(ComponentName name) { service = null; } }; @Override protected void onDestroy() { super.onDestroy(); speed.stopCalculateNetSpeed(); unbindService(conn); } }
附上Demo源码:Android 流量与网速监测(悬浮窗) 源码