CONNECTIVITY_ACTION意图两次接收无线上网的连接时

问题描述 投票:49回答:14

在我的应用我有一个是通过BroadcastReceiver标签推出的一种成分,过滤<receiver>主意都能android.net.conn.CONNECTIVITY_CHANGE

我的目标很简单,就是知道什么时候建立WiFi连接,所以我在做什么在onReceive()是这样的:

NetworkInfo networkInfo = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if(networkInfo.getType() == ConnectivityManager.TYPE_WIFI && networkInfo.isConnected()) {
    // Wifi is connected
}

它工作正常,但我似乎总是约一秒钟之内获得两个相同的意图是建立WiFi连接时。我想看看任何信息,我可以从意图,ConnectivityManagerWifiManager得到,但我无法找到任何区别这两种意图。

查看日志,存在还接收两个相同的目的确定至少一个其它BroadcastReceiver

它是在HTC Desire的运行了Android 2.2

任何想法,为什么我似乎得到“复制”的意图时,无线上网连接或者两者之间的差异可能是什么?

android android-wifi android-broadcastreceiver
14个回答
62
投票

注:对于最近的,跟上时代的回答,请参见下面的this one

很多使用Google和调试之后,我相信这是确定无线上网已经连接或断开的正确方法。

在广播接收器的onReceive()方法:

public void onReceive(final Context context, final Intent intent) {

if(intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
    NetworkInfo networkInfo =
        intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
    if(networkInfo.isConnected()) {
        // Wifi is connected
        Log.d("Inetify", "Wifi is connected: " + String.valueOf(networkInfo));
    }
} else if(intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
    NetworkInfo networkInfo =
        intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
    if(networkInfo.getType() == ConnectivityManager.TYPE_WIFI &&
        ! networkInfo.isConnected()) {
        // Wifi is disconnected
        Log.d("Inetify", "Wifi is disconnected: " + String.valueOf(networkInfo));
    }
}
}

连同在AndroidManifest.xml以下接收机元件

<receiver android:name="ConnectivityActionReceiver"
    android:enabled="true" android:label="ConnectivityActionReceiver">
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
        <action android:name="android.net.wifi.STATE_CHANGE"/>
    </intent-filter>
</receiver>

一些解释:

  • 如果只考虑ConnectivityManager.CONNECTIVITY_ACTION,我总是包含相同的NetworkInfo情况下,两个目的(这两个的getType()== TYPE_WIFI和isConnected()==真)当无线上网连接 - 在这个问题上所描述的问题。
  • 当仅使用WifiManager.NETWORK_STATE_CHANGED_ACTION,但是没有任何意图广播时无线上网的断开,但含有不同的NetworkInfo情况下,允许确定一个事件无线上网连接时两个目的。

注:我收到一个单一的崩溃报告(NPE),其中intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO)返回null。所以,即使它似乎是极为罕见的情况发生,它可能是添加一个空检查是一个好主意。

干杯,托斯滕


0
投票

我处理的方式,是通过简单地节约了网络的状态,然后比较,看看是否有一个变化。

public class ConnectivityChangedReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        boolean previouslyConnected = MyApp.getInstance().isNetworkPreviouslyConnected();
        boolean currentlyConnected = MyApp.getInstance().isNetworkConnected();

        if (previouslyConnected != currentlyConnected) {
            // do something and reset
            MyApp.getInstance().resetNetworkPreviouslyConnected();
        }
    }

}

如果这是你采取的方法,它在你的片段或活动的onResume恢复是很重要的,所以,它保持当前值:

@Override
public void onResume() {
    super.onResume();
    MyApp.getInstance().resetNetworkPreviouslyConnected();
}

我这样做,我BaseFragment,所有片段的父母在我的应用程序。


0
投票

从意向检查NETWORKTYPE和比较activeNetworkInfo.getType()

                 Bundle bundle = intent.getExtras();
                 ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
                 NetworkInfo ni = manager.getActiveNetworkInfo();

                 if(ni != null && ni.getState() == NetworkInfo.State.CONNECTED) {
                     if(bundle.getInt("networkType") == ni.getType()) {
                         // active network intent
                     }
                 }

0
投票

发现网络连接说没有互联网,但居然还有一种特殊情况。原来getActiveNetworkInfo总是会把你返回DISCONNECTED /受阻时,而电池电量低,只是交换应用网络发生变化的具体案例

退房this post


0
投票

当开启WiFi,

  1. 随着移动数据ON,两次广播被发送:广播#1:移动数据断开,和广播#2:WIFI连接
  2. 随着移动数据OFF,只有一个广播被发送:广播#1:WIFI连接

可以在上述两个条件下转动WIFI OFF可以观察到类似的行为。

为了区分两者,请按#2及以下#3:

        @Override
        public void onReceive(Context context, Intent intent) {
            Log.d(TAG, "*** Action: " + intent.getParcelableExtra("networkInfo"));

            NetworkInfo netInfo = intent.getParcelableExtra("networkInfo");

            if(intent.getAction().equalsIgnoreCase("android.net.conn.CONNECTIVITY_CHANGE")) {
                ConnectivityManager connectivityManager
                        = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
                NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
                if (activeNetInfo != null) {
                    if (netInfo.getType() == ConnectivityManager.TYPE_WIFI) {
                        if (netInfo.getState().name().contains("DISCONNECTED")
                                && activeNetInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
                            Log.d(TAG, "WIFI disconnect created this broadcast. MOBILE data ON."); // #1
                        } else if (netInfo.getState().name().contains("CONNECTED")
                                && activeNetInfo.getType() == ConnectivityManager.TYPE_WIFI) {
                            Log.d(TAG, "WIFI connect created this broadcast."); // #2
                        }
                    } else if (netInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
                        if (netInfo.getState().name().contains("DISCONNECTED")
                                && activeNetInfo.getType() == ConnectivityManager.TYPE_WIFI) {
                            Log.d(TAG, "MOBILE data disconnect created this broadcast. WIFI ON."); // #3
                        } else if (netInfo.getState().name().contains("CONNECTED")
                                && activeNetInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
                            Log.d(TAG, "MOBILE data connect created this broadcast."); // #4
                        }
                    }
                } else {
                    Log.d(TAG, "No network available");
                }
            }
        }

-2
投票

只听行动“android.net.conn.CONNECTIVITY_CHANGE”。每当建立或销毁连接它的播出。

“android.net.wifi.STATE_CHANGE”,当连接建立,将播放。所以,你得到两个触发器。

请享用!


12
投票

如果你在WifiManager.NETWORK_STATE_CHANGED_ACTION听,因为有2种方法在NetworkInfo你会两次收到此

  • isConnectedOrConnecting()
  • isConnected()

第一次isConnectedOrConnecting()返回trueisConnected() false 第二次isConnectedOrConnecting()isConnected()返回true

干杯


4
投票

更新托斯滕的代码,这样,当WIFI断开连接,只有一个适当的广播起作用时。

二手NetworkInfo.getDetailedState()== DetailedState.DISCONNECTED的检查。

public void onReceive(final Context context, final Intent intent) {
    if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
        NetworkInfo networkInfo = intent
            .getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
        if (networkInfo.isConnected()) {
            // Wifi is connected
            Log.d("Inetify","Wifi is connected: " + String.valueOf(networkInfo));
        }
    } else if (intent.getAction().equals(
        ConnectivityManager.CONNECTIVITY_ACTION)) {
        NetworkInfo networkInfo = intent
            .getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
        if (networkInfo.getDetailedState() == DetailedState.DISCONNECTED) {
            // Wifi is disconnected
            Log.d("Inetify","Wifi is disconnected: "+String.valueOf(networkInfo));
        }
    }
}

3
投票

如果你注册的活动为目的听众,那么你将收到相同的消息两次。具体来说,您需要选择是否要监听的包级别(XML)或程序化水平。

如果你设置了一个类的广播接收器和附加听它,你附加一个意图过滤器的活动,则该消息将被复制两次。

我希望这能解决您的问题。


3
投票

这是对21 API和更高的连接更改注册的正确方法。下面的代码可以放在一个基地活动,这样你可以期待在您的应用程序的每个屏幕(从这个活动继承)来获取这些回调。

首先,创建一个网络回调将监测连接变化。

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private val networkCallback: ConnectivityManager.NetworkCallback = object : ConnectivityManager.NetworkCallback() {

    // Implement the callback methods that are relevant to the actions you want to take.
    // I have implemented onAvailable for connecting and onLost for disconnecting.

    override fun onAvailable(network: Network?) {
        super.onAvailable(network)
    }

    override fun onLost(network: Network?) {
        super.onLost(network)
    }
}

然后,注册并在相关点注销该回调。

override fun onResume() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
        cm?.registerNetworkCallback(NetworkRequest.Builder().build(), networkCallback)
    }
}

并在适当的时候注销。

override fun onPause() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
        cm?.unregisterNetworkCallback(networkCallback)
    }
}

请注意,有是Build.VERSION_CODES.LOLLIPOP检查。此功能仅在棒棒糖及更高版本。一定要拥有怎样,如果你支持不到在你的应用程序API 21处理的预棒棒糖设备的网络状态变化的计划。


2
投票

我用SharedPref与及时解决两次电话。

private static final Long SYNCTIME = 800L;
private static final String LASTTIMESYNC = "DATE";
SharedPreferences sharedPreferences;
private static final String TAG = "Connection";

@Override
public void onReceive(Context context, Intent intent) {
     Log.d(TAG, "Network connectivity change");
     sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);

     final ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
     final NetworkInfo ni = connectivityManager.getActiveNetworkInfo();

        if (ni != null && ni.isConnected()) {   

            if(System.currentTimeMillis()-sharedPreferences.getLong(LASTTIMESYNC, 0)>=SYNCTIME)
            {
                sharedPreferences.edit().putLong(LASTTIMESYNC, System.currentTimeMillis()).commit();
                // Your code Here.
            }
     }
     else if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, Boolean.FALSE)) {
            Log.d(TAG, "There's no network connectivity");

    }
}

因为有1.call和2.call(约200毫秒为单位)之间的小延迟。所以如果与时间第二个电话会停止,只是第一个将持续。


2
投票

我解决了,如果在

onCreate()
       intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
       intentFilter.addAction("android.net.wifi.WIFI_STATE_CHANGED");
       intentFilter.addAction("android.net.wifi.STATE_CHANGE");
       ctx.registerReceiver(outgoingReceiver, intentFilter);

BroadcastReceiver
 public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
                NetworkInfo networkInfo =
                        intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
                if(networkInfo.getType() == ConnectivityManager.TYPE_WIFI &&
                        networkInfo.isConnected()) {
                    // Wifi is connected
                    Log.d("Inetify", "Wifi is connected: " + String.valueOf(networkInfo));

                    Log.e("intent action", intent.getAction());
                    if (isNetworkConnected(context)){
                        Log.e("WiFi", "is Connected. Saving...");
                        try {
                            saveFilesToServer("/" + ctx.getString(R.string.app_name).replaceAll(" ", "_") + "/Temp.txt");
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }}


 boolean isNetworkConnected(Context context) {
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo ni = cm.getActiveNetworkInfo();
        if (ni != null) {
            Log.e("NetworkInfo", "!=null");

            try{
                //For 3G check
                boolean is3g = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
                        .isConnectedOrConnecting();
                //For WiFi Check
                boolean isWifi = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
                        .isConnected();

                Log.e("isWifi", "isWifi="+isWifi);
                Log.e("is3g", "is3g="+is3g);
                if (!isWifi)
                {

                    return false;
                }
                else
                {
                    return true;
                }

            }catch (Exception er){
                return false;
            }

        } else{
            Log.e("NetworkInfo", "==null");
            return false;
        }
    }

1
投票

我使用的意图额外费用的NetworkInfo解决了这个问题。在下面的例子中,如果无线连接或移动的onReceive事件被触发一次。

if (intent.getAction().equalsIgnoreCase(ConnectivityManager.CONNECTIVITY_ACTION)) {

        NetworkInfo networkInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);

        boolean screenIsOn = false;
        // Prüfen ob Screen on ist
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            screenIsOn = pm.isInteractive();
        } else {
            screenIsOn = pm.isScreenOn();
        }

        if (Helper.isNetworkConnected(context)) {
            if (networkInfo.isConnected() && networkInfo.isAvailable()) {
                Log.v(logTAG + "onReceive", "connected");

                if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
                    Log.v(logTAG + "onReceive", "mobile connected");

                } else if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
                    Log.v(logTAG + "onReceive", "wifi connected");
                }
            }
        }

和我的助手:

    public static boolean isNetworkConnected(Context ctx) {
    ConnectivityManager cm = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo ni = cm.getActiveNetworkInfo();

    return ni != null;
}

1
投票

如果你只想一次接受它,你可以简单地通过变量控制它。

 if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
                NetworkInfo activeNetwork = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
                if (activeNetwork != null) { // connected to the internet
                    if (activeNetwork.isConnected() && !isUpdated) {
                        if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) {
                            // connected to wifi
                        } else if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) {
                            // connected to the mobile provider's data plan
                        }

                        isUpdated = true;
                    } else {
                        isUpdated = false;
                    }
                }
            }
© www.soinside.com 2019 - 2024. All rights reserved.