ネットワーク接続/切断イベントをハンドリング
掲載コードに問題があったので、こっそりエントリを再々修正。
ネットワーク接続状態は必ずConnectivityManagerを使って取得する。なお、ConnectivityManagerを利用するには、AndroidManifest.xmlに
サンプルコード
public class NetworkEventActivity extends Activity { private boolean connected = false; private BroadcastReceiver connectivityActionReceiver; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 初期状態を取得 ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo ni = cm.getActiveNetworkInfo(); connected = (ni != null) && ni.isConnected(); // BroadcastReceiverを登録 connectivityActionReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // ネットワーク接続状態を取得する ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo ni = cm.getActiveNetworkInfo(); boolean connected = (ni != null) && ni.isConnected(); // ハンドラをコールする onConnectedChanged(connected); } }; registerReceiver(connectivityActionReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); } /** * ネットワーク接続状態が変わった時にコールされるハンドラ */ private void onConnectedChanged(boolean connected) { if (connected == this.connected) return; this.connected = connected; if (connected) { Log.d("test", "接続済み"); } else { Log.d("test", "切れた!!!1!"); } } /** * 接続済であればtrueを返す */ private boolean isConnected() { return connected; } @Override protected void onDestroy() { // 使い終わったBroadcastReceiverを解放 unregisterReceiver(connectivityActionReceiver); super.onDestroy(); } }
期待通りに動作しないコード
このエントリは何度か修正しているのだが、動かないコードとその理由を掲載しておく。
ConnectivityManager.EXTRA_NO_CONNECTIVITYを使う
connectivityActionReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // ネットワーク接続状態を取得する boolean isConnected = !intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); boolean connected = (ni != null) && ni.isConnected(); // ハンドラをコールする onConnectedChanged(connected); } };
BroadcastReceiver.onReceive(Context, Intent)のIntentからEXTRA_NO_CONNECTIVITYの値を取得すればネットワークが切断されているかわかるよなどと書かれているが、こいつは大嘘。
Issue 13468 -
android -
Problem about ConnectivityManager.EXTRA_NO_CONNECTIVITY -
Android - An Open Handset Alliance Project - Google Project Hosting
に書かれているのだが、機内モードがONの時にネットワークに接続されていると値を返してくるので使ってはいけない。
ConnectivityManager.EXTRA_NETWORK_INFOを使う
connectivityActionReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // ネットワーク接続状態を取得する NetworkInfo ni = (NetworkInfo)intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO); boolean connected = (ni != null) && ni.isConnected(); // ハンドラをコールする onConnectedChanged(connected); } };
これで行けるだろうと数日間掲載していたのだが、駄目だった。
registerReceiver()すると最初にBroadcastが飛んで来るのだが、このBroadcastはデバイスのネットワークインタフェース毎に飛んでくるようだ(3G回線とWiFiが付いている場合は2回)。そのため、接続中/切断中のインタフェースが混在していると、一瞬切断されたかのようにイベントを拾ってしまう。