为什么 onReceive() 被多次调用?

why onReceive() is being called many times?

我不知道为什么当我连接或断开wifi时,下面贴出的wifi接收器代码中的相应回调被调用了很多次至少三次,并且

因此,如果我想根据当前 wifi 状态调用一个函数,该函数将被调用多次,我不希望出现这种情况,尤其是

当有wifi连接时应该调用的函数,我正在显示一个对话框,并且该回调将被多次调用,对话框将是 多次调用会造成重叠

请看下面的帖子logcat,这只是我得到的一个例子。

请问为什么wifi状态对应的回调会被多次调用,如何避免多次调用?

代码:

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

    tv_status = (TextView) findViewById(R.id.tv_status);

    this.registerReceiver(this.myWifiReceiver, new IntentFilter(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION));
}

private BroadcastReceiver myWifiReceiver = new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO Auto-generated method stub
        Log.d(TAG, "@onReceive()");

        mConnMgr = (ConnectivityManager)getSystemService(network_service);
        WifiManager wifiMgr = (WifiManager) context.getSystemService(WiFi_Service);

        switch (wifiMgr.getWifiState()) {
        case WifiManager.WIFI_STATE_ENABLED:
            Log.d(TAG, "wifi enabled");

            if (mConnMgr != null) {
                networkInfo = mConnMgr.getActiveNetworkInfo();
                if (networkInfo != null) {
                    switch(networkInfo.getType()) {
                    case ConnectivityManager.TYPE_WIFI: 
                        if (networkInfo.isConnected()) {
                            tv_status.setText("Connected");
                            Log.d(TAG, "Connected");
                        }else if (networkInfo.isConnectedOrConnecting()) {
                            tv_status.setText("Status: CONNECTED Or CONNECTING");
                            Log.d(TAG, "Status: CONNECTED Or CONNECTING");
                        }else if (networkInfo.isFailover()){
                            Log.d(TAG, "Status: FailOver");
                        }else if (networkInfo.isRoaming()) {
                            Log.d(TAG, "Status: Roaming");
                        }else if (networkInfo.isAvailable()) {
                            Log.d(TAG, "Status: Available");
                        } else {
                            Log.d(TAG, "Status: disconnected");
                        }
                        break;

                    }
                }else {
                    tv_status.setText("Status: No Default NetWork Connected");
                    Log.d(TAG, "Status: No Default NetWork Connected");
                }
            } else {
                tv_status.setText("Status:  ConnMgr is null");
                Log.d(TAG, "Status:  ConnMgr is null");
            }

            break;

LogCat:

03-04 15:31:31.031: D/MainActivity(16120): @onReceive()
03-04 15:31:31.031: D/MainActivity(16120): wifi enabled
03-04 15:31:31.032: D/MainActivity(16120): Status: No Default NetWork Connected
03-04 15:31:31.546: D/MainActivity(16120): @onReceive()
03-04 15:31:31.547: D/MainActivity(16120): wifi enabled
03-04 15:31:31.547: D/MainActivity(16120): Status: No Default NetWork Connected
03-04 15:31:31.617: D/MainActivity(16120): @onReceive()
03-04 15:31:31.618: D/MainActivity(16120): wifi enabled
03-04 15:31:31.620: D/MainActivity(16120): Status: No Default NetWork Connected
03-04 15:31:31.636: D/MainActivity(16120): @onReceive()
03-04 15:31:31.636: D/MainActivity(16120): wifi enabled
03-04 15:31:31.637: D/MainActivity(16120): Status: No Default NetWork Connected
03-04 15:32:28.661: D/MainActivity(16120): @onReceive()
03-04 15:32:28.663: D/MainActivity(16120): wifi enabled
03-04 15:32:28.666: D/MainActivity(16120): Status: No Default NetWork Connected
03-04 15:32:28.708: D/MainActivity(16120): @onReceive()
03-04 15:32:28.709: D/MainActivity(16120): wifi enabled
03-04 15:32:28.710: D/MainActivity(16120): Status: No Default NetWork Connected
03-04 15:32:28.722: D/MainActivity(16120): @onReceive()
03-04 15:32:28.722: D/MainActivity(16120): wifi enabled
03-04 15:32:28.722: D/MainActivity(16120): Status: No Default NetWork Connected

Update_1:

MySolution 使用计时器:

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

    tv_status = (TextView) findViewById(R.id.tv_status);
    IntentFilter intfil = new IntentFilter(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);

    this.registerReceiver(this.myWifiReceiver, intfil);
}

private BroadcastReceiver myWifiReceiver = new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO Auto-generated method stub
        Log.d(TAG, "@onReceive()");
        Timer t1 = new Timer();
        Timer t2 = new Timer();

        if (!locked) {
            if (scheduled1) {
                t1.cancel();
                t1.purge();
            }
            if (scheduled2) {
                t2.cancel();
                t2.purge();
            }

            WifiManager wifiMgr = (WifiManager) context.getSystemService(WiFi_Service);

            switch (wifiMgr.getWifiState()) {
            case WifiManager.WIFI_STATE_ENABLED:
                Log.d(TAG, "wifi enabled");
                locked = true;
                t1 = new Timer();
                t1.schedule(MQTTReceiverLockTimedTask, 4000);
                scheduled1 = true;
                module();
                break;

            case WifiManager.WIFI_STATE_DISABLED:
                Log.d(TAG, "wifi disabled");
                locked = true;
                t2 = new Timer();
                t2.schedule(MQTTReceiverLockTimedTask, 4000);
                scheduled2 = true;
                break;
            }
        }
    }
};

TimerTask MQTTReceiverLockTimedTask = new TimerTask() {

    @Override
    public void run() {
        // TODO Auto-generated method stub
        locked = false;
    }
};

protected void module() {
    // TODO Auto-generated method stub
    mConnMgr = (ConnectivityManager)getSystemService(network_service);

    if (mConnMgr != null) {
        networkInfo = mConnMgr.getActiveNetworkInfo();
        if (networkInfo != null) {
            switch(networkInfo.getType()) {
            case ConnectivityManager.TYPE_WIFI: 
                if (networkInfo.isConnected()) {
                    tv_status.setText("Connected");
                    Log.d(TAG, "Connected");
                }else if (networkInfo.isConnectedOrConnecting()) {
                    tv_status.setText("Status: CONNECTED Or CONNECTING");
                    Log.d(TAG, "Status: CONNECTED Or CONNECTING");
                }else if (networkInfo.isFailover()){
                    Log.d(TAG, "Status: FailOver");
                }else if (networkInfo.isRoaming()) {
                    Log.d(TAG, "Status: Roaming");
                }else if (networkInfo.isAvailable()) {
                    Log.d(TAG, "Status: Available");
                } else {
                    Log.d(TAG, "Status: disconnected");
                }
                break;

            }
        }else {
            tv_status.setText("Status: No Default NetWork Connected");
            Log.d(TAG, "Status: No Default NetWork Connected");
        }
    } else {
        tv_status.setText("Status:  ConnMgr is null");
        Log.d(TAG, "Status:  ConnMgr is null");
    }
}

将 WiFi 的当前状态保存在某个地方,管理器或其他东西,并且仅当 onReceive() 以不同于当前状态的状态调用时才执行您的代码。

假设您在 Activity.

中使用此代码

在你 activity 你会有一个 属性 叫做 currentWifiState ,一开始它等于 -100;例如

在你的接收器中,代码是这样的

if (wifiManager.getWifiState() == currentWifiState)
     return;

那么如果你被通知的状态与当前状态相同,你将什么都不做。

除非 Wifi 状态发生变化,否则您的代码将不会执行。

WifiManager documentation 开始 WifiManager.SUPPLICANT_STATE_CHANGED_ACTION:

Broadcast intent action indicating that the state of establishing a connection to an access point has changed.One extra provides the new SupplicantState.

您接到了很多 onReceive() 的电话,因为 SupplicantState 提供了有关建立连接状态的更详细信息。每次此状态发生变化时,都会广播一个新的意图。由于您只需要不太详细的信息,因此您似乎多次收到相同的广播。

至于如何避免这种情况:搜索另一个意图来收听,例如 ConnectivityManager.CONNECTIVITY_ACTION 如果它适合您的需要,或者尝试 Mahmoud Elmorabea 的解决方案 - 将当前 wifi 连接状态保存在私有字段中您的 Activity class,并在 onReceive() 上检查连接状态是否已更改。如果没有,请跳过其余代码。否则,运行 代码并更新您的状态。如果您使用此解决方案,请记住在 Activity 生命周期期间保存状态字段。