android实例之——流量监控悬浮窗(实时网速的获取)

前几天想做一个类似于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);
	}
}
有需要的也可以下载源码看看
附源码: 下载源码



  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值