請改參考
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 外的另一選擇
沒有留言:
張貼留言