ネットワークイベントをリッスンするレシーバーを登録しました。
<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が実際に接続されているときに作成したいルーチンがいくつかあり、それらを3回続けて呼び出さないでください。
PS:3Gはメッセージを1つだけ送信するため、ここでは問題ありません。
更新:
デバイス固有の問題のようです。
テストでは、2つの欲望HDと4つのランダムAndroid電話(さまざまなAquosモデルといくつかの名前のない中国語のもの)を使用しました。DHDとwifi接続の1つのランダム電話の両方で、3つのメッセージを受け取りました。残りの電話では、メッセージは1つしかありませんでした。
複数のブロードキャストの受信はデバイス固有の問題です。一部の電話は1つのブロードキャストを送信し、他の電話は2または3を送信します。しかし、回避策があります:
Wifiが切断されたときに切断メッセージが表示されると仮定すると、最初の1つが正しいものであり、他の2つは何らかの理由でエコーしていると思います。
メッセージが呼び出されたことを知るには、接続と切断を切り替える静的なブール値を使用し、接続を受信してブール値が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つのブロードキャストのみが取得されます。
接続タイプが変更されると、明らかに機能します。デフォルトの場合と同様に、デバイスが接続から外れると、activeNetworkInfo
はnullになり、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;
}
}
私の場合、BroadcastReceiversをonResume
に登録し、onDestroy.
でのみ登録解除していました
これにより、アクティビティが再開する回数に応じて、各ブロードキャストレシーバーが3または4回登録されました。
ブロードキャストレシーバーをアクティビティライフサイクルの適切な場所に設定すると、混乱を招く複数の呼び出しの発生を防ぐことができます。
LocalBroadcastreceiverをoncreate()
ではなくonResume()
自体に登録します。 onDestroy
で未登録
Aleksanderによって提案されたアプローチに関する私の懸念は、同じタイプのネットワーク変更を考慮しないことです。あるWiFiネットワークから別のWiFiネットワークへ。
ネットワーク名が含まれているアクティブなネットワークのextraInfoを比較することを提案しています。 WiFi SSIDまたはVZWなどのモバイルネットワーク名
String currentNetworkName = "";
ConnectivityManager connectivityManager =
((ConnectivityManager) context.getSystemService(
Context.CONNECTIVITY_SERVICE));
NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
boolean connected = activeNetwork != null && activeNetwork.isConnectedOrConnecting();
if (connected) {
// prevent duplicate connect broadcasts
String extraInfo = activeNetwork.getExtraInfo();
if(! currentNetworkName.equals(extraInfo)) {
// to do: handle network changes
currentNetworkName = extraInfo;
}
} else {
Log.d(TAG, "is not connected");
isConnected = false;
currentNetworkName = "";
}
ユーザーがオンラインに戻ったときにデータをアップロードするアプリケーションがあります。私の放送受信機はインテントを複数回受信できるため、データが複数回アップロードされる可能性があります。これを処理するために、すでに実行されている場合は何もしないサービスを使用します。
放送受信機:
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);
}
}