前几天想做一个类似于360流量监控悬浮窗的效果,可以实时显示网速。
重要的读取系统的流量文件,文件路径/proc/self/net/dev
下面是复制下来的dev文件
Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
lo: 5200 48 0 0 0 0 0 0 5200 48 0 0 0 0 0 0
dummy0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
rmnet0: 43413730 45920 0 0 0 0 0 0 4447114 39247 0 0 0 0 0 0
rmnet1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
rmnet2: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
rmnet3: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
rmnet4: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
rmnet5: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
rmnet6: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
rmnet7: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
usb0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
tunl0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
ip6tnl0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
其中/eth是以太网信息 tiwlan0 是 Wifi rmnet0 是 GPRS
当然,对于不同的机型,文件格式也可能不相同,可自行下载ES文件浏览器查看,并不在sd卡中,在根目录下。
下面我们就来看看是怎么读取跟显示的
首先是悬浮窗,布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<RelativeLayout
android:id="@+id/rl_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ImageView
android:id="@+id/img_float"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/ic_launcher" />
<ImageView
android:id="@+id/img_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/presence_busy"
android:visibility="gone" />
</RelativeLayout>
<TextView
android:id="@+id/tv_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:paddingLeft="5dp"
android:textColor="#ffff4444"
android:textSize="15sp" />
</RelativeLayout>
然后是自定义的悬浮窗显示,位置可移动,单击会出现关闭悬浮窗按钮
代码如下:
public class FloatView extends View {
WindowManager mWManger;
WindowManager.LayoutParams mWManParams;
public View view;
//初始位置
private float startX;
private float startY;
//坐标
private float x;
private float y;
//
private float mTouchSatrtX;
private float mTouchStartY;
//组件
public ImageView img_folat,img_close;
public TextView tv_show;
Context mContext;
public FloatView(Context context) {
super(context);
this.mContext = context;
}
/**
* 初始化mWManger,mWManParams
*/
public void show(){
mWManger = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mWManParams = new WindowManager.LayoutParams();
//设置LayoutParams的参数
mWManParams.type = 2002;//设置系统级窗口
mWManParams.flags |= 8;
//调整悬浮窗到左上角
mWManParams.gravity = Gravity.TOP|Gravity.LEFT;
//以屏幕左上角为源点,设置x,y
mWManParams.x = 0;
mWManParams.y = 0;
//悬浮窗的长宽数据
mWManParams.width = 80;
mWManParams.height = 40;
mWManParams.format = -3;//透明
//加载悬浮窗布局文件
view = LayoutInflater.from(mContext).inflate(R.layout.traffic_view, null);
mWManger.addView(view, mWManParams);
view.setOnTouchListener(new OnTouchListener() {
/**
* 改变悬浮窗位置
*/
@Override
public boolean onTouch(View v, MotionEvent event) {
//获取相对屏幕的位置,即以屏幕左上角为原点
x = event.getRawX();
y = event.getRawY() - 25;//25为系统状态栏的高度
//Log.e("初始位置", x+"======="+y);
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
startX = x;
startY = y;
//获取相对View的坐标,以view的左上角为原点
mTouchSatrtX = event.getX();
mTouchStartY = event.getY();
//Log.e("相对view的位置", mTouchSatrtX+"--------"+mTouchStartY);
break;
case MotionEvent.ACTION_MOVE:
updatePosition();
break;
case MotionEvent.ACTION_UP:
updatePosition();
show_img_close();
mTouchSatrtX = mTouchStartY =0;
break;
}
return true;
}
});
img_close = (ImageView) view.findViewById(R.id.img_close);
/**
* 关闭悬浮窗图标点击事件
*/
img_close.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(mContext,Traffic_Service.class);
mContext.stopService(intent);
view.setVisibility(View.GONE);
}
});
tv_show = (TextView) view.findViewById(R.id.tv_show);
}
/**
* 更新悬浮窗的位置
*
*/
public void updatePosition(){
mWManParams.x = (int) (x - mTouchSatrtX);
mWManParams.y = (int) (y - mTouchStartY);
mWManger.updateViewLayout(view, mWManParams);
}
/**
* 控制关闭悬浮窗按钮的显示与隐藏
*/
public void show_img_close() {
if (Math.abs(x - startX) < 1.5 && Math.abs(y - startY) < 1.5
&& !img_close.isShown()) {
img_close.setVisibility(View.VISIBLE);
} else if (img_close.isShown()) {
img_close.setVisibility(View.GONE);
}
}
}
最后,最主要的获取网速,本来写的每秒读取一次系统流量文件,但频繁的读取会浪费系统资源,所以改成了一段时间后在读取,可根据个人需要修改,在代码中有标注,注释很清楚。
下面看看代码:
public class Traffic_Service extends Service {
//
private Handler mHandler;
// 系统流量文件
public final String DEV_FILE = "/proc/self/net/dev";
// 流量数据
String[] ethData = { "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0",
"0", "0", "0", "0", "0" };
String[] gprsData = { "0", "0", "0", "0", "0", "0", "0", "0", "0", "0",
"0", "0", "0", "0", "0", "0" };
String[] wifiData = { "0", "0", "0", "0", "0", "0", "0", "0", "0", "0",
"0", "0", "0", "0", "0", "0" };
// 用来存储前一个时间点的数据
String[] data = { "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0",
"0" };
// 以太网
final String ETHLINE = "eth0";
// wifi
final String WIFILINE = "wlan0";
// gprs
final String GPRSLINE = "rmnet0";
/**
* 定义线程周期性地获取网速
*/
private Runnable mRunnable = new Runnable() {
// 每3秒钟获取一次数据,求平均,以减少读取系统文件次数,减少资源消耗
@Override
public void run() {
refresh();
mHandler.postDelayed(mRunnable, 3000);
}
};
/**
* 启动服务时就开始启动线程获取网速
*/
@Override
public void onStart(Intent intent, int startId) {
mHandler.postDelayed(mRunnable, 0);
};
/**
* 在服务结束时删除消息队列
*/
@Override
public void onDestroy() {
mHandler.removeCallbacks(mRunnable);
super.onDestroy();
};
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
final FloatView view = new FloatView(this);
view.show();
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 1) {
// System.out.println((float) (msg.arg1 / 1024) + "kb/s");
view.tv_show.setText((float) (msg.arg1 / (1024 * 3))
+ "k/s");
}
}
};
}
/**
* 读取系统流量文件
*/
public void readDev() {
FileReader fr = null;
try {
fr = new FileReader(DEV_FILE);
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "系统流量文件读取失败", Toast.LENGTH_SHORT).show();
}
BufferedReader bufr = new BufferedReader(fr, 500);
String line;
String[] data_temp;
String[] netData;
int k;
int j;
// 读取文件,并对读取到的文件进行操作
try {
while ((line = bufr.readLine()) != null) {
data_temp = line.trim().split(":");
if (line.contains(ETHLINE)) {
netData = data_temp[1].trim().split(" ");
for (k = 0, j = 0; k < netData.length; k++) {
if (netData[k].length() > 0) {
ethData[j] = netData[k];
j++;
}
}
} else if (line.contains(GPRSLINE)) {
netData = data_temp[1].trim().split(" ");
for (k = 0, j = 0; k < netData.length; k++) {
if (netData[k].length() > 0) {
gprsData[j] = netData[k];
j++;
}
}
} else if (line.contains(WIFILINE)) {
netData = data_temp[1].trim().split(" ");
for (k = 0, j = 0; k < netData.length; k++) {
wifiData[j] = netData[k];
j++;
}
}
}
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 实时读取系统流量文件,更新
*/
public void refresh() {
// 读取系统流量文件
readDev();
// 计算增量
int[] delta = new int[12];
delta[0] = Integer.parseInt(ethData[0]) - Integer.parseInt(data[0]);
delta[1] = Integer.parseInt(ethData[1]) - Integer.parseInt(data[1]);
delta[2] = Integer.parseInt(ethData[8]) - Integer.parseInt(data[2]);
delta[3] = Integer.parseInt(ethData[9]) - Integer.parseInt(data[3]);
delta[4] = Integer.parseInt(gprsData[0]) - Integer.parseInt(data[4]);
delta[5] = Integer.parseInt(gprsData[1]) - Integer.parseInt(data[5]);
delta[6] = Integer.parseInt(gprsData[8]) - Integer.parseInt(data[6]);
delta[7] = Integer.parseInt(gprsData[9]) - Integer.parseInt(data[7]);
delta[8] = Integer.parseInt(wifiData[0]) - Integer.parseInt(data[8]);
delta[9] = Integer.parseInt(wifiData[1]) - Integer.parseInt(data[9]);
delta[10] = Integer.parseInt(wifiData[8]) - Integer.parseInt(data[10]);
delta[11] = Integer.parseInt(wifiData[9]) - Integer.parseInt(data[11]);
data[0] = ethData[0];
data[1] = ethData[1];
data[2] = ethData[8];
data[3] = ethData[9];
data[4] = gprsData[0];
data[5] = gprsData[1];
data[6] = gprsData[8];
data[7] = gprsData[9];
data[8] = wifiData[0];
data[9] = wifiData[1];
data[10] = wifiData[8];
data[11] = wifiData[9];
// 每秒下载的字节数
int traffic_data = delta[0] + delta[4] + delta[8];
// System.out.println("每秒流量"+traffic_data);
Message msg = mHandler.obtainMessage();
msg.what = 1;
msg.arg1 = traffic_data;
mHandler.sendMessage(msg);
}
}
有需要的也可以下载源码看看
附源码: 下载源码