首页 文章

连接Wifi时,CONNECTIVITY_ACTION意图收到两次

提问于
浏览
49

在我的应用程序中,我有 BroadcastReceiver ,它通过 <receiver> 标记作为组件启动,过滤 android.net.conn.CONNECTIVITY_CHANGE 意图 .

我的目标只是知道何时 Build 了Wifi连接,所以我在 onReceive() 所做的是:

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

它工作正常,但在 Build Wifi连接时,我似乎总是在大约一秒钟内得到两个相同的意图 . 我试图查看我可以从意图获得的任何信息, ConnectivityManagerWifiManager ,但我找不到任何可以区分两种意图的信息 .

查看日志,至少还有一个 BroadcastReceiver 也接收到两个相同的意图 .

它运行在搭载Android 2.2的HTC Desire上

任何想法为什么我似乎在Wifi连接时获得“重复”的意图或两者之间的差异可能是什么?

14 回答

  • 0

    找到一个特殊的网络连接案例,说没有互联网,但实际上有 . 事实证明 getActiveNetworkInfo 会在特定情况下返回 DISCONNECTED/BLOCKED ,当电池电量低且app刚刚切换时更换网络

    看看this post

  • 1

    检查来自intent的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
                         }
                     }
    
  • 3

    如果您只想接收一次,您可以通过变量简单地控制它 .

    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;
                        }
                    }
                }
    
  • 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

    经过大量的谷歌搜索和调试后,我相信这是确定Wifi连接或断开连接的正确方法 .

    BroadcastReceiver中的 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()== true)当Wifi连接时 - 这个问题中描述的问题 .

    • 当仅使用 WifiManager.NETWORK_STATE_CHANGED_ACTION 时,Wifi断开连接时没有广播意图,但两个意图包含不同的NetworkInfo实例,允许在连接Wifi时确定一个事件 .

    注意:我收到一个崩溃报告(NPE),其中 intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO) 返回null . 因此,即使它似乎极少发生,添加空检查也许是个好主意 .

    干杯,托斯滕

  • 0

    如果您正在收听 WifiManager.NETWORK_STATE_CHANGED_ACTION ,您将收到两次,因为 NetworkInfo 中有2种方法

    • isConnectedOrConnecting()

    • isConnected()

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

    干杯

  • 12

    更新了Torsten的代码,这样当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));
            }
        }
    }
    
  • 0

    如果您将活动注册为目标侦听器,那么您将收到两次相同的消息 . 具体来说,您需要选择是否要在包级别(XML)或编程级别上进行侦听 .

    如果您为广播接收器设置了一个类并附加了监听它并且您将一个intent过滤器附加到该活动,那么该消息将被复制两次 .

    我希望这能解决你的问题 .

  • 2

    我通过使用SharedPref with Time解决了两次调用问题 .

    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 milisec) . 因此,在IF中,第二次呼叫将停止,并且第一次呼叫将继续 .

  • 4

    如果在,我解决了

    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;
            }
        }
    
  • -2

    我通过使用NetworkInfo的intent额外解决了这个问题 . 在下面的示例中,如果wifi连接或移动,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;
    }
    
  • 59

    打开WIFI时,

    • 当MOBILE数据为ON时,发送两个广播:广播#1:MOBILE数据断开,广播#2:WIFI连接

    • 关闭MOBILE数据时,仅发送一个广播:广播#1:连接WIFI

    在上述两种条件下关闭WIFI时可以观察到类似的行为 .

    要区分这两者,请遵循以下#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");
                    }
                }
            }
    
  • 1

    这是在API 21及更高版本上注册连接更改的正确方法 . 以下代码可以放在基本活动中,这样您就可以期望应用程序中的每个屏幕(继承自此活动)获得这些回调 .

    首先,创建一个网络回调,监控连接变化 .

    @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,请务必制定如何处理Pre-Lollipop设备中的网络状态更改的计划 .

  • 2

    只听动作“android.net.conn.CONNECTIVITY_CHANGE” . 无论何时 Build 或销毁连接,都会广播它 .

    Build 连接后将播放“android.net.wifi.STATE_CHANGE” . 所以你得到两个触发器 .

    请享用!

相关问题