Twitter4JでStethoを使う方法

StethoはFacebookが公開している超便利ライブラリです。
通信内容を母艦のChrome Developer Toolsで丸裸にできます。

詳しくは [StethoでAndroidのNetwork Performanceを見る - Qiita](http://qiita.com/wasabeef_jp/items/1e7bdb78766708206d3d) 参照。

Twitter4JでStethoを使う場合はちょっとクセがあるのでその解説を備忘録代わりに書いておきます。

デバッグビルドでのみ動作するようにします。

また、Twitter4J(twitter4j-http2-support)の動作の都合上、最初の通信後ではないとOkHttpインスタンスが取得できないので、この方法だと最初の通信だけはinspectできません。

![CDFmQ7VVAAAGqAG.jpg](https://qiita-image-store.s3.amazonaws.com/0/39221/0c7eadcc-b765-0353-db61-b38cab64bdc5.jpeg)


# 環境

 |version|備考
---|---|---
Twitter4J|4.0.3|*1
OkHttp|2.3.0|*1
AndroidStudio|1.2 Beta3|


*1 カスタマイズ版を使っています。


# Set-up

## Download

```groovy:build.gradle
dependencies {
    debugCompile 'com.facebook.stetho:stetho:1.1.0'
    debugCompile 'com.facebook.stetho:stetho-okhttp:1.1.0'
}
```

通常は上記で十分なんですが個人的に okhttp をカスタマイズしているので、自力で stetho-okhttp をビルドし直して下記のように書いています。

```groovy:build.gradle
dependencies {
    compile files('libs/okhttp-2.3.0.jar')
    compile 'com.squareup.okio:okio:1.3.0'

    debugCompile 'com.facebook.stetho:stetho:1.1.0'
    debugCompile files('libs/stetho-okhttp-1.1.0-SNAPSHOT.jar')
}
```

## Setup

いわゆるApplicationクラスでStethoの初期化を行います。

```java:main/java/com/twitpane/App.java
public class App extends AppBase {
...
}
```

```java:debug/java/com/twitpane/AppBase.java
package com.twitpane;

import android.app.Application;

import com.facebook.stetho.Stetho;
import com.facebook.stetho.okhttp.StethoInterceptor;
import com.squareup.okhttp.Interceptor;
import com.squareup.okhttp.OkHttpClient;
import com.twitpane.util.TPUtil;

import java.util.List;

import jp.takke.util.MyLog;
import twitter4j.Twitter;

public class AppBase extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        // デバッグビルドでのみStethoを有効化
        Stetho.initialize(
                Stetho.newInitializerBuilder(this)
                .enableDumpapp(Stetho.defaultDumperPluginsProvider(this))
                .enableWebKitInspector(Stetho.defaultInspectorModulesProvider(this))
                .build());

    }

    public static void onTwitterConnectionEstablished(Twitter twitter) {

        try {
            final twitter4j.AlternativeHttpClientImpl http = TPUtil.getHttpClientImpl(twitter);
            final OkHttpClient client = TPUtil.getOkHttpClient(http);

            if (client != null) {

                final List<Interceptor> interceptors = client.networkInterceptors();
                if (interceptors.size() == 0) {
                    interceptors.add(new StethoInterceptor());
                }
            }

        } catch (Exception e) {
            MyLog.e(e);
        }
    }
}
```

```java:release/java/com/twitpane/AppBase.java
package com.twitpane;

import android.app.Application;

import twitter4j.Twitter;

public class AppBase extends Application {

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

    public static void onTwitterConnectionEstablished(Twitter twitter) {
    }
}
```

```java:TPUtil.java
...
    public static twitter4j.AlternativeHttpClientImpl getHttpClientImpl(
            final Twitter twitter) throws ClassNotFoundException,
            NoSuchFieldException, IllegalAccessException {

        final Class<?> clazz = Class.forName("twitter4j.TwitterBaseImpl");
        final Field f1 = clazz.getDeclaredField("http");
        f1.setAccessible(true);
        final HttpClient impl = (HttpClient) f1.get(twitter);
        return (twitter4j.AlternativeHttpClientImpl) impl;
    }

    public static OkHttpClient getOkHttpClient(AlternativeHttpClientImpl http) {

        try {
            final Field f3 = ((Object) http).getClass().getDeclaredField("okHttpClient");
            f3.setAccessible(true);

            // client = http.okHttpClient
            return (OkHttpClient) f3.get(http);
        } catch (Exception e) {
            MyLog.e(e);
            return null;
        }
    }
```

MyLog.java は省略

で、通信後におもむろに AppBase.onTwitterConnectionEstablished を呼び出してあげればOK。

```TimelineFragment.java

...
    result = twitter.getHomeTimeline(mPaging);

    AppBase.onTwitterConnectionEstablished(twitter);
...

```