請改參考
2023.03.19
感覺這篇筆記的做法多做了一些不必要的事情,但這也是學習的歷程,所以還是保留......
ConnectivityManager
NetworkInfo
Process
ping(8) - Linux man page
或可透過 是否成功獲取網頁內容 做為判斷網際網路連線的依據,參考
【Kotlin】以 OkHttp3 偵測是否有網際網路連線能力
首先授予 app 權限
AndroidManifest.xml:
activity_main.xml:
一般偵測區域網路連線,只要 ConnectivityManager + NetworkInfo 即可,如下:
但這不足以得知是否連上網際網路,例如:
一般我們家裡都有無線路由器,當我們把路由器上 WAN 的線拔掉,家裡對外就斷線了,但 Android 設備仍可以連上路由器,則
info.isAvailable() 是 true
info.isConnected() 是 true
這樣無法判斷是否連上網際網路。
Android 的底層是 Linux,一般來說,在 /system/bin/ 下有 ping 這個程式,如果沒有,可能是被該 Android 裝置的製造商移除了;因為是 Linux 的指令,指令參數請參考 Linux;我們可以藉 ping 來偵測網路是否通。
如果網際網路是通的,則 strPing 字串會含有如下的內容:
64 bytes from 168.95.1.1: icmp_seq=1 ttl=249 time=4.67 ms
64 bytes from 168.95.1.1: icmp_seq=2 ttl=249 time=6.55 ms
64 bytes from 168.95.1.1: icmp_seq=3 ttl=249 time=4.29 ms
64 bytes from 168.95.1.1: icmp_seq=4 ttl=249 time=5.27 ms
提醒您:老人家這篇筆記偷懶,並未考慮 app 執行的程式合理性及最佳化,ping 這種耗時的指令,建議您還是放在 Thread 或 AsyncTask 執行比較好。
相關筆記 ----
【Android】AsyncTask - Thread 外的另一選擇
AndroidManifest.xml:
... ... <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> ... ...
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.oldgrayduck.ping.MainActivity"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="PING" android:id="@+id/btnPing" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:nestedScrollingEnabled="true" android:onClick="onbtnPingClicked"/> </RelativeLayout>
一般偵測區域網路連線,只要 ConnectivityManager + NetworkInfo 即可,如下:
ConnectivityManager connManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo info = connManager.getActiveNetworkInfo(); // 可透過下列指令取得進一步的連線資訊 info.getTypeName(); // 目前以何種方式連線 (WIFI, MOBILE) info.getState(); // 目前連線狀態 (DISCONNECTED, CONNECTING, CONNECTED) info.isAvailable(); // 目前網路是否可使用 (true/false) info.isConnected(); // 網路是否已連接 (true/false) info.isConnectedOrConnecting(); // 網路是否已連接 或 連線中 (true/false) info.isFailover(); // 網路目前是否有問題 (true/false) info.isRoaming(); // 網路目前是否在漫遊中 (true/false)
但這不足以得知是否連上網際網路,例如:
一般我們家裡都有無線路由器,當我們把路由器上 WAN 的線拔掉,家裡對外就斷線了,但 Android 設備仍可以連上路由器,則
info.isAvailable() 是 true
info.isConnected() 是 true
這樣無法判斷是否連上網際網路。
Android 的底層是 Linux,一般來說,在 /system/bin/ 下有 ping 這個程式,如果沒有,可能是被該 Android 裝置的製造商移除了;因為是 Linux 的指令,指令參數請參考 Linux;我們可以藉 ping 來偵測網路是否通。
... ... public void onbtnPingClicked(View v) { if (isConnected()) Toast.makeText(this, "網路已連線", Toast.LENGTH_LONG).show(); else Toast.makeText(this, "斷線中", Toast.LENGTH_LONG).show(); } private boolean isConnected() { boolean result = false; ConnectivityManager connManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo info = connManager.getActiveNetworkInfo(); if (info==null || !info.isConnected()) { Log.d(TAG, "網路 不通"); result = false; } else { if(info.isConnected()) Log.d(TAG, "info connected"); else Log.d(TAG, "info disconnected"); if (info.isAvailable()) { try { Log.d(TAG, "info is available"); // 不像 Windows 的 ping 預設執行 4 次 // Linux 的 ping 預設是一直執行的,所以一定要下參數指定次數 // 不然會造成您的 app 無回應 // 試著 ping 168.95.1.1, 4 次, 參數 -c 4 Process process = new ProcessBuilder().command("/system/bin/ping","-c 4","168.95.1.1") .redirectErrorStream(true) .start(); try { String strPing = ""; InputStream in = process.getInputStream(); OutputStream out = process.getOutputStream(); InputStreamReader reader = new InputStreamReader(in, "utf-8"); int i; Log.d(TAG, "read instream"); while ((i = in.read()) != -1) { strPing = strPing + (char) i; } out.close(); in.close(); reader.close(); Log.d(TAG, "strPing ==== "+strPing); if(strPing.indexOf("ttl")>=0) { Log.d(TAG, "strPing 字串中有 ttl"); result = true; } else { Log.d(TAG, "Ping 沒回應"); result = false; } } catch(Exception e) { result = false; } finally { // 記得要釋放掉 process process.destroy(); } } catch (Exception e) { Log.d(TAG, "Exception--> " + e.getMessage()); result = false; } } else { Log.d(TAG, "網路不可用"); result = false; } } return result; } ... ...
如果網際網路是通的,則 strPing 字串會含有如下的內容:
64 bytes from 168.95.1.1: icmp_seq=1 ttl=249 time=4.67 ms
64 bytes from 168.95.1.1: icmp_seq=2 ttl=249 time=6.55 ms
64 bytes from 168.95.1.1: icmp_seq=3 ttl=249 time=4.29 ms
64 bytes from 168.95.1.1: icmp_seq=4 ttl=249 time=5.27 ms
提醒您:老人家這篇筆記偷懶,並未考慮 app 執行的程式合理性及最佳化,ping 這種耗時的指令,建議您還是放在 Thread 或 AsyncTask 執行比較好。
相關筆記 ----
【Android】AsyncTask - Thread 外的另一選擇
沒有留言:
張貼留言