Android项目实战--手机卫士34--流量管理

Posted MiracleAce

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android项目实战--手机卫士34--流量管理相关的知识,希望对你有一定的参考价值。



最新实战教程,让你了解Android自动化刷量、作弊与防作弊的那些事,案例:刷友盟统计、批量注册苹果帐号




之前一直忙着找工作,所有都没有时间更新这个系列了,不过其实也差不多要完成的了,后面的一些都是一些比较零散的东西了

好了,不多说,现在就进入我们的正题,今天我们就讲一下那个流量管理的功能,其实流量管理并不难,android里面已经有自己的api的了

但由于它里面有一些东西,我也弄不明白,所以今天这个只是一个简单的示例,大家回去之后想继续完善的话,就要自己花时间研究一下了

好,我们先来看一下是我们要实现的界面

               

我们要实现的界面就是这样的了,我们使用一个抽屉的控件


首先,我们先来建一个model类,用来存放我们要显示的信息

com.xiaobin.security.domain.TrafficInfo

package com.xiaobin.security.domain;

import android.graphics.drawable.Drawable;

public class TrafficInfo

	private String name;
	private Drawable icon;
	private int uid;
	
	public String getName()
	
		return name;
	
	public void setName(String name)
	
		this.name = name;
	
	public Drawable getIcon()
	
		return icon;
	
	public void setIcon(Drawable icon)
	
		this.icon = icon;
	
	public int getUid()
	
		return uid;
	
	public void setUid(int uid)
	
		this.uid = uid;
	



上面的那个uid就是我们的应用在android里面的uid啦,它从一装进手机里面开始,就不会变化的啦


写完model类之后,我们就先来写一下界面吧,我们这次,用到了一个控件,叫抽屉(SlidingDrawer),下面我把我们的布局文件粘出来

traffic_manager.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="40dip"
        android:background="@drawable/title_background"
        android:gravity="center_vertical|center_horizontal"
        android:orientation="horizontal" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/traffic_manager"
            android:textColor="@android:color/white"
            android:textSize="22sp" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/tv_traffic_2g_3g"
            android:layout_width="0dip"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:paddingLeft="8dip"
            android:text="@string/traffic" />

        <TextView
            android:id="@+id/tv_traffic_wifi"
            android:layout_width="0dip"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:paddingLeft="8dip"
            android:text="@string/traffic" />
    </LinearLayout>

    <SlidingDrawer
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:content="@+id/lv_traffic_content"
        android:handle="@+id/iv_traffic_handle"
        android:orientation="vertical" >

        <ImageView
            android:id="@id/iv_traffic_handle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:contentDescription="@string/hello_world"
            android:src="@drawable/handle" />

        <ListView
            android:id="@id/lv_traffic_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:cacheColorHint="@android:color/white" />
    </SlidingDrawer>

</LinearLayout>

在SlidingDrawer这个节点里面,大家要注意了,我们必须要给它指定一个handle和content的,不然,它是会报错的

好啦,节点写好之后,我们就可以写我们的逻辑啦

首先,我们就要先拿到我们总的流量啦

	private void setTotalTraffic()
	
		//拿到2G和3G的总共接收到的数据大小
		long total_2g_3g_received = TrafficStats.getMobileRxBytes();
		//拿到2G和3G的总共发送出去的数据大小
		long total_2g_3g_transmitted  = TrafficStats.getMobileTxBytes();
		//拿到2G和3G的总数据大小
		long total_2g_3g = total_2g_3g_received + total_2g_3g_transmitted;
		
		tv_traffic_2g_3g.setText("2G/3g 总流量:" + TextFormater.dataSizeFormat(total_2g_3g));
		
		//拿到总共接收到的数据大小
		long total_received = TrafficStats.getTotalRxBytes();
		//拿到总共发送的数据大小
		long total_transmitted = TrafficStats.getTotalTxBytes();
		//拿到总数据大小
		long total = total_received + total_transmitted;
		拿到wifi的总数据大小
		long total_wifi = total - total_2g_3g;
		
		tv_traffic_wifi.setText("wifi 总流量:" + TextFormater.dataSizeFormat(total_wifi));
	

其实Android有一个类就是用来获取这些流量的信息的,TrafficStats

就这样,我们就可以拿到了wifi和2g/3g的总流量的了


注意,这个流量是会随着你每一次关机,都会设置为0的,也就是说,当你关机一次之后,这个值就是变成0的啦,所有要做一个流量管理的,就要把以前的也记录下来,然后再进行统计了


好啦,拿到了,总的流量之后,我们就要来拿到对应的一个个应用的流量了

首先,我们会先拿到一个会首先流量信息的应用列表先的

	//拿到所有会产生流量的应用信息
	private void initResolveInfos()
	
		trafficInfos.clear();
		//拿到一个包管理器
		PackageManager packageManager = this.getPackageManager();
		Intent intent = new Intent();
		//android.intent.action.MAIN这个action代表的就是应用的入口
		intent.setAction("android.intent.action.MAIN");
		//android.intent.category.LAUNCHER代表的就是在桌面创建一个图标
		intent.addCategory("android.intent.category.LAUNCHER");
		//这个方法就是根据对应的条件,intent指定条件,然后查询出相应的activity
		//那么根据我们上面设置的intent,我们就可以知道,我们要查询的是应用的入口activity而且是桌面上有图标的activity
		//因为这样的应用,才会有可能产生流量的
		List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(intent, 0);
		
		for(ResolveInfo resolveInfo : resolveInfos)
		
			//得到应用的名字
			String name = resolveInfo.loadLabel(packageManager).toString();
			//得到应用的图标
			Drawable icon = resolveInfo.loadIcon(packageManager);
			//得到应用的包名
			String packageName = resolveInfo.activityInfo.packageName;
			int uid = 0;;
			try
			
				//得到应用的packageInfo对象
				PackageInfo packageInfo = packageManager.getPackageInfo(packageName, 0);
				//得到这个应用对应的uid
				uid = packageInfo.applicationInfo.uid;
				//根据uid得到这个应用的接收数据大小
				long received = TrafficStats.getUidRxBytes(uid);
				//根据uid得到这个应用的发送数据大小
				long transmitted = TrafficStats.getUidTxBytes(uid);
				//有些应用不会产生流量信息的,拿到的值就会是-1
				//不产生流量的,我们就不把它加入到list里面
				if(received == -1 && transmitted == -1)
				
					continue;
				
			
			catch (NameNotFoundException e)
			
				e.printStackTrace();
			
			TrafficInfo trafficInfo = new TrafficInfo();
			trafficInfo.setName(name);
			trafficInfo.setIcon(icon);
			trafficInfo.setUid(uid);
			trafficInfos.add(trafficInfo);
		
	

上面这个方法的注释已经很详细了,我就不多说啦,有什么不明白的,可以提出来


有了这个应用的列表之后,不用想的了,我们肯定会写一个adapter的了

	private class TrafficAdapter extends BaseAdapter
	

		@Override
		public int getCount()
		
			return trafficInfos.size();
		

		@Override
		public Object getItem(int position)
		
			return trafficInfos.get(position);
		

		@Override
		public long getItemId(int position)
		
			return position;
		

		@Override
		public View getView(int position, View convertView, ViewGroup parent)
		
			View view;
			ViewHolder holder;
			TrafficInfo info = trafficInfos.get(position);
			if(convertView == null)
			
				view = View.inflate(TrafficManagerActivity.this, R.layout.traffic_manager_item, null);
				holder = new ViewHolder();
				holder.iv_traffic_icon = (ImageView) view.findViewById(R.id.iv_traffic_icon);
				holder.tv_traffic_name = (TextView) view.findViewById(R.id.tv_traffic_name);
				holder.tv_traffic_received = (TextView) view.findViewById(R.id.tv_traffic_received);
				holder.tv_traffic_transmitted = (TextView) view.findViewById(R.id.tv_traffic_transmitted);
				view.setTag(holder);
			
			else
			
				view = convertView;
				holder = (ViewHolder) view.getTag();
			
			holder.iv_traffic_icon.setImageDrawable(info.getIcon());
			holder.tv_traffic_name.setText(info.getName());
			//根据uid得到这个应用的接收数据大小
			long received = TrafficStats.getUidRxBytes(info.getUid());
			//根据uid得到这个应用的发送数据大小
			long transmitted = TrafficStats.getUidTxBytes(info.getUid());
			holder.tv_traffic_received.setText(TextFormater.dataSizeFormat(received));
			holder.tv_traffic_transmitted.setText(TextFormater.dataSizeFormat(transmitted));
			return view;
		
		
	
	
	private class ViewHolder
	
		ImageView iv_traffic_icon;
		TextView tv_traffic_name;
		TextView tv_traffic_received;
		TextView tv_traffic_transmitted;
	

好啦,写到这里,我们的流量获取以及显示的操作,就基本上是完成的啦,但是还是有一点小问题要处理的,我们的流量是会变化的,但是我们这里根本就没有刷新机制,

所以,接下来,我们就用一个计时器来进行刷新的

	@Override
	protected void onStart()
	
		timer = new Timer();
		timerTask = new TimerTask()
		
			@Override
			public void run()
			
				Message msg = Message.obtain();
				handler.sendMessage(msg);
			
		;
		timer.schedule(timerTask, 1000, 3000);
		super.onStart();
	

	@Override
	protected void onStop()
	
		if(timer != null)
		
			timer.cancel();
			timer = null;
			timerTask = null;
		
		super.onStop();
	

我在onStart和onStop方法里面,进行了对一个计时器的初始化和取消,这样子,我们的流量列表就可以刷新的了,通过handler来刷新

	@SuppressLint("HandlerLeak")
	private Handler handler = new Handler()
	
		public void handleMessage(Message msg) 
		
			adapter.notifyDataSetChanged();
		
	;

好啦,这样子,流量管理的功能就读完的了,下面把完整的activity粘出来

com.xiaobin.security.ui.TrafficManagerActivity

package com.xiaobin.security.ui;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.net.TrafficStats;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import com.xiaobin.security.R;
import com.xiaobin.security.domain.TrafficInfo;
import com.xiaobin.security.utils.TextFormater;

public class TrafficManagerActivity extends Activity

	private TextView tv_traffic_2g_3g;
	private TextView tv_traffic_wifi;
	private ListView lv_traffic_content;
	private TrafficAdapter adapter;
	
	private List<TrafficInfo> trafficInfos;
	
	private Timer timer;
	private TimerTask timerTask;
	
	@SuppressLint("HandlerLeak")
	private Handler handler = new Handler()
	
		public void handleMessage(Message msg) 
		
			adapter.notifyDataSetChanged();
		
	;
	
	@Override
	protected void onCreate(Bundle savedInstanceState)
	
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.traffic_manager);
		
		tv_traffic_2g_3g = (TextView) findViewById(R.id.tv_traffic_2g_3g);
		tv_traffic_wifi = (TextView) findViewById(R.id.tv_traffic_wifi);
		setTotalTraffic();
		
		trafficInfos = new ArrayList<TrafficInfo>();
		initResolveInfos();
		
		lv_traffic_content = (ListView) findViewById(R.id.lv_traffic_content);
		adapter = new TrafficAdapter();
		lv_traffic_content.setAdapter(adapter);
	
	
	@Override
	protected void onStart()
	
		timer = new Timer();
		timerTask = new TimerTask()
		
			@Override
			public void run()
			
				Message msg = Message.obtain();
				handler.sendMessage(msg);
			
		;
		timer.schedule(timerTask, 1000, 3000);
		super.onStart();
	
	
	@Override
	protected void onStop()
	
		if(timer != null)
		
			timer.cancel();
			timer = null;
			timerTask = null;
		
		super.onStop();
	
	
	private void setTotalTraffic()
	
		//拿到2G和3G的总共接收到的数据大小
		long total_2g_3g_received = TrafficStats.getMobileRxBytes();
		//拿到2G和3G的总共发送出去的数据大小
		long total_2g_3g_transmitted  = TrafficStats.getMobileTxBytes();
		//拿到2G和3G的总数据大小
		long total_2g_3g = total_2g_3g_received + total_2g_3g_transmitted;
		
		tv_traffic_2g_3g.setText("2G/3g 总流量:" + TextFormater.dataSizeFormat(total_2g_3g));
		
		//拿到总共接收到的数据大小
		long total_received = TrafficStats.getTotalRxBytes();
		//拿到总共发送的数据大小
		long total_transmitted = TrafficStats.getTotalTxBytes();
		//拿到总数据大小
		long total = total_received + total_transmitted;
		拿到wifi的总数据大小
		long total_wifi = total - total_2g_3g;
		
		tv_traffic_wifi.setText("wifi 总流量:" + TextFormater.dataSizeFormat(total_wifi));
	
	
	//拿到所有会产生流量的应用信息
	private void initResolveInfos()
	
		trafficInfos.clear();
		//拿到一个包管理器
		PackageManager packageManager = this.getPackageManager();
		Intent intent = new Intent();
		//android.intent.action.MAIN这个action代表的就是应用的入口
		intent.setAction("android.intent.action.MAIN");
		//android.intent.category.LAUNCHER代表的就是在桌面创建一个图标
		intent.addCategory("android.intent.category.LAUNCHER");
		//这个方法就是根据对应的条件,intent指定条件,然后查询出相应的activity
		//那么根据我们上面设置的intent,我们就可以知道,我们要查询的是应用的入口activity而且是桌面上有图标的activity
		//因为这样的应用,才会有可能产生流量的
		List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(intent, 0);
		
		for(ResolveInfo resolveInfo : resolveInfos)
		
			//得到应用的名字
			String name = resolveInfo.loadLabel(packageManager).toString();
			//得到应用的图标
			Drawable icon = resolveInfo.loadIcon(packageManager);
			//得到应用的包名
			String packageName = resolveInfo.activityInfo.packageName;
			int uid = 0;;
			try
			
				//得到应用的packageInfo对象
				PackageInfo packageInfo = packageManager.getPackageInfo(packageName, 0);
				//得到这个应用对应的uid
				uid = packageInfo.applicationInfo.uid;
				//根据uid得到这个应用的接收数据大小
				long received = TrafficStats.getUidRxBytes(uid);
				//根据uid得到这个应用的发送数据大小
				long transmitted = TrafficStats.getUidTxBytes(uid);
				//有些应用不会产生流量信息的,拿到的值就会是-1
				//不产生流量的,我们就不把它加入到list里面
				if(received == -1 && transmitted == -1)
				
					continue;
				
			
			catch (NameNotFoundException e)
			
				e.printStackTrace();
			
			TrafficInfo trafficInfo = new TrafficInfo();
			trafficInfo.setName(name);
			trafficInfo.setIcon(icon);
			trafficInfo.setUid(uid);
			trafficInfos.add(trafficInfo);
		
	
	
	//============================================================================================
	
	private class TrafficAdapter extends BaseAdapter
	

		@Override
		public int getCount()
		
			return trafficInfos.size();
		

		@Override
		public Object getItem(int position)
		
			return trafficInfos.get(position);
		

		@Override
		public long getItemId(int position)
		
			return position;
		

		@Override
		public View getView(int position, View convertView, ViewGroup parent)
		
			View view;
			ViewHolder holder;
			TrafficInfo info = trafficInfos.get(position);
			if(convertView == null)
			
				view = View.inflate(TrafficManagerActivity.this, R.layout.traffic_manager_item, null);
				holder = new ViewHolder();
				holder.iv_traffic_icon = (ImageView) view.findViewById(R.id.iv_traffic_icon);
				holder.tv_traffic_name = (TextView) view.findViewById(R.id.tv_traffic_name);
				holder.tv_traffic_received = (TextView) view.findViewById(R.id.tv_traffic_received);
				holder.tv_traffic_transmitted = (TextView) view.findViewById(R.id.tv_traffic_transmitted);
				view.setTag(holder);
			
			else
			
				view = convertView;
				holder = (ViewHolder) view.getTag();
			
			holder.iv_traffic_icon.setImageDrawable(info.getIcon());
			holder.tv_traffic_name.setText(info.getName());
			//根据uid得到这个应用的接收数据大小
			long received = TrafficStats.getUidRxBytes(info.getUid());
			//根据uid得到这个应用的发送数据大小
			long transmitted = TrafficStats.getUidTxBytes(info.getUid());
			holder.tv_traffic_received.setText(TextFormater.dataSizeFormat(received));
			holder.tv_traffic_transmitted.setText(TextFormater.dataSizeFormat(transmitted));
			return view;
		
		
	
	
	private class ViewHolder
	
		ImageView iv_traffic_icon;
		TextView tv_traffic_name;
		TextView tv_traffic_received;
		TextView tv_traffic_transmitted;
	




好啦,今天就到这里,如果有什么不明白的,可以留言


注意,用模拟器来测试这个流量管理是会有点问题的,模拟器不支持一些功能的,所以最好用真机来测试


最后,和大家说一下

为了方便大家的交流,我创建了一个群,这样子大家有什么疑问也可以在群上交流

群号是298440981


今天源码下载



以上是关于Android项目实战--手机卫士34--流量管理的主要内容,如果未能解决你的问题,请参考以下文章

Android项目实战_手机安全卫士流量统计

Android 项目实战--手机卫士(实现splash)

Android项目实战_手机安全卫士系统加速

Android项目实战--手机卫士35--清除程序缓存

Android项目实战--手机卫士--结束

手机安全卫士——流量管理