(Android)Networkの通信状況をしっかり見る

## Androidアプリの改善
接続中の通信回線を見て，
サーバから取ってくる画像のサイズを変えるようにしました．

今回は，そのために学んだ

- オンライン，オフライン判定
- Wi-Fi, Mobileネットワーク判定
- ネットワーク状況の変化を動的に受け取るReceiver

についてのコードを載せます．

## オンライン，オフライン判定
簡単に判定できます．

```java:NetUtils.java
    public static boolean isOnline(Context context) {
        ConnectivityManager connMgr = (ConnectivityManager)
                context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
        // You should always check isConnected(), since isConnected()
        // handles cases like unstable network state.
        return (networkInfo != null && networkInfo.isConnected());
    }
```
ただ，Wifi, Mobileいずれのネットワークも見つからない場合 (機内モードなど) ，
`connMgr.getActiveNetworkInfo()`が`Null`を返すので気をつけてください．

## Wi-Fi, Moblieネットワーク判定
こちらも簡単です．

```java:NetUtils.java
    public static boolean isWifiConnected(Context context) {
        ConnectivityManager connMgr = (ConnectivityManager)
                context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
        return networkInfo != null && networkInfo.isConnected()
                && networkInfo.getType() == ConnectivityManager.TYPE_WIFI;
    }
```

## ネットワーク状況の変化を動的に受け取るReceiver
こちらはまず，BroadcastReceiverを継承したクラスを作り，
`onReceive(context, intent)`メソッドを次のようにオーバーライドします．

```java:NetworkReceiver.java
    public interface OnNetworkStateChangedListener {
        void changedToWifi();
        void changedToMobile();
        void changedToOffline();
    }

　　@Override
    public void onReceive(Context context, Intent intent) {
        ConnectivityManager conn = (ConnectivityManager)
                context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = conn.getActiveNetworkInfo();

        if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
            if(mCallback!=null) mCallback.changedToWifi();
            Log.i(TAG, "Network state has changed to WIFI");
        } else if (networkInfo != null) {
            if(mCallback!=null) mCallback.changedToMobile();
            Log.i(TAG, "Network state has changed to MOBILE");
        } else {
            if(mCallback!=null) mCallback.changedToOffline();
            Log.i(TAG, "I have no idea...");
        }
    }
```
あとは，ネットワーク状況の変化を受け取りたいActivityなどで，
コールバックを受け取れるようにすれば完成です．

今回は，Callback インターフェースを介して，eventの受け渡しをします．
下のようにReceiverを登録することで，Wi-Fi -> Mobile回線のような変化を
Receiverが受け取れるようになります．

```java:MainActivity.java
　　@Override
    public void onResume() {
        super.onResume();
        // Registers BroadcastReceiver to track network connection changes.
        IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        mReceiver = new NetworkReceiver(mListener);
        registerReceiver(mReceiver, filter);
    }

    @Override
    public void onPause() {
        super.onPause();
        if(mReceiver != null) {
            unregisterReceiver(mReceiver);
        }
    }
```

## おまけ
今回，行った変更はこんな感じです．

**Before**
リスト表示に使う画像は，Wi-Fiが使えない時を意識して，小さめの画像にしてました．
ListViewに渡すAdapterの中はこんな感じで，常に150x150の画像をリクエストしてました．

```java:ImageAdapter.java
// always requests 150x150 image
ListItem item = getItem(position);
String url = item.generatePhotoURL("q");    // q : 150x150 image

ImageLoader.ImageListener listener =
        ImageLoader.getImageListener(holder.imageView,
                R.drawable.loading_default, R.drawable.ic_image_broken);
holder.imageView.setTag(mImageLoader.get(url, listener));
```

**After**
Wi-Fiにつながっているときは，大きめの画像を取ってくるようにしました．

```java:ImageAdapter.java
// change image quality by checking network state
ListItem item = getItem(position);
String quality_flg = is_wifi_connected ? "z": "q";  // z : 640x640, q : 150x150
String url = item.generatePhotoURL(quality_flg);

ImageLoader.ImageListener listener =
        ImageLoader.getImageListener(holder.imageView,
                R.drawable.loading_default, R.drawable.ic_image_broken);
holder.imageView.setTag(mImageLoader.get(url, listener));
```
結果，Wi-Fi時のリストがきれいになりました．

## 参考文献
[PerformingNetworkOperations | Android Developers](https://developer.android.com/training/basics/network-ops/index.html)