android广播接收器OnReceive()延迟导致错误

时间:2014-08-09 04:45:45

标签: java android

我的广播接收器监听WiFi ssid更改,如果ssid发生更改,则返回布尔值WifiChanged true。我在另一个活动中检查此布尔值,该活动根据返回的值更改列表,无论是真还是假。默认情况下布尔值为false。

我故意改变wifi,它应该触发广播接收器将布尔值返回到true并相应地设置列表,但实际发生的是我的列表基于布尔值更改为false,因为广播接收器需要一段时间才能返回价值。在下面的日志中,您可以看到布尔值为false,并且在0.58秒后大约ssid发生变化。到那时为时已晚

08-08 16:43:54.487: D/PlayerManager(20733): Did Wi-Fi Changed: false
   |
   |
   |
08-08 16:43:55.047: V/ConnectionChangeReceiver(20733): onReceive(Context context, Intent intent)
08-08 16:43:55.077: D/ConnectionChangeReceiver(20733): ssid changed from s_ssid="Walter_Meth_Lab" to newSsid="Kings_Landing"

这是我的OnReceive()

public class ConnectionChangeReceiver extends BroadcastReceiver {
private static final String TAG = "ConnectionChangeReceiver";
private static String s_ssid = null;
private static String s_ipAddress = null;
private static String mNetworkType;
private static ConnectionChangeReceiver sInstance;

private ConnectionChangeListener mConnectionChangeListener;
private boolean mHasWifiChanged;

public static ConnectionChangeReceiver getInstance() {
    Log.v(TAG, "getInstance()");
    synchronized (ConnectionChangeReceiver.class) {
        if (sInstance == null) {
            sInstance = new ConnectionChangeReceiver();
        }
    }
    return sInstance;
}

public boolean WifiChanged() {
    return mHasWifiChanged;
}


public void setConnectionChangeListener(final ConnectionChangeListener listener) {
    this.mConnectionChangeListener = listener;
}

@Override
public void onReceive(final Context context, final Intent intent) {
Log.v(TAG, "onReceive(Context context, Intent intent)");

mHasWifiChanged = false;
String newSsid = null;

String action = intent.getAction();
if ((action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) || (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION))
        || (action.equals("android.net.conn.CONNECTIVITY_CHANGE"))) {
    NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
    if (networkInfo != null) {
        if (networkInfo.getTypeName().equals("WIFI")) {
            WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
            if (wm != null) {
                WifiInfo connectionInfo = wm.getConnectionInfo();
                if (connectionInfo != null) {
                    newSsid = connectionInfo.getSSID();
                    if ((newSsid != null) && (s_ssid != null) && (newSsid.compareTo(s_ssid) != 0)) {
                        Log.d(TAG, "ssid changed from s_ssid=" + s_ssid + " to newSsid=" + newSsid);
                        mHasWifiChanged = true;
                    }
                }
            }
        }
    }
}

s_ssid = newSsid;

这是我使用布尔值

的另一个活动
boolean WifiChanged = ConnectionChangeReceiver.getInstance().WifiChanged();
        Log.d(TAG, "Did Wi-Fi Changed:" + WifiChanged);
        if (WifiChanged) {
            //Do Something

        }

如果更改了Wi-Fi ssid,则列表应根据WifiChanged更改为true,但WifiChanged将始终更改为false,因为ChangeReceiver()未按时返回true并且使用默认false。

2 个答案:

答案 0 :(得分:5)

有很多方法可以完成这项工作。

我更喜欢使用LocalBroadcastManager

这是如何工作的:让ConnectionChangeReceiver 传递 - ,当它可用时,而不是让活动要求提供信息。完成ConnectionChangeReceiver处理收到的intent后,会发出local广播。如果你的活动是活着的并且正在倾听,它会对此作出反应。

// Snippet from your `ConnectionChangeReceiver # onReceive(...)` method
if (connectionInfo != null) {
    newSsid = connectionInfo.getSSID();
    if ((newSsid != null) && (s_ssid != null) && (newSsid.compareTo(s_ssid) != 0)) {
        Log.d(TAG, "ssid changed from s_ssid=" + s_ssid + " to newSsid=" + newSsid);
        mHasWifiChanged = true;

        // We can send a local broadcast now
        // Note that the String `"com.my.app.wifi.WIFI_RELATED_CHANGE"` can be 
        // customized to your preference
        Intent localIntent = new Intent("com.my.app.wifi.WIFI_RELATED_CHANGE");

        // Including this extra is redundant here since `mHasWifiChanged` will
        // always be true at this point. I am including it for example sake.
        // Again, notice that the key `"com.my.app.wifi.WIFI_HAS_CHANGED"` can
        // be customized
        localIntent.putExtra("com.my.app.wifi.WIFI_HAS_CHANGED", mHasWifiChanged);

        // Broadcasts the Intent to receivers in this app
        LocalBroadcastManager.getInstance(context).sendBroadcast(localIntent);
    }
}

在活动方面:在您的活动中创建BroadcastReceiver并将其设置为侦听操作"com.my.app.wifi.WIFI_RELATED_CHANGE"。此字符串值必须与从ConnectionChangeReceiver # onReceive(...)发送广播时使用的值相同:

// Declared as a class member in your Activity
BroadcastReceiver wifiRelatedChangeListener = new BroadcastReceiver() {

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

        String action = intent.getAction();
        if (action.equals("com.my.app.wifi.WIFI_RELATED_CHANGE")) {
            // In your current setup, `mHasWifiChanged` will always be true
            // Act on it
        }
    }
};

您应该将BroadcastReceiver声明为类成员。这将允许您适当地注册和取消注册BroadcastReceiver:在onResume()中注册并在onPause()中取消注册。

onResume()您的活动中,注册此接收器以倾听行动com.my.app.wifi.WIFI_RELATED_CHANGE

@Override
public void onResume() {
    super.onResume();

    // Activity has come to foreground. Register to listen for changes to wifi state.

    // Create an IntentFilter with action `com.my.app.wifi.WIFI_RELATED_CHANGE`
    IntentFilter intentFilter = new IntentFilter("com.my.app.wifi.WIFI_RELATED_CHANGE");

    // Register your broadcastreceiver to receive broadcasts 
    // with action `com.my.app.wifi.WIFI_RELATED_CHANGE`
    LocalBroadcastManager.getInstance(this)
                         .registerReceiver(wifiRelatedChangeListener, intentFilter);
}

取消注册onPause()中的接收者:

@Override
public void onPause() {
    super.onPause();

    // Activity is going to background. No need to listen anymore
    LocalBroadcastManager.getInstance(this).unregisterReceiver(wifiRelatedChangeListener);
}

请注意,您可以在许多活动中声明wifiRelatedChangeListener之类的接收器。广播从ConnectionChangeReceiver # onReceive(...)发送一次。无论那个前景/收听的活动是什么,都会收到这个广播并对其采取行动。

  

到那时为时已晚

此问题不会出现在上面讨论的解决方案中。

答案 1 :(得分:2)

你的方法不正确。您的广播接收器应向您的活动发送消息,然后您的活动应使用“onNewIntent”方法检查WiFi状态。然后,如果你在你的接收器中设置一个静态变量(你可能不应该这样做),你可以检查它,但最好只是发送你的Activity一个带有WiFi状态的布尔“额外”。

问题是您的UI线程比后台线程快得多。因此,如果活动正在响应接收者也在响应的事件,那么Android很可能会优先考虑活动在后台线程上的处理。