之前一直忙着找工作,所有都没有时间更新这个系列了,不过其实也差不多要完成的了,后面的一些都是一些比较零散的东西了
好了,不多说,现在就进入我们的正题,今天我们就讲一下那个流量管理的功能,其实流量管理并不难,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; } }
写完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>
好啦,节点写好之后,我们就可以写我们的逻辑啦
首先,我们就要先拿到我们总的流量啦
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)); }
就这样,我们就可以拿到了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(); }
@SuppressLint("HandlerLeak") private Handler handler = new Handler() { public void handleMessage(Message msg) { adapter.notifyDataSetChanged(); } };
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
今天源码下载