我正在开发一个用于检查互联网连接的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>

当前回答

CONNECTIVITY_ACTION文档:

针对Android 7.0 (API级别24)及以上的应用程序,如果它们在manifest中声明了广播接收器,则不会接收此广播。如果应用程序向context . registerreceiver()注册了BroadcastReceiver,并且该context仍然有效,那么应用程序仍然会接收广播。

其他回答

检查网络状态:

private void checkInternetConnection() {

    if (br == null) {

        br = new BroadcastReceiver() {

            @Override
            public void onReceive(Context context, Intent intent) {

                Bundle extras = intent.getExtras();

                NetworkInfo info = (NetworkInfo) extras
                        .getParcelable("networkInfo");

                State state = info.getState();
                Log.d("TEST Internet", info.toString() + " "
                        + state.toString());

                if (state == State.CONNECTED) {
                      Toast.makeText(getApplicationContext(), "Internet connection is on", Toast.LENGTH_LONG).show();

                } else {
                       Toast.makeText(getApplicationContext(), "Internet connection is Off", Toast.LENGTH_LONG).show();
                }

            }
        };

        final IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        registerReceiver((BroadcastReceiver) br, intentFilter);
    }
}

记得在onDestroy中注销服务。

干杯! !

对于想动态注册广播的人:

BroadcastReceiver mWifiReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (checkWifiConnect()) {
            Log.d(TAG, "wifi has connected");
            // TODO
        }
    }
};

private void registerWifiReceiver() {
    IntentFilter filter = new IntentFilter();
    filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
    filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
    filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
    mContext.registerReceiver(mWifiReceiver, filter);
}

private void unregisterWifiReceiver() {
    mContext.unregisterReceiver(mWifiReceiver);
}

private boolean checkWifiConnect() {
    ConnectivityManager manager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = manager.getActiveNetworkInfo();
    if (networkInfo != null
            && networkInfo.getType() == ConnectivityManager.TYPE_WIFI
            && networkInfo.isConnected()) {
        return true;
    }
    return false;
}

警告:为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
})

回答第一个问题:您的广播接收器被调用了两次,因为

您已经添加了两个<intent-filter>

网络连接的改变: <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> WiFi状态变化: <action android:name="android.net.wifi.WIFI_STATE_CHANGED" />

就用一个: <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />。

它将只响应一个操作而不是两个。更多信息请参见这里。

回答你的第二个问题(如果可以上网,你想让对方只打一次电话):

你的代码是完美的;只有在互联网可用时才通知。

更新

如果你只是想检查手机是否与互联网相连,你可以使用这种方法来检查你的连接。

public boolean isOnline(Context context) {

    ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo netInfo = cm.getActiveNetworkInfo();
    //should check null because in airplane mode it will be null
    return (netInfo != null && netInfo.isConnected());
}

清单:

<receiver android:name=".your.namepackage.here.ConnectivityReceiver">
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
    </intent-filter>
</receiver>

接收方的类:

public class ConnectivityReceiver extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();
        switch (action) {
            case ConnectivityManager.CONNECTIVITY_ACTION:
                DebugUtils.logDebug("BROADCAST", "network change");
                if(NetworkUtils.isConnect()){
                    //do action here
                }
            break;
        }
    }
}

和类utils,如example:

public class NetworkUtils {

    public static boolean isConnect() {
        ConnectivityManager connectivityManager = (ConnectivityManager) Application.getInstance().getSystemService(Context.CONNECTIVITY_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            Network[] netArray = connectivityManager.getAllNetworks();
            NetworkInfo netInfo;
            for (Network net : netArray) {
                netInfo = connectivityManager.getNetworkInfo(net);
                if ((netInfo.getTypeName().equalsIgnoreCase("WIFI") || netInfo.getTypeName().equalsIgnoreCase("MOBILE")) && netInfo.isConnected() && netInfo.isAvailable()) {
                    //if (netInfo.getState().equals(NetworkInfo.State.CONNECTED)) {
                    Log.d("Network", "NETWORKNAME: " + netInfo.getTypeName());
                    return true;
                }
            }
        } else {
            if (connectivityManager != null) {
                @SuppressWarnings("deprecation")
                NetworkInfo[] netInfoArray = connectivityManager.getAllNetworkInfo();
                if (netInfoArray != null) {
                    for (NetworkInfo netInfo : netInfoArray) {
                        if ((netInfo.getTypeName().equalsIgnoreCase("WIFI") || netInfo.getTypeName().equalsIgnoreCase("MOBILE")) && netInfo.isConnected() && netInfo.isAvailable()) {
                            //if (netInfo.getState() == NetworkInfo.State.CONNECTED) {
                            Log.d("Network", "NETWORKNAME: " + netInfo.getTypeName());
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }
}