TrafficStats類實現Android監聽網速
一、網路狀態
Android市場的逐漸降溫及形成穩定,其實說明了Android的發展走向穩重成熟的階段。
除卻最開始的功能實現,到如今的使用者體驗至上,Android研發面臨的挑戰卻從未冷卻。基於大多數APP均是以APP為資料展示框架,實現客戶與伺服器資料互動,網路扮演了十分重要的角色。
網路狀態,除了WiFi,資料,網路不可用等,還有網路條件不好等情形。存有標誌網路速度的則能較好地標示當前網路情形。
以下則實現監聽網速,展示當前網速條件。藉由給客戶更好的使用者體驗。
二、實現監聽網速
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(int * uid) //獲取某個網路UID的傳送位元組數 */
建立浮動視窗,用於展示網速狀態;應用程式後臺執行,浮動視窗依舊顯示,則使用Service展示浮動視窗;在Activity中開啟Service。
網速監聽主體功能實現,TrafficBean.java:
Service中建立浮動視窗,展示網速狀態,ManagerService.java:package com.future.netobserverdemo.bean; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.net.TrafficStats; import android.os.Handler; import android.os.Message; import android.util.Log; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.io.Serializable; import java.math.BigDecimal; import java.util.Timer; import java.util.TimerTask; /** * 功能:流量Bean屬性資訊 * 作者:vision * 時間:2016/10/19 */ public class TrafficBean implements Serializable { /** * 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(int * uid) //獲取某個網路UID的傳送位元組數 */ /** * 不支援狀態【標識變數】 */ private static final int UNSUPPORT = -1; /** * 列印資訊標誌 */ private static final String TAG = "TrafficBean"; /** * 當前物件例項 */ private static TrafficBean instance; /** * 當前應用的uid */ static int UUID; /** * 上一次記錄網路位元組流 */ private long preRxBytes = 0; /** * */ private Timer mTimer = null; /** * 上下文物件 */ private Context context; /** * 訊息處理器 */ private Handler handler; /** * 更新頻率 */ private final int UPDATE_FREQUENCY = 1; private int times = 1; /** * 構造方法 * * @param context * @param handler * @param uid */ public TrafficBean(Context context, Handler handler, int uid) { this.context = context; this.handler = handler; this.UUID = uid; } public TrafficBean(Context context, Handler handler) { this.context = context; this.handler = handler; } /** * 獲取例項物件 * * @param context * @param handler * @return */ public static TrafficBean getInstance(Context context, Handler handler) { if (instance == null) { instance = new TrafficBean(context, handler); } return instance; } /** * 獲取總流量 * * @return */ public long getTrafficInfo() { long recTraffic = UNSUPPORT;//下載流量 long sendTraffic = UNSUPPORT;//上傳流量 recTraffic = getRecTraffic(); sendTraffic = getSendTraffic(); if (recTraffic == UNSUPPORT || sendTraffic == UNSUPPORT) { return UNSUPPORT; } else { return recTraffic + sendTraffic; } } /** * 獲取上傳流量 * * @return */ private long getSendTraffic() { long sendTraffic = UNSUPPORT; sendTraffic = TrafficStats.getUidTxBytes(UUID); if (sendTraffic == UNSUPPORT) { return UNSUPPORT; } RandomAccessFile rafSend = null; String sndPath = "/proc/uid_stat/" + UUID + "/tcp_snd"; try { rafSend = new RandomAccessFile(sndPath, "r"); sendTraffic = Long.parseLong(rafSend.readLine()); } catch (FileNotFoundException e) { Log.e(TAG, "FileNotFoundException: " + e.getMessage()); sendTraffic = UNSUPPORT; } catch (IOException e) { Log.e(TAG, "IOException: " + e.getMessage()); e.printStackTrace(); } finally { try { if (rafSend != null) rafSend.close(); } catch (IOException e) { Log.w(TAG, "Close RandomAccessFile exception: " + e.getMessage()); } } return sendTraffic; } /** * 獲取下載流量 * 某個應用的網路流量資料儲存在系統的 * /proc/uid_stat/$UID/tcp_rcv | tcp_snd檔案中 * * @return */ private long getRecTraffic() { long recTraffic = UNSUPPORT; recTraffic = TrafficStats.getUidRxBytes(UUID); if (recTraffic == UNSUPPORT) { return UNSUPPORT; } Log.i(TAG, recTraffic + " ---1"); //訪問資料檔案 RandomAccessFile rafRec = null; String rcvPath = "/proc/uid_stat/" + UUID + "/tcp_rcv"; try { rafRec = new RandomAccessFile(rcvPath, "r"); recTraffic = Long.parseLong(rafRec.readLine()); // 讀取流量統計 } catch (FileNotFoundException e) { Log.e(TAG, "FileNotFoundException: " + e.getMessage()); recTraffic = UNSUPPORT; } catch (IOException e) { Log.e(TAG, "IOException: " + e.getMessage()); e.printStackTrace(); } finally { try { if (rafRec != null) rafRec.close(); } catch (IOException e) { Log.w(TAG, "Close RandomAccessFile exception: " + e.getMessage()); } } Log.i("test", recTraffic + "--2"); return recTraffic; } /** * 獲取當前下載流量總和 * * @return */ public static long getNetworkRxBytes() { return TrafficStats.getTotalRxBytes(); } /** * 獲取當前上傳流量總和 * * @return */ public static long getNetworkTxBytes() { return TrafficStats.getTotalTxBytes(); } /** * 獲取當前網速 * * @return */ 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() { @Override public void run() { if (times == UPDATE_FREQUENCY) { Message msg = new Message(); msg.what = 1; //msg.arg1 = getNetSpeed(); msg.obj = getNetSpeed(); handler.sendMessage(msg); times = 1; } else { times++; } } }, 1000, 1000); } } /** * 停止網速監聽計算 */ public void stopCalculateNetSpeed() { if (mTimer != null) { mTimer.cancel(); mTimer = null; } } /** * 獲取當前應用uid * * @return */ public int getUid() { try { PackageManager pm = context.getPackageManager(); //修改 ApplicationInfo ai = pm.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA); return ai.uid; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } return -1; } }
public class ManagerService extends Service {
private static final String TAG = "ManagerService";
/**
* 浮動窗口布局
*/
private LinearLayout floatLL;
public WindowManager.LayoutParams params;
/**
* 浮動串口布局引數
*/
public WindowManager windowManager;
public TextView floatTV;
private ServiceBinder binder = new ServiceBinder();
@Override
public void onCreate() {
super.onCreate();
createFloatView();
}
/**
* 建立浮動窗口布局
*/
private void createFloatView() {
params = new WindowManager.LayoutParams();
windowManager = (WindowManager) getApplication().getSystemService(getApplication().WINDOW_SERVICE);
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;// 設定window
// type為TYPE_SYSTEM_ALERT
params.format = PixelFormat.RGBA_8888;// 設定圖片格式,效果為背景透明
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;// 設定浮動視窗不可聚焦(實現操作除浮動視窗外的其他可見視窗的操作)
params.gravity = Gravity.LEFT | Gravity.TOP;// 預設位置:左上角
params.width = WidgetUtils.dpToPx(getApplicationContext(), 65);
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.x = (WidgetUtils.getScreenWidth(getApplicationContext()) - params.width) / 2;// 設定x、y初始值,相對於gravity
params.y = 10;
// 獲取浮動視窗檢視所在佈局
LayoutInflater inflater = LayoutInflater.from(getApplication());
floatLL = (LinearLayout) inflater.inflate(R.layout.float_layout, null);
windowManager.addView(floatLL, params);// 新增mFloatLayout
floatTV = (TextView) floatLL.findViewById(R.id.move_desc);
floatTV.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
// 設定監聽浮動視窗的觸控移動
floatTV.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// getRawX是觸控位置相對於螢幕的座標,getX是相對於按鈕的座標
params.x = (int) event.getRawX() - floatTV.getMeasuredWidth() / 2;
Log.i(TAG, "RawX" + event.getRawX());
Log.i(TAG, "X" + event.getX());
params.y = (int) event.getRawY() - floatTV.getMeasuredHeight() / 2 - 25;// 減25為狀態列的高度
Log.i(TAG, "RawY" + event.getRawY());
Log.i(TAG, "Y" + event.getY());
windowManager.updateViewLayout(floatLL, params);// 重新整理
return false; // 此處必須返回false,否則OnClickListener獲取不到監聽
}
});
floatTV.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
Toast.makeText(getApplicationContext(), "浮動視窗被點選了!", Toast.LENGTH_SHORT).show();
}
});
}
public void setSpeed(String str) {
floatTV.setText(str);
}
@Override
public void onDestroy() {
super.onDestroy();
if (floatLL != null && windowManager != null) {
windowManager.removeView(floatLL);// 移除懸浮視窗
}
startService(new Intent(this, ManagerService.class));
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY_COMPATIBILITY;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
}
public class ServiceBinder extends Binder {
public ManagerService getService() {
return ManagerService.this;
}
}
}
Activity中繫結service,實現功能:
public class MainActivity extends AppCompatActivity {
/**
* Activity管理器
*/
private ActivityManager activityManager;
/**
* 浮動圖示
*/
private TextView moveDesc;
/**
* 訊息處理器
*/
private Handler handler;
/**
* 流量資訊物件
*/
private TrafficBean trafficBean;
/**
* 服務
*/
private ManagerService service;
/**
* 標記資訊
*/
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
moveDesc = (TextView) findViewById(R.id.tv);
try {
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 1) {
moveDesc.setText(msg.obj + "kb/s");
if (service != null) {
service.setSpeed(msg.obj + "kb/s");
}
}
super.handleMessage(msg);
}
};
trafficBean = new TrafficBean(this, handler, 12580);
trafficBean.startCalculateNetSpeed();
} catch (Exception e) {
e.printStackTrace();
}
Log.d(TAG, "總流量 = " + trafficBean.getTrafficInfo());
Intent intent = new Intent(MainActivity.this, ManagerService.class);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder iBinder) {
service = ((ManagerService.ServiceBinder) iBinder).getService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
service = null;
}
};
@Override
protected void onDestroy() {
super.onDestroy();
trafficBean.stopCalculateNetSpeed();
unbindService(conn);
}
}
展示效果:
三、細節注意
1,使用與建立對應,onCreate()中繫結,onDestory()中解綁;
2,清單檔案配置許可權及服務和廣播接收者。
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<service android:name="com.future.netobserverdemo.service.ManagerService" />
<receiver android:name="com.future.netobserverdemo.service.ManagerReceiver">
<intent-filter android:priority="2147483647"> <!-- 優先順序加最高 -->
<!-- 系統啟動完成後會呼叫 -->
<action android:name="android.intent.action.BOOT_COMPLETED" />
<!-- 解鎖完成後會呼叫 -->
<action android:name="android.intent.action.USER_PRESENT" />
<!-- 監聽情景切換 -->
<action android:name="android.media.RINGER_MODE_CHANGED" />
</intent-filter>
</receiver>
原始碼
上班族如何安排時間才能每天都早起,讀書,跑步,冥想?
1,早起毀一天 -- 任何依靠自制力的事情,最後都會失敗; 2,心態陷阱 -- 貪多,為了讀書而讀書,為了瀏覽而瀏覽,促進心理焦慮; ---- 通過某種行為,達到某種目的----- 目的 3,目標--手段--執行意圖 --- 同樣的效果,更節省意志力 ---- 愛好他,比強壓自己學習更好,好太多 4,為了讓自己幸福 -- 幫助自己去完成更美好的事情,同時讚美自己 ---- 自我增強存在價值相關推薦
TrafficStats類實現Android監聽網速
一、網路狀態 Android市場的逐漸降溫及形成穩定,其實說明了Android的發展走向穩重成熟的階段。 除卻最開始的功能實現,到如今的使用者體驗至上,Android研發面臨的挑戰卻從未冷卻。基於大多數APP均是以APP為資料展示框架,實現客戶與
Android 自定義Dialog類,並在Activity中實現按鈕監聽。
實際開發中,經常會用到Dialog,比如退出時候會彈出是否退出,或者還有一些編輯框也會用Dialog實現,效果圖如下: 開發中遇到的問題無非在於如果在Activity中監聽這個Dialog中實現的按鈕,Dialog類如下,在MyDialog這個類中實現了一個LeaveMyDialogLi
Android UI事件處理——實現事件監聽介面的4種方法
前段時間看到一個同學的android課程有這樣一個作業要求:....... 非內部類實現onClickListener監聽介面的方式監聽按鈕單擊事件 ....... 感覺蠻奇怪,一般對於UI事件的處理
android 監聽上下左右鍵的功能實現
鍵盤中的上下左右與返回鍵。可以直接監聽,不需要在xml或者其他地方註冊。 主要方法是: public boolean onKeyDown(int kCode,KeyEvent kEvent) { switch(kCode) { case KeyEvent.KEYCODE
Android實現流量統計和網速監控懸浮窗
很多安全衛士類軟體都實現了網速監測功能,也算是一個比較實用的功能。Android下,TrafficStats類實現了對流量的統計。 static long getMobileRxBytes()//獲取通過Mobile連線收到的位元組總數,但不包含WiFi static
android實現事件監聽的2種常用方式
1.使用內部匿名類: private Button button; @Override protected void onCreate(Bundle savedInstanceState) { sup
Javascript----input事件實現動態監聽textarea內容變化
span oninput idt ava ntb ima property onchange pre 1、代碼 <!DOCTYPE html> <html> <head> <title>textarea輸入文字監聽
實現滾輪監聽,導航欄置頂的效果。
nav idt ack doc color win ID cti col 為了項目的制作,需要一個導航欄置頂的效果,遇到了點難度,但還是克服了,通過比較導航和滾動條的高度實現置頂效果 <div id="daohang" style="width:100%;heig
Android 監聽APP進入後臺或切換到前臺方案對比
api 5.0 等等 推薦一個 情況 lis 需要 推出 soc 在我們開發的過程中,經常會遇到需要我們判斷app進入後臺,或者切換到前臺的情況。比如我們想判斷app切換到前臺時,顯示一個解鎖界面,要求用戶輸入解鎖密碼才能繼續進行操作;我們想判斷app切換到後臺,記錄一下l
Android 監聽屏幕喚醒和關閉的廣播
n) 應用 dma 今天 new and androidm receive err 今天希望應用程序的服務運行時,可以監聽到屏幕的喚醒。繼續百度學習法,連同監聽閉幕關閉也一同學習了。 此種情況需要動態註冊系統廣播。在AndroidManifest.xml中靜態註冊
Android 監聽屏幕鎖屏&用戶解鎖
clas 開始 ets adc spa contex screen context scree 在做視頻播放器的時候,遇到一個問題,在用戶播放視頻然後鎖屏之後,視頻播放器仍然在繼續播放,遇到類似手機系統狀態改變的問題的時候,首先想到了廣播,下面做個總結: public
JS實現鍵盤監聽(包括組合鍵)
nbsp html gist 收集 and ros register col next 依然使用案例驅動~案例是學習的最好實踐! <html> <head> <meta
Android 監聽文件夾
external 分享 tex xtend 目錄 nac 觸發 改變 @override 在一次Android和pc端的通訊過程中,我們放棄了adb forward來實現socket通訊。而是使用adb push文件,我監聽文件夾... 都學習一下很有必要 本篇簡單Andr
Android監聽藍芽耳機的按鍵事件 藍芽無法響應KeyEvent監聽不到
需求:藍芽耳機的按鍵事件,暫停/播放 音訊/視訊 ,無法響應藍芽KeyEvent的事件 此問題是由於中的藍芽KeyEvent監聽不到導致的,可以通過以下方法監聽藍芽按鍵事件 private MediaSession mSession; &
Python和Redis實現訂單監聽,語音播報
1.MP3格式的音訊檔案 如 audio.mp3 2.建立虛禮環境 建立虛擬環境 安裝:pip install virtualenv 建立:virtualenv venv 啟用:venv\Scripts\activate 3.安裝所需擴充套件 pip install playso
android 監聽元件構建完成
//有時候要獲取一個元件的位置總是返回0,原因是元件還沒繪製完成,該方法就是等待元件構建完成回撥 mView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
android監聽虛擬按鍵的顯示與隱藏
虛擬按鍵在華為手機中大量存在,而虛擬按鍵的存在無疑增加了螢幕適配的難度,往往許多時候我們的介面需要根據虛擬按鍵的顯示與否(虛擬按鍵的顯示隱藏是使用者可以動態調整的)來調整介面的ui顯示,但android系統本身(似乎)並沒有提供此類介面(PS:反正我沒找到類似介面),經過研究得到一個可用的方式。 a
Android 監聽手機按下Home鍵
系統本身有這個廣播,只需要監聽這個廣播就可以了! private BroadcastReceiver mHomeKeyEventReceiver = new BroadcastReceiver() { String SYSTEM_REASON = "reaso
Android獲取當前網速質量——分四個等級
在開發中,有時候常常需要根據使用者當前的網速來做一些操作,比如圖片的載入,當網速非常好的時候,比如連線的是wifi,我們就會下載高解析度的圖片,反之,當用戶使用的是2g網時,我們則給他下載低解析度的小圖,從而節省使用者流量。 而Facebook其實已經給我們提供了這麼一個庫,詳見netw
Android監聽Home鍵、鎖屏、解屏(落雨敏詳細講解)附原始碼
前言:最近做視訊播放,發現當在播放時點選電源鍵進行鎖屏,視訊繼續播放問題,於是通過廣播進行監聽。廣播監聽可以用於很多地方,在此落雨敏詳細講解Home鍵、鎖屏、解屏的事件處理。先講解思路,然後在一步一步實現,下面會貼出所有程式碼。 &nbs