很多安全卫士类软件都实现了网速监测功能,也算是一个比较实用的功能。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();@Overridepublic void onCreate() {super.onCreate();createFloatView();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {return START_STICKY_COMPATIBILITY;}@Overridepublic IBinder onBind(Intent intent) {return binder;}@Overridepublic 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_ALERTwmParams.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初始值,相对于gravitywmParams.y = 10;// 获取浮动窗口视图所在布局LayoutInflater inflater = LayoutInflater.from(getApplication());mFloatLayout = (LinearLayout) inflater.inflate(R.layout.float_layout, null);mWindowManager.addView(mFloatLayout, wmParams);// 添加mFloatLayoutmFloatView = (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() {@Overridepublic 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() {@Overridepublic void onClick(View arg0) {                            // do something... 跳转到应用}});}public void setSpeed(String str) {mFloatView.setText(str.toString());}@Overridepublic 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;elsereturn 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() {@Overridepublic 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;}}

然后再Activity里面,就需要去启动Service,以显示悬浮窗,然后TrafficInfo通过Handler,把当前网速发给Activity,Activity调用Service的方法了来更新悬浮窗的View。

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;@Overrideprotected 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() {@Overridepublic 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;            }        };@Overrideprotected void onDestroy() {super.onDestroy();speed.stopCalculateNetSpeed();unbindService(conn); }}

这样,就能够显示悬浮窗。如果还需要后台运行,那Service就需要常驻不被杀死,这部分请参考我另一篇博文: Android 通过JNI实现守护进程,保证Service服务不被杀死

附上Demo源码:Android 流量与网速监测(悬浮窗) 源码

Android实现流量统计和网速监控悬浮窗_第1张图片


更多相关文章

  1. Android判断上网方式(Wifi还是数据流量)
  2. 大佬就是强!意外收获字节跳动内部资料——《Android Binder机制实
  3. android上文本框输入限制最大字节数
  4. [置顶] Android防火墙+流量统计代码
  5. Android 分享一个流量显示界面
  6. Android获取网速和下载速度
  7. android中流的理解。(字节流读写与字符流的读写)
  8. android获取手机流量使用情况

随机推荐

  1. Android[中级教程]第十章 Mysql+Json+And
  2. android之AIDL实例详解
  3. android4.0下使用multiDexEnabled属性的
  4. android home键的处理
  5. Android Recovery UI浅析1——概览
  6. Android: HttpClient与Webview共享cookie
  7. QtAndroid详解(4):JNI调用Android系统功能
  8. Android应用无线测试要点
  9. 将android Market缓存转移到SD卡的小程序
  10. Android(安卓)LruCache内存缓存图片