Twitter4Jでユーザフォロー時にandroid.os.NetworkOnMainThreadExceptionが発生した場合の対処法

[Twitter4J](http://twitter4j.org/ja/) を使って、Android アプリ上で Twitter のフォロー機能を実現しようとした時に少しはまったので、その解決方法のメモを置いておきます。

次の `followTwitterUser()` メソッドを実行すると `android.os.NetworkOnMainThreadException` エラーが発生し、アプリが強制終了してしまいました。なぜ？

```java:java
public void followTwitterUser(String username) {
    // Twitter インスタンスの取得
    Twitter twitter = TwitterUtils.getTwitterInstance(this);

    // TwitterUtils クラスは以下のページを参照:
    //    Android再入門 - Twitterクライアントを作ってみよう
    //    http://qiita.com/gabu/items/f6f39900fd5e449045f9
    
    try {
        // Twitter フォロー実行
        twitter.createFriendship(username);
    } catch (TwitterException e) {
        e.printStackTrace();
    }
}
```
```java:java
String username = "twitter";
followTwitterUser(username);
```

エラーの内容は以下の通り。

```text:android.os.NetworkOnMainThreadException
FATAL EXCEPTION: main
android.os.NetworkOnMainThreadException
    at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1133)
    at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLOutputStream.write(OpenSSLSocketImpl.java:708)
    at java.io.BufferedOutputStream.flushInternal(BufferedOutputStream.java:185)
    at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:85)
    at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:824)
    at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:283)
    at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:497)
    at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:134)
    at twitter4j.HttpResponseImpl.<init>(HttpResponseImpl.java:35)
    at twitter4j.HttpClientImpl.handleRequest(HttpClientImpl.java:143)
    at twitter4j.HttpClientBase.request(HttpClientBase.java:53)
    at twitter4j.HttpClientBase.post(HttpClientBase.java:82)
    at twitter4j.TwitterImpl.post(TwitterImpl.java:1986)
    at twitter4j.TwitterImpl.createFriendship(TwitterImpl.java:480)
(以下省略)
```

エラー中にある `AndroidBlockGuardPolicy.onNetwork` というキーワードで調べてわかったのですが、どうやら Android 4.0 以降は、Main スレッド( UI スレッド)上でネットワーク通信を行うとこのエラーが発生するようです。

このエラーを回避するには、ネットワーク通信を別スレッド(サブスレッド)で実行する必要があります。サブスレッドで非同期処理を行う `AsyncTask` を作って `doInBackground()`コールバック内でネットワーク通信が必要な処理(Twitterのフォロー)を実行するように書き換えます。

```java:java
// サブスレッドから参照できるように Twitter クラスのインスタンスを保持する変数はメンバ変数にしておく
// 例:
// public class TwitterActivity extends Activity {
//
//     private Twitter mTwitter = null;
//     // ...(以下省略)
// }

public void followTwitterUserAsync(String username) {
    // Twitter インスタンスの取得
    mTwitter = TwitterUtils.getTwitterInstance(this);

    // サブスレッドで実行するタスクを作成
    AsyncTask<String, Void, Boolean> task = new AsyncTask<String, Void, Boolean>() {
        @Override
        protected Boolean doInBackground(String... params) {
            username = params[0];
            try {
                // Twitter フォロー実行
                mTwitter.createFriendship(username);
                return true;
            } catch (TwitterException e) {
                e.printStackTrace();
                return false;
            }
        }
		
        @Override
        protected void onPostExecute(Boolean followResult) {
            if (followResult) {
                // フォロー成功時の処理
            } else {
                // フォロー失敗時の処理
            }
        }
    };
    task.execute(username);
}
```

```java:java
String username = "twitter";
followTwitterUserAsync(username);
```
これで Twitter フォローができるようになりました。
ネットワーク通信を伴う処理はサブスレッドで実行する、というのがミソですね。