我正在开发一个用于检查互联网连接的android广播接收器。

问题是我的广播接收器被调用了两次。我希望它只在网络可用时被调用。如果它不可用,我不想被通知。

这是广播接收机

public class NetworkChangeReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(final Context context, final Intent intent) {
        final ConnectivityManager connMgr = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);

        final android.net.NetworkInfo wifi = connMgr
                .getNetworkInfo(ConnectivityManager.TYPE_WIFI);

        final android.net.NetworkInfo mobile = connMgr
                .getNetworkInfo(ConnectivityManager.TYPE_MOBILE);

        if (wifi.isAvailable() || mobile.isAvailable()) {
            // Do something

            Log.d("Network Available ", "Flag No 1");
        }
    }
}

这是manifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcastreceiverforinternetconnection"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <receiver android:name=".NetworkChangeReceiver" >
            <intent-filter>
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
                <action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

当前回答

警告:为android.net.conn.CONNECTIVITY_CHANGE声明一个broadcastreceiver对于目标为N或更高的应用程序是不建议使用的。一般来说,应用程序不应该依赖于这个广播,而是使用JobScheduler或GCMNetworkManager。

由于CONNECTIVITY_CHANGE已弃用,那么我们应该使用另一种方式来做相同的事情

接下来的NetworkConnectionLiveData将处理所有的OS Version,直到现在,如果目标SDK小于Build.VERSION_CODES。棒棒糖,那么只有我们可以使用broadcastReceiver

最好的部分是这个类使用LiveData,所以不需要注册任何接收器使用LiveData,它将处理所有的事情

class NetworkConnectionLiveData(val context: Context) : LiveData<Boolean>() {

    private var connectivityManager: ConnectivityManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager

    private lateinit var connectivityManagerCallback: ConnectivityManager.NetworkCallback

    override fun onActive() {
        super.onActive()
        updateConnection()
        when {
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.N -> connectivityManager.registerDefaultNetworkCallback(getConnectivityManagerCallback())
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> lollipopNetworkAvailableRequest()
            else -> {
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                    context.registerReceiver(networkReceiver, IntentFilter("android.net.conn.CONNECTIVITY_CHANGE"))
                }
            }
        }
    }

    override fun onInactive() {
        super.onInactive()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            connectivityManager.unregisterNetworkCallback(connectivityManagerCallback)
        } else {
            context.unregisterReceiver(networkReceiver)
        }
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private fun lollipopNetworkAvailableRequest() {
        val builder = NetworkRequest.Builder()
                .addTransportType(android.net.NetworkCapabilities.TRANSPORT_CELLULAR)
                .addTransportType(android.net.NetworkCapabilities.TRANSPORT_WIFI)
        connectivityManager.registerNetworkCallback(builder.build(), getConnectivityManagerCallback())
    }

    private fun getConnectivityManagerCallback(): ConnectivityManager.NetworkCallback {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

            connectivityManagerCallback = object : ConnectivityManager.NetworkCallback() {
                override fun onAvailable(network: Network?) {
                    postValue(true)
                }

                override fun onLost(network: Network?) {
                    postValue(false)
                }
            }
            return connectivityManagerCallback
        } else {
            throw IllegalAccessError("Should not happened")
        }
    }

    private val networkReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            updateConnection()
        }
    }

    private fun updateConnection() {
        val activeNetwork: NetworkInfo? = connectivityManager.activeNetworkInfo
        postValue(activeNetwork?.isConnected == true)
    }
} 

使用LiveData到任何类:

NetworkConnectionLiveData(context ?: return)
    .observe(viewLifecycleOwner, Observer { isConnected ->
        if (!isConnected) {
            // Internet Not Available
            return@Observer
        }
        // Internet Available
})

其他回答

我知道这个帖子已经很老了,而且已经有了完整的答案,但我觉得下面的帖子可能会帮助到一些人。

问题主体中的代码包含一个这里没有人解决的错误。 @Nikhil正在检查wifi/手机是否可用,而不是是否连接。

解决方法如下:

@Override
public void onReceive(final Context context, final Intent intent) {
    final ConnectivityManager connMgr = (ConnectivityManager) context
            .getSystemService(Context.CONNECTIVITY_SERVICE);

    final android.net.NetworkInfo wifi = connMgr
            .getNetworkInfo(ConnectivityManager.TYPE_WIFI);

    final android.net.NetworkInfo mobile = connMgr
            .getNetworkInfo(ConnectivityManager.TYPE_MOBILE);

    if (wifi.isConnected() || mobile.isConnected()) {
      // do stuff
    }
}
public class AsyncCheckInternet extends AsyncTask<String, Void, Boolean> {

public static final int TIME_OUT = 10 * 1000;

private OnCallBack listener;

public interface OnCallBack {

    public void onBack(Boolean value);
}

public AsyncCheckInternet(OnCallBack listener) {
    this.listener = listener;
}

@Override
protected void onPreExecute() {
}

@Override
protected Boolean doInBackground(String... params) {

    ConnectivityManager connectivityManager = (ConnectivityManager) General.context
            .getSystemService(Context.CONNECTIVITY_SERVICE);

    NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();

    if ((networkInfo != null && networkInfo.isConnected())
            && ((networkInfo.getType() == ConnectivityManager.TYPE_WIFI) || (networkInfo
                    .getType() == ConnectivityManager.TYPE_MOBILE))) {
        HttpURLConnection urlc;
        try {
            urlc = (HttpURLConnection) (new URL("http://www.google.com")
                    .openConnection());
            urlc.setConnectTimeout(TIME_OUT);
            urlc.connect();
            if (urlc.getResponseCode() == HttpURLConnection.HTTP_OK) {
                return true;
            } else {
                return false;
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
            return false;

        } catch (IOException e) {
            e.printStackTrace();
            return false;

        }
    } else {
        return false;
    }
}

@Override
protected void onPostExecute(Boolean result) {
    if (listener != null) {
        listener.onBack(result);
    }
}

}

到2022年,上述BroadcastReceiver方法都将失效。由于Android 7.0的限制,BroadcastReceiver方法将不再工作。检查互联网是否可用的最新和最简单的方法是使用以下代码。(Android 12测试)

val networkRequest = NetworkRequest.Builder()
        .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
        .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
        .build()

private val networkCallback = object : ConnectivityManager.NetworkCallback() {
    // network is available for use
    override fun onAvailable(network: Network) {
        super.onAvailable(network)
    }

    // Network capabilities have changed for the network
    override fun onCapabilitiesChanged(
            network: Network,
            networkCapabilities: NetworkCapabilities
    ) {
        super.onCapabilitiesChanged(network, networkCapabilities)
        val unmetered = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
    }

    // lost network connection
    override fun onLost(network: Network) {
        super.onLost(network)
    }
}

val connectivityManager = getSystemService(ConnectivityManager::class.java) as ConnectivityManager
connectivityManager.requestNetwork(networkRequest, networkCallback

将这段代码放在一个函数中,并在activity/fragment的onCreate()中调用它。在onAvailable()和onLost()函数中,每当互联网连接或断开连接时,您都会收到通知。与此同时,您可以使用liveData或任何您喜欢的方式在其他活动/片段中广播这些更新。 官方文档链接:https://developer.android.com/training/monitoring-device-state/connectivity-status-type

使用https://github.com/JobGetabu/DroidNet更容易

 @Override
    public void onInternetConnectivityChanged(boolean isConnected) {

        if (isConnected) {
            //do Stuff with internet
            netIsOn();
        } else {
            //no internet
            netIsOff();
        }
    }

    private void netIsOn(){...}

    private void netIsOff(){...}

这里有一种适合活动、片段或上下文的方法。它也会自动注销,如果你做的活动/片段(在onDestroy),如果你希望:

abstract class ConnectionBroadcastReceiver : BroadcastReceiver() {
    companion object {
        @JvmStatic
        fun registerWithoutAutoUnregister(context: Context, connectionBroadcastReceiver: ConnectionBroadcastReceiver) {
            context.registerReceiver(connectionBroadcastReceiver, IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))
        }

        @JvmStatic
        fun registerToFragmentAndAutoUnregister(context: Context, fragment: Fragment, connectionBroadcastReceiver: ConnectionBroadcastReceiver) {
            val applicationContext = context.applicationContext
            registerWithoutAutoUnregister(applicationContext, connectionBroadcastReceiver)
            fragment.lifecycle.addObserver(object : LifecycleObserver {
                @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
                fun onDestroy() {
                    applicationContext.unregisterReceiver(connectionBroadcastReceiver)
                }
            })
        }

        @JvmStatic
        fun registerToActivityAndAutoUnregister(activity: AppCompatActivity, connectionBroadcastReceiver: ConnectionBroadcastReceiver) {
            registerWithoutAutoUnregister(activity, connectionBroadcastReceiver)
            activity.lifecycle.addObserver(object : LifecycleObserver {
                @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
                fun onDestroy() {
                    activity.unregisterReceiver(connectionBroadcastReceiver)
                }
            })
        }

        @JvmStatic
        fun hasInternetConnection(context: Context): Boolean {
            val info = (context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).activeNetworkInfo
            return !(info == null || !info.isConnectedOrConnecting)
        }
    }

    override fun onReceive(context: Context, intent: Intent) {
        val hasConnection = !intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)
//        Log.d("AppLog", "conenctivity changed. hasConnection? $hasConnection")
        onConnectionChanged(hasConnection)
    }

    abstract fun onConnectionChanged(hasConnection: Boolean)
}

在片段中的用法:

    ConnectionBroadcastReceiver.registerToFragmentAndAutoUnregister(activity!!, this, object : ConnectionBroadcastReceiver() {
        override fun onConnectionChanged(hasConnection: Boolean) {
            // Log.d("AppLog", "onConnectionChanged:" + hasConnection)
        }
    })