简体   繁体   English

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

[英]android broadcast receiver OnReceive() delay causing errors

My Broadcast Receiver listens for WiFi ssid change and if the ssid changes it return the boolean WifiChanged true.I check for this boolean in another activity which changes a list based on the value returned whether it was true or false.By default the boolean value is false. 我的广播接收器侦听WiFi的ssid更改,如果ssid更改,则返回布尔值WifiChanged true。我在另一个活动中检查此布尔值,该活动根据返回的值是true还是false更改列表。默认情况下,布尔值是假。

I intentionally change the wifi which should trigger the broadcast receiver to return the boolean value to true and set the list accordingly but what actually happens is that my list is changed based on the boolean value false as broadcast receiver takes a while to return the value. 我有意更改了wifi,它应该触发广播接收器将布尔值返回为true并相应地设置列表,但实际上发生的情况是我的列表基于布尔值false更改了,因为广播接收器需要一段时间才能返回该值。 In the log below you can see the boolean value is false and after 0.58 seconds approximately the ssid changes. 在下面的日志中,您可以看到布尔值是false,大约0.58秒后ssid会更改。 By that time its too late 到那时为时已晚

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"

Here is my OnReceive() 这是我的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;

This is the other activity where i use the boolean 这是我使用布尔值的另一个活动

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

        }

If the Wi-Fi ssid is changed, the list should change based the WifiChanged true but it always changes for WifiChanged false as ChangeReceiver() does not return true on time and the default false is used. 如果更改了Wi-Fi ssid,则列表应根据WifiChanged true进行更改,但对于WifiChanged false始终会更改,因为ChangeReceiver()不能及时返回true,并且使用默认false。

There are many ways to get this done. 有很多方法可以完成这项工作。

I prefer using the LocalBroadcastManager . 我更喜欢使用LocalBroadcastManager

How this will work: instead of having the activity ask for information, let ConnectionChangeReceiver deliver it - as and when it is available . 它将如何工作:让ConnectionChangeReceiver在活动可用时 发送它,而不是让活动询问信息。 Once ConnectionChangeReceiver is done with processing the received intent , it sends out a local broadcast. 一旦ConnectionChangeReceiver完成处理接收到的intent ,它就会发出local广播。 If your activity is alive and listening, it reacts to this. 如果您的活动是活跃的并且正在倾听,它会对此做出反应。

// 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);
    }
}

On the activity side: create a BroadcastReceiver in your activity and set it to listen for action "com.my.app.wifi.WIFI_RELATED_CHANGE" . 在活动方面:在您的活动中创建一个BroadcastReceiver ,并将其设置为侦听"com.my.app.wifi.WIFI_RELATED_CHANGE" This String value must be the same as the one used when sending the broadcast from your ConnectionChangeReceiver # onReceive(...) : 此String值必须与从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
        }
    }
};

You should declare the BroadcastReceiver as a class member. 您应该将BroadcastReceiver声明为类成员。 This will allow you to register and unregister the BroadcastReceiver appropriately: register in onResume() and unregister in onPause() . 这将允许您适当地注册和取消注册BroadcastReceiver :在onResume()注册并在onPause()取消注册。

In onResume() of your activity, register this receiver to listen for action com.my.app.wifi.WIFI_RELATED_CHANGE : 在您的活动的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);
}

Unregister the reciever in onPause() : onPause()取消注册接收器:

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

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

Note that you can declare a receiver such as wifiRelatedChangeListener in however many activities. 请注意,您可以在许多活动中声明接收器,例如wifiRelatedChangeListener The broadcast is sent once from ConnectionChangeReceiver # onReceive(...) . 广播从ConnectionChangeReceiver # onReceive(...)发送一次。 Whichever activity is in the foreground/listening at that point, will receive this broadcast and act upon it. 无论哪个活动在该前景/收听中,将接收该广播并对其进行操作。

By that time its too late 到那时为时已晚

This issue will not be present in the solution discussed above. 在上面讨论的解决方案中将不存在此问题。

You have an incorrect approach. 你的方法不正确。 Your broadcast receiver should send a message to your Activity, and then your Activity should check the WiFi status using the method "onNewIntent". 您的广播接收器应向您的活动发送消息,然后您的活动应使用“onNewIntent”方法检查WiFi状态。 Then if you are setting a static variable in your receiver (which you probably shouldn't do) you could check it, but better just send your Activity a Boolean "extra" with the WiFi status. 然后,如果你在接收器中设置一个静态变量(你可能不应该这样做),你可以检查它,但最好只是发送你的Activity一个带有WiFi状态的布尔“额外”。

The problem is that your UI thread is much faster than a background thread. 问题是你的UI线程比后台线程快得多。 So if an Activity is responding to an event that a receiver is also responding to, it's very likely Android will prioritize the Activity's processing over the background thread. 因此,如果活动正在响应接收者也在响应的事件,那么Android很可能会优先考虑活动在后台线程上的处理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM