Twitterのタイムラインをgzip転送の効用
勉強中
この本で勉強中Androidプログラミングバイブル―SDK3.0/2.3/2.2/2.1対応 (smart phone programming bible)
- 作者: 布留川英一
- 出版社/メーカー: ソシム
- 発売日: 2011/04
- メディア: 単行本
- 購入: 4人 クリック: 58回
- この商品を含むブログ (16件) を見る
参考
DefaultHttpClientのgzip転送の効用http://d.hatena.ne.jp/Tackn1977/20120414/1334373350
Twitterのタイムラインでgzip転送の効用を見る
タイムラインは常に容量が変化しますがgzip転送の効果は十分に見て取れる結果が出ました。アプリケーションソース
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="jp.tackn.defaulthttpclientex" android:versionCode="1" android:versionName="1.0"> <application android:label="@string/app_name"> <activity android:name=".MainActivity" android:label="@string/app_name" android:launchMode="singleInstance"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="myapp" android:host="httpclient" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="4" /> <supports-screens android:resizeable="true" /> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> </manifest>
MainActivity.java
package jp.tackn.defaulthttpclientex; import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Color; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.*; import java.io.*; import java.net.MalformedURLException; import java.net.URL; import java.util.zip.GZIPInputStream; import oauth.signpost.OAuthProvider; import oauth.signpost.basic.DefaultOAuthProvider; import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer; import oauth.signpost.exception.OAuthCommunicationException; import oauth.signpost.exception.OAuthExpectationFailedException; import oauth.signpost.exception.OAuthMessageSignerException; import oauth.signpost.http.HttpRequest; import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; /** * DefaultHttpClientを使ったサンプルプログラム * * @author Tackn */ public class MainActivity extends Activity implements View.OnClickListener { //定数 /** OAuth CONSUMER KEY */ private String CONSUMER_KEY=""; /** OAuth CONSUMER SECRET */ private String CONSUMER_SECRET=""; /** OAuth REQUEST_TOKEN URL */ private String REQUEST_TOKEN_URL=""; /** OAuth AUTHORIZE URL */ private String AUTHORIZE_URL=""; /** OAuth ACCESS TOKEN URL */ private String ACCESS_TOKEN_URL=""; /** ブラウザのコールバックURL */ private final static String CALLBACKURL="myapp://httpclient"; /** Log用tag */ private final static String LOG_TAG = "tackn"; /** 内容に合わせる */ private final static int WC = LinearLayout.LayoutParams.WRAP_CONTENT; /** 親コンテンツに合わせる */ private final static int FP = LinearLayout.LayoutParams.FILL_PARENT; /** URL入力用エディットボックス */ private EditText url_input; /** 結果表示用テキストビュー */ private TextView result_view; /**gzip追加有無 */ private CheckBox cb_Gzipx; //認証 private CommonsHttpOAuthConsumer consumer; private OAuthProvider provider; /** アクティビティ起動時に呼ばれる */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //TwitterのOAuth関連の読み込み CONSUMER_KEY =getResources().getString(R.string.Consumer_key); CONSUMER_SECRET =getResources().getString(R.string.Consumer_secret); REQUEST_TOKEN_URL=getResources().getString(R.string.Request_token_URL); AUTHORIZE_URL =getResources().getString(R.string.Authorize_URL); ACCESS_TOKEN_URL =getResources().getString(R.string.Access_token_URL); //コンポーネントの垂直方向に配置 LinearLayout mainLayout = new LinearLayout(this); mainLayout.setBackgroundColor(Color.WHITE); mainLayout.setOrientation(LinearLayout.VERTICAL); // URL入力欄の生成 url_input = new EditText(this); // url_input.setText("http://www.ugtop.com/spill.shtml", TextView.BufferType.NORMAL);//確認くん // url_input.setText("http://www.kojikoji.net/", TextView.BufferType.NORMAL);//GET/POST 確認くん url_input.setText("https://api.twitter.com/1/statuses/public_timeline.xml", TextView.BufferType.NORMAL);//GET/POST 確認くん url_input.setLayoutParams(new LinearLayout.LayoutParams(FP, WC)); mainLayout.addView(url_input); // gzipするかのチェックボックスの生成 cb_Gzipx = new CheckBox(this); cb_Gzipx.setText("ヘッダーにgzipを追加"); cb_Gzipx.setTextColor(Color.BLACK); cb_Gzipx.setChecked(false); cb_Gzipx.setLayoutParams(new LinearLayout.LayoutParams(WC, WC)); mainLayout.addView(cb_Gzipx); //実行するボタンの生成 mainLayout.addView(makeButton("取得", "get")); //結果を表示するテキストビューの生成 result_view = new TextView(this); result_view.setTextSize(16f); result_view.setTextColor(Color.BLACK); result_view.setLayoutParams(new LinearLayout.LayoutParams(FP, FP)); mainLayout.addView(result_view); //ビューのセット setContentView(mainLayout); //認証 doOauth(false); } /** * ボタンを押したときの動作 * * @param v クリックされたView */ public void onClick(View v) { if (v.getTag().equals("get")) { getFile(url_input.getText().toString()); } else { Toast.makeText(this, "何事!", Toast.LENGTH_SHORT); } } /** * ボタンを作成するサブクラス * * @param text ボタンのラベル * @param tag ボタンの識別タグ * @return 作成したButtonオブジェクト */ private Button makeButton(String text, String tag) { Button button = new Button(this); button.setText(text); button.setTag(tag); button.setOnClickListener(this); button.setLayoutParams(new LinearLayout.LayoutParams(FP, WC)); return button; } /** * URLのパスからSDカード直下にファイルを取得する * * @param url 取得するURL */ private void getFile(String url) { try { URL path = new URL(url); } catch (MalformedURLException ex) { result_view.setText(result_view.getText() + "URLが不正です\n"); return; } HttpRequest rq = null; /** * HTTP GETリクエスト */ HttpGet httpGet = new HttpGet(url); try { rq= consumer.sign(httpGet); } catch (OAuthMessageSignerException ex) { Log.e(LOG_TAG,"OAuthMessageSignerException: "+ex.getMessage()); } catch (OAuthExpectationFailedException ex) { Log.e(LOG_TAG,"OAuthExpectationFailedException: "+ex.getMessage()); } catch (OAuthCommunicationException ex) { Log.e(LOG_TAG,"OAuthCommunicationException: "+ex.getMessage()); } if (cb_Gzipx.isChecked()) { result_view.setText(result_view.getText() + "gzip圧縮\n"); httpGet.setHeader("Accept-Encoding", "gzip, deflate"); } else { result_view.setText(result_view.getText() + "gzip非圧縮\n"); } /** 読み込みサイズ */ int size = 0; /** 読み込みバッファ */ byte[] w = new byte[1024]; /** 入力ストリーム */ InputStream in = null; /** 受信用ストリーム */ ByteArrayOutputStream out = new ByteArrayOutputStream(); /**ファイル保存用ストリーム */ FileOutputStream writefile = null; /** コンテンツ取得用HTTPクライアント */ DefaultHttpClient httpClient = new DefaultHttpClient(); /**取得結果 */ HttpResponse execute = null; try {//URLへリクエスト execute = httpClient.execute(httpGet); switch (execute.getStatusLine().getStatusCode()) { case HttpStatus.SC_OK: result_view.setText(result_view.getText() + "Status 200 OK (HTTP/1.0 - RFC 1945)\n"); break; case HttpStatus.SC_MOVED_PERMANENTLY: result_view.setText(result_view.getText() + "Status 301 Moved Permanently (HTTP/1.0 - RFC 1945)\n"); return; case HttpStatus.SC_MOVED_TEMPORARILY: result_view.setText(result_view.getText() + "Status 302 Moved Temporarily (Sometimes Found) (HTTP/1.0 - RFC 1945)\n"); return; case HttpStatus.SC_NOT_FOUND: result_view.setText(result_view.getText() + "Status 404 Not Found (HTTP/1.0 - RFC 1945)\n"); return; case HttpStatus.SC_INTERNAL_SERVER_ERROR: result_view.setText(result_view.getText() + "Status 500 Server Error (HTTP/1.0 - RFC 1945)\n"); return; case HttpStatus.SC_SERVICE_UNAVAILABLE: result_view.setText(result_view.getText() + "Status 503 Service Unavailable (HTTP/1.0 - RFC 1945)\n"); return; default: result_view.setText(result_view.getText() + "Status " + execute.getStatusLine().getStatusCode() + "\n"); return; } } catch (ClientProtocolException ex) { Log.e(LOG_TAG, "ClientProtocolException: " + ex.getMessage()); } catch (IOException ex) { Log.e(LOG_TAG, "IOException: " + ex.getMessage()); } try {//HttpStatus.SC_OKの場合取得開始 /** 取得開始時刻 */ Long stratTime = System.currentTimeMillis(); //gzip転送の有無で切り替え if (isGZipHttpResponse(execute)) { in = new GZIPInputStream(execute.getEntity().getContent()); } else { in = execute.getEntity().getContent(); } //読み込み処理 while (true) { size = in.read(w); if (size <= 0) { break; } out.write(w, 0, size); } in.close(); /** * 取得終了時刻 */ Long endTime = System.currentTimeMillis(); result_view.setText(result_view.getText() + "取得時間:" + (endTime - stratTime) + "ms\n"); Log.i(LOG_TAG, "取得時間:"+(endTime - stratTime) + "ms"); //ファイルに保存 if(checkSDCard()){ /** 出力ファイルパスの取得 */ File dir = Environment.getExternalStorageDirectory(); File file = null; if(url.length()-1==url.lastIndexOf("/")){ file=File.createTempFile("test", ".html", dir); }else{ file=new File(dir.getAbsolutePath()+url.substring(url.lastIndexOf("/"))); } Log.i(LOG_TAG, url); writefile = new FileOutputStream(file); writefile.write(out.toByteArray()); writefile.flush(); writefile.close(); } } catch (IOException ex) { Log.e(LOG_TAG,"IOException: "+ex.getMessage()); } catch (IllegalStateException ex) { Log.e(LOG_TAG,"IllegalStateException: "+ex.getMessage()); } finally { if (in != null) { try { in.close(); writefile.close(); } catch (IOException ex) { } } httpClient.getConnectionManager().shutdown(); } } /** * gzipが有効か判定する処理 * * @param response HTTPレスポンス * @return gzip圧縮されているかの判定 */ private boolean isGZipHttpResponse(HttpResponse response) { Header header = response.getEntity().getContentEncoding(); if (header == null) { return false; } String value = header.getValue(); return (!TextUtils.isEmpty(value) && value.contains("gzip")); } /** * SDカードの状態をチェック * @return SDカードが着込み可かどうか */ private boolean checkSDCard() { String status = Environment.getExternalStorageState(); if (status.equalsIgnoreCase(Environment.MEDIA_MOUNTED)) { // Toast.makeText(MainActivity.this, // "SDカードが装着されている", // Toast.LENGTH_LONG).show(); //この状態が返ってきた場合は、読み書きが可能です。 return true; } else if (status.equalsIgnoreCase(Environment.MEDIA_MOUNTED_READ_ONLY)) { Toast.makeText(MainActivity.this, "SDカードが装着されていますが、読み取り専用・書き込み不可です", Toast.LENGTH_LONG).show(); return false; } else if (status.equalsIgnoreCase(Environment.MEDIA_REMOVED)) { Toast.makeText(MainActivity.this, "SDカードが装着されていません", Toast.LENGTH_LONG).show(); return false; } else if (status.equalsIgnoreCase(Environment.MEDIA_SHARED)) { Toast.makeText(MainActivity.this, "SDカードが装着されていますが、USBストレージとしてPCなどに" + "マウント中です", Toast.LENGTH_LONG).show(); return false; } else if (status.equalsIgnoreCase(Environment.MEDIA_BAD_REMOVAL)) { Toast.makeText(MainActivity.this, "SDカードのアンマウントをする前に、取り外しました", Toast.LENGTH_LONG).show(); return false; } else if (status.equalsIgnoreCase(Environment.MEDIA_CHECKING)) { Toast.makeText(MainActivity.this, "SDカードのチェック中です", Toast.LENGTH_LONG).show(); return false; } else if (status.equalsIgnoreCase(Environment.MEDIA_NOFS)) { Toast.makeText(MainActivity.this, "SDカードは装着されていますが、ブランクであるか、" + "またはサポートされていないファイルシステムを利用しています", Toast.LENGTH_LONG).show(); return false; } else if (status.equalsIgnoreCase(Environment.MEDIA_UNMOUNTABLE)) { Toast.makeText(MainActivity.this, "SDカードは装着されていますが、マウントすることができません", Toast.LENGTH_LONG).show(); return false; } else if (status.equalsIgnoreCase(Environment.MEDIA_UNMOUNTED)) { Toast.makeText(MainActivity.this, "SDカードは存在していますが、マウントすることができません", Toast.LENGTH_LONG).show(); return false; } else { Toast.makeText(MainActivity.this, "その他の要因で利用不可能", Toast.LENGTH_LONG).show(); return false; } } /** * Oauth認証 * * @param setup */ private void doOauth(boolean setup) { consumer = new CommonsHttpOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET); provider = new DefaultOAuthProvider(REQUEST_TOKEN_URL, ACCESS_TOKEN_URL, AUTHORIZE_URL); try { //トークンの読み込み SharedPreferences pref = getSharedPreferences("token", MODE_PRIVATE); String token = pref.getString("token", ""); String tokenSecret = pref.getString("tokenSecret", ""); //認証済み if (!setup && token.length() > 0 && tokenSecret.length() > 0) { consumer.setTokenWithSecret(token, tokenSecret); } //認証処理のためブラウザ起動 else { String url = provider.retrieveRequestToken(consumer, CALLBACKURL); Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); this.startActivity(intent); } } catch (Exception e) { Toast.makeText(this, "doOauth: "+e.getMessage(), Toast.LENGTH_LONG).show(); Log.e(LOG_TAG, "doOauth: "+e.getMessage()); } } /** * トークン情報の取得 設定終了時に呼ばれる * AndroidManifestのactivityにandroid:launchMode="singleInstance" * の記述が必要 * @param intent */ @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); Uri uri = intent.getData(); if (uri != null && uri.toString().startsWith(CALLBACKURL)) { String verier = uri.getQueryParameter(oauth.signpost.OAuth.OAUTH_VERIFIER); try { provider.retrieveAccessToken(consumer, verier); //トークン書き込み SharedPreferences prof = getSharedPreferences("token", MODE_PRIVATE); SharedPreferences.Editor editor = prof.edit(); editor.putString("token", consumer.getToken()); editor.putString("tokenSecret", consumer.getTokenSecret()); editor.commit(); } catch (Exception e) { Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show(); Log.e(LOG_TAG, e.getMessage()); } } } }