BroadcastReceiver为一个事件接收多个相同的消息

时间:2011-12-07 09:06:28

标签: android networking wifi broadcastreceiver

我注册了一个侦听网络事件的接收器:

<receiver 
    android:label="NetworkConnection"
    android:name=".ConnectionChangeReceiver" >
    <intent-filter >
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    </intent-filter>
</receiver>

接收器也很简单:

public class ConnectionChangeReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
        if (activeNetInfo != null) {
                Log.v("@@@","Receiver : " + activeNetInfo);
        } else {
            Log.v("@@@","Receiver : " + "No network");
        }
    }
}

问题是,当连接Wifi时,我连续收到3条相同的消息,如下所示:

Receiver : NetworkInfo: type: WIFI[], state: CONNECTED/CONNECTED, reason: (unspecified), extra: (none), roaming: false, failover: false, isAvailable: true
Receiver : NetworkInfo: type: WIFI[], state: CONNECTED/CONNECTED, reason: (unspecified), extra: (none), roaming: false, failover: false, isAvailable: true
Receiver : NetworkInfo: type: WIFI[], state: CONNECTED/CONNECTED, reason: (unspecified), extra: (none), roaming: false, failover: false, isAvailable: true

它们都是“连接/连接”(它们不应该像CONNECTING / OBTAINING_IPADDR等),所以问题是如何确定它何时真正连接?当wifi实际连接时我有一些我想做的例程,我不希望连续三次调用它们。

PS:3G只发送一条消息,所以这里没问题。

更新:

似乎是设备特定的问题。

为了测试我拿了2个Desire HD和4个随机Android手机(不同的Aquos型号和一些无名的中文内容)。在DHD和wifi上的一个随机电话连接上我收到3条消息,在剩下的手机上我只收到一条消息。 WTF。

6 个答案:

答案 0 :(得分:56)

接收多个广播是设备特定的问题。有些手机只发送一个广播而另一个发送2或3.但是有一个解决方法:

假设你在wifi断开连接时收到断开连接的消息,我猜第一个是正确的,另外两个只是由于某种原因的回声。

要知道消息已被调用,你可以有一个静态布尔值,它在connect和disconnect之间切换,只在你收到一个连接并且boolean为true时调用你的子例程。类似的东西:

public class ConnectionChangeReceiver extends BroadcastReceiver {
    private static boolean firstConnect = true;

    @Override
    public void onReceive(Context context, Intent intent) {
        final ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        final NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
        if (activeNetInfo != null) {
            if(firstConnect) { 
                // do subroutines here
                firstConnect = false;
            }
        }
        else {
            firstConnect= true;
        }
    }
}

答案 1 :(得分:8)

您还可以在静态字段中缓存上次处理的连接类型,并检查收到的广播。这样,每种连接类型只能获得一个广播。

当连接类型发生变化时,它显然会起作用。当设备不连接时,activeNetworkInfo将为空,currentType将为NO_CONNECTION_TYPE,与默认情况相同。

public class ConnectivityReceiver extends BroadcastReceiver {

    /** The absence of a connection type. */
    private static final int NO_CONNECTION_TYPE = -1;

    /** The last processed network type. */
    private static int sLastType = NO_CONNECTION_TYPE;

    @Override
    public void onReceive(Context context, Intent intent) {
        ConnectivityManager connectivityManager = (ConnectivityManager)
                context.getSystemService(Context.CONNECTIVITY_SERVICE);

        NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
        final int currentType = activeNetworkInfo != null
                ? activeNetworkInfo.getType() : NO_CONNECTION_TYPE;

        // Avoid handling multiple broadcasts for the same connection type
        if (sLastType != currentType) {
            if (activeNetworkInfo != null) {
                boolean isConnectedOrConnecting = activeNetworkInfo.isConnectedOrConnecting();
                boolean isWiFi = ConnectivityManager.TYPE_WIFI == currentType;
                boolean isMobile = ConnectivityManager.TYPE_MOBILE == currentType;

                // TODO Connected. Do your stuff!
            } else {
                // TODO Disconnected. Do your stuff!
            }

            sLastType = currentType;
        }
}

答案 2 :(得分:3)

在我的情况下,我在onResume注册了我的BroadcastReceivers,并且仅在onDestroy.

中取消注册

这导致每个广播接收者注册3到4次,具体取决于活动恢复的次数。

根据活动生命周期将广播接收器设置在正确的位置,可以让您停止多次混乱的呼叫。

答案 3 :(得分:1)

oncreate()内注册您的LocalBroadcastreceiver,而不是onResume()。未注册onDestroy

答案 4 :(得分:0)

我有一个应用程序在用户重新联机时上传数据。由于我的广播接收器可以多次接收该意图,因此可能导致数据不止一次上传。为了解决这个问题,我使用的服务如果已经运行则不会做任何事情。

广播接收器:

public class ConnectionChangeReceiver extends BroadcastReceiver {
    private static boolean firstConnect = true;

    @Override
    public void onReceive(Context context, Intent intent) {
        final ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        final NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
        if (activeNetInfo != null) {
            startService();
        }   
    }
}

服务:

public class MyService extends Service {
    private boolean mRunning;

    @Override
    public void onCreate() {
        super.onCreate();
        mRunning = false;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (!mRunning) {
            mRunning = true;
            uploadTheData();
        }
        return super.onStartCommand(intent, flags, startId);
    }
}

答案 5 :(得分:0)

我对Aleksander提出的方法感到担忧的是,它没有考虑相同类型的网络更改,例如从一个WiFi网络到另一个WiFi网络。

我建议比较活动网络的extraInfo,其中包含网络名称,例如WiFi SSID或移动网络名称(例如VZW)

services.AddAuthentication(HttpSys.DefaultsAuthenticationSchme)