广播接收器以检测网络是否已连接

26

我正在尝试获取用户连接到网络的时刻,于是我想到了使用BroadcastReceiver的方法... 我想要做的事情是,当用户连接到一个网络时,知道这个网络是否连接到互联网。

另外一个主要的问题是,要知道WiFi是否需要Browse Log in,例如:查看Handling Network Sign-On文档。

我到目前为止尝试了什么?

我已将我的BroadcastReceiver更改为:

if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
NetworkInfo networkInfo = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if (networkInfo != null && networkInfo.getDetailedState() == NetworkInfo.DetailedState.CONNECTED) {
    Log.d("Network", "Internet YAY");
} else if (networkInfo != null && networkInfo.getDetailedState() == NetworkInfo.DetailedState.DISCONNECTED) {
    if (isNetworkOnline()) {
        Log.d(TAG, String.valueOf(tikis));
        NetTask TeInternet = new NetTask();
        TeInternet.execute("https://www.google.com");


    }
}

问题在于当我尝试连接没有 Internet ConnectionWiFi 时,输入是这样的:

D/Network﹕ Internet YAY
D/Network﹕ Internet YAY
D/Network﹕ Internet YAY
D/RequiresLoginBroadcast﹕ 1 //this occurs sometimes

根据网络登录处理文档,我已将内部类更改为以下内容:

doInBackground()方法:

protected Boolean doInBackground(String...params) {
boolean internetAccessExists = false;
String urlToBeAccessed = params[0];
final int TIMEOUT_VALUE_IN_MILLISECONDS = 15000;
URL url;
HttpURLConnection urlConnection = null;
try {
    url = new URL(urlToBeAccessed);
    urlConnection = (HttpURLConnection) url.openConnection();
    //set the respective timeouts for the connection
    urlConnection.setConnectTimeout(TIMEOUT_VALUE_IN_MILLISECONDS);
    urlConnection.setReadTimeout(TIMEOUT_VALUE_IN_MILLISECONDS);
    //the redirect check is valid only after the response headers have been received
    //this is triggered by the getInputStream() method
    InputStream in = new BufferedInputStream(urlConnection.getInputStream());
    if (!url.getHost().equals(urlConnection.getURL().getHost())) {
        internetAccessExists = true;
    }
}
//any sort of exception is considered as a redirect.
//more specific exceptions such as SocketTimeOutException and IOException can be handled as well
catch (Exception e) {
    Log.d(TAG, e.toString());
} finally {
    Log.d(TAG, "Finally");
    urlConnection.disconnect();
}
return internetAccessExists;

我到目前为止寻找的是什么?

  1. 如何检测 Android 中 WIFI 连接已建立?
  2. Android WIFI 如何检测特定的 WIFI 连接是否可用
  3. BroadcastReceiver 不起作用(检测 WIFI 是否已连接)

还有更多...但可悲的是我没有找到适合我的正确答案。

简短总结

我正在尝试获取用户连接到网络的确切事件,然后找到一种好方法来检测是否可以进行 Google Ping 或检查是否有 Internet 连接(仅限 WIFI,不允许 3G 连接),因为我目前正在使用的代码有时会出现故障...

我认为这是了解是否存在Internet 连接的好方法,因为我想知道的是是否需要浏览器登录以检测 WIFI。

我们快要完成了......但我不明白为什么会进入 BroadcastReceiver 4 次甚至 5 次...有时候会说有 Internet 连接,但实际上没有...


它会检查网络是否已连接吗? - Skizo-ozᴉʞS ツ
http://www.codeproject.com/Articles/818734/Article-Android-Connectivity - ecle
你需要 wifi 连接还是 互联网 连接? - Darpan
@Skizo:今晚会看一下这个……请提醒我 :) - Yash Sampat
如果你需要什么,只要让我知道,我会解释你想要的东西,如果你不理解的话:) 谢谢 - Skizo-ozᴉʞS ツ
显示剩余16条评论
6个回答

23

这就是我目前正在使用的代码,它完美地运行着。当网络连接成功(不仅是打开,而是真正连接到互联网上)时,我会收到通知。
它也适用于任何类型的数据连接,但可以轻松修改为只接受WiFi、3G、4G等。

代码:

public class NetworkReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
            NetworkInfo networkInfo = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
            if (networkInfo != null && networkInfo.getDetailedState() == NetworkInfo.DetailedState.CONNECTED) {
                Log.d("Network", "Internet YAY");
            } else if (networkInfo != null && networkInfo.getDetailedState() == NetworkInfo.DetailedState.DISCONNECTED) {
                Log.d("Network", "No internet :(");
            }
        }
    }
}

清单:

<receiver
    android:name=".receivers.NetworkReceiver">
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    </intent-filter>
</receiver>

1
我的代码可以检测用户连接/断开任何类型的网络。 - Moonbloom
那么 Log.d("Network", "No internet :("); 的意思是无法连接到特定的网络? - Skizo-ozᴉʞS ツ
不,这意味着用户已断开与互联网的连接。 - Moonbloom
所以 (networkInfo != null && networkInfo.getDetailedState() == NetworkInfo.DetailedState.CONNECTED) 它并没有说当用户连接到网络时,它表示拥有互联网连接?... 这很奇怪。 - Skizo-ozᴉʞS ツ
8
.EXTRA_NETWORK_INFO已经过时了!!该死 - filthy_wizard
显示剩余2条评论

10
public abstract class NetworkReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
    if (null != intent) {
        State wifiState = null;  
        State mobileState = null;  
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);  
        wifiState = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState();  
        mobileState = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState();  
        if (wifiState != null && mobileState != null  
                && State.CONNECTED != wifiState  
                && State.CONNECTED == mobileState) {  
            // phone network connect success
            gNetwork();
        } else if (wifiState != null && mobileState != null  
                && State.CONNECTED != wifiState  
                && State.CONNECTED != mobileState) {  
            // no network
            noNetwork();
        } else if (wifiState != null && State.CONNECTED == wifiState) {  
            // wift connect success
            WIFINetwork();
        }
    }
}

}

清单集

 <receiver android:name=".receiver.AssistantReceiver" >
        <intent-filter>
            <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
        </intent-filter>
    </receiver>

你能否解释一下你的代码吗?我并没有要求3G。 - Skizo-ozᴉʞS ツ

4
在这份文档中,你可以找到所有需要的内容:确定和监控连接状态。同时,也可以查看Connectivity.java这个类。
简单来说,步骤如下:
1. 拦截CONNECTIVITY_CHANGE广播。
2. 在onReceive()方法中,检查网络是否连接,并确定是Wifi还是GPRS。
这应该很容易实现,而且不会出现任何问题。但有些情况下,比如某些HTC和三星设备修改了核心系统,可能会出现不同的行为。

3

NetworkChangeReceiver.java

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;

public class NetworkChangeReceiver extends BroadcastReceiver {

    private NetworkChangeCallback callback;

    public NetworkChangeReceiver(NetworkChangeCallback callback) {
        this.callback = callback;
    }                                               

    @Override
    public void onReceive(Context context, Intent intent) {
        boolean status = isNetworkAvailable(context);
        showLog("" + status);
        if (callback != null) {
            callback.onNetworkChanged(status);
        }
    }

    private boolean isNetworkAvailable(Context context) {
        try {
            ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo activeNetworkInfo = cm.getActiveNetworkInfo();
            return (activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting());
        } catch (NullPointerException e) {
            showLog(e.getLocalizedMessage());
            return false;
        }
    }

    private void showLog(String message) {
        Log.e("NetworkChangeReceiver", "" + message);
    }
}

MainActivity.java

public class MainActivity extends AppCompatActivity implements NetworkChangeCallback { 

    private NetworkChangeReceiver networkChangeReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        networkChangeReceiver = new NetworkChangeReceiver(this);
    }   

    @Override
    protected void onPause() {
        super.onPause();
        if (networkChangeReceiver != null) {
            unregisterReceiver(networkChangeReceiver);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        registerReceiver(networkChangeReceiver, intentFilter);
    }

    @Override
    public void onNetworkChanged(boolean status) {
        Log.e("MainActivity","Status: " + status);
    }
}

NetworkChangeCallback.java

public interface NetworkChangeCallback {
    void onNetworkChanged(boolean status);
}

AndroidManifest.xml

    <receiver android:name=".NetworkChangeReceiver">
        <intent-filter>
            <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
        </intent-filter>
    </receiver>

这只能检测用户从WiFi切换到数据网络,对吗?它不会检查实际的互联网连接。我的意思是,你可以连接到WiFi,但需要登录,它会像连接一样触发吗? - Skizo-ozᴉʞS ツ

2
我尝试了以下方法,它有效。虽然还没有完全测试,但我用类似的方法来接收电池状态。这种方式可以减少代码量并完成任务。
private BroadcastReceiver networkReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
            NetworkInfo networkInfo = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
            if (networkInfo != null && networkInfo.getDetailedState() == NetworkInfo.DetailedState.CONNECTED) {
                Log.d(LOG_TAG, "We have internet connection. Good to go.");
            } else if (networkInfo != null && networkInfo.getDetailedState() == NetworkInfo.DetailedState.DISCONNECTED) {
                Log.d(LOG_TAG, "We have lost internet connection");
            }
        }
    }
};

@Override
protected void onResume() {
    super.onResume();
    IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
    registerReceiver(networkReceiver, intentFilter);
}

@Override
protected void onPause() {
    super.onPause();
    if (networkReceiver != null)
        unregisterReceiver(networkReceiver);
}

0

我知道这有点晚了,但对于未来的读者,新的建议方法似乎是使用 WorkManager。它是 Android X 的一部分,并支持 API 级别 14 及更高版本,使检测和在连接更改时运行代码变得简单。

val constraints = Constraints.Builder()
    .setRequiredNetworkType(NetworkType.CONNECTED)
    .build()

val myWorkRequest =
    OneTimeWorkRequestBuilder<MyWorker>()
        .setConstraints(constraints)
        .build()

WorkManager.getInstance(MyApplication.context).enqueue(myWorkRequest)

当检测到连接时将执行的类:

class MyWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
    override fun doWork(): Result {
        doThis()
        return Result.success()
    }

    private fun doThis() {
        Log.d("ASDF", "::onReceive")
    }
}

附加资源:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接