スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Android用のTwitterクライアントを作ってみる



もう猫も杓子もTwitterな昨今いかがお過ごしでしょうか。


というわけですごい単純なTwitterClientを作成したいと思います。
ちなみにこちらの「きしだのはてな」さんのサンプルをす~っごく参考にしました。
http://d.hatena.ne.jp/nowokay/20091030
また、
「ところで、HTMLの最初のほうに変更がないと、loadDataしても画面が更新されないのはなんでなんだぜ?」
と発言されていますが、本当になぜなんだぜ?


ちなみに
・キャッシュかな?と思い、WebView.clearCache でキャシュをクリアするも意味なし
・描画に更新かければいいのかと考え、WebView.postInvalidate()を呼ぶも意味なし
・WebView.loadData を2回呼ぶと更新される・・・。←とりあえず暫定で採用
・きしだのはてなさんのサンプルのように、上のほうの文字列を変更する
という状況でした。
わけわかんね。



layout/main.xml


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent"
	>

	<TableLayout android:id="@+id/TableLayout01" android:layout_width="fill_parent" android:layout_height="wrap_content">
		<TableRow android:id="@+id/TableRow01" android:layout_width="fill_parent" android:layout_height="wrap_content">
			<Button
				android:text="Update"
				android:id="@+id/UpdateButton"
				android:layout_width="fill_parent"
				android:layout_height="wrap_content" 
				android:layout_weight="1">
			</Button>
			<Button
				android:text="Reload"
				android:id="@+id/ReloadButton"
				android:layout_width="fill_parent"
				android:layout_height="wrap_content"
				 android:layout_weight="1">
			</Button>
		</TableRow>
	</TableLayout>

	<EditText
		android:text=""
		android:id="@+id/UpdateEdit"
		android:layout_width="fill_parent"
		android:layout_height="wrap_content">
	</EditText>
	<WebView
		android:id="@+id/twitter_web"
		android:layout_width="fill_parent"
		android:layout_height="fill_parent"
		android:text=""/>


</LinearLayout>

ボタンを2つ並べて表示するために、TableLayoutを使用。
また、2つボタンのサイズを統一するためにlayout_weightの値をそろえる。



AndroidManifest.xml


ネットに繋ぐ前提となるので
・<uses-permission android:name="android.permission.INTERNET"></uses-permission>
を追加



Main.java


package com.omokageru.ak.twitter;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.MultiAutoCompleteTextView.Tokenizer;

public class Main extends Activity {
	private Button updateButton;
	private Button reloadButton;
	private EditText updateEdit;
	private WebView webView;

	private DefaultHttpClient httpClient;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		updateButton = (Button) findViewById(R.id.UpdateButton);

		// ボタン押下時の処理
		updateButton.setOnClickListener(new OnClickListener() {

			public void onClick(View v) {
				// TODO 自動生成されたメソッド・スタブ

				// 通信を伴うので別スレッドで
				new Thread(){
					@Override
					public void run() {
						// TODO 自動生成されたメソッド・スタブ
						updateButton.setClickable(false);
						reloadButton.setClickable(false);
						String str = updateEdit.getEditableText().toString();
						UpdateTwitter(str);
						reloadButton.setClickable(true);
						updateButton.setClickable(true);
					}
				}.start();
			}
		});

		reloadButton = (Button) findViewById(R.id.ReloadButton);

		reloadButton.setOnClickListener(new OnClickListener() {

			public void onClick(View view) {
				// TODO 自動生成されたメソッド・スタブ

				// 通信を伴うので別スレッドで
				new Thread(){
					@Override
					public void run() {
						updateButton.setClickable(false);
						reloadButton.setClickable(false);
						GetAndWriteHomeTimeLine();
						reloadButton.setClickable(true);
						updateButton.setClickable(true);
					}
				}.start();
			}
		});

		updateEdit = (EditText) findViewById(R.id.UpdateEdit);
		webView = (WebView) findViewById(R.id.twitter_web);

		httpClient = new DefaultHttpClient();
		Credentials cred = new UsernamePasswordCredentials( "Twitter User ID", "Password");//userとpassを
		httpClient.getCredentialsProvider().setCredentials( new AuthScope("twitter.com", 80), cred);

		GetAndWriteHomeTimeLine();
    }

	/**
	 * Twitterへつぶやく
	 * @param str
	 * 投稿内容
	 */
	private synchronized void UpdateTwitter( String str){
		try {
			// パラメータstatus=hoge でhogeを発言
			// status は必須パラメータ
			HttpPost post = new HttpPost( "http://twitter.com/statuses/update.json?status=" + str);
			// 一応これで発言するはず
			HttpResponse response = httpClient.execute(post);

			// 失敗時の処理
			if(response.getStatusLine().getStatusCode() != HttpStatus.SC_OK){
				return;
			}

			// ここからの描画はなぜか利かない・・・
			GetAndWriteHomeTimeLine();

		} catch (ClientProtocolException e) {
			// TODO 自動生成された catch ブロック
		} catch (IOException e) {
			// TODO 自動生成された catch ブロック
		}

	}

	/**
	 * friend_timelineは将来廃止予定らしいので home_timeline を取得し表示。<br />
	 * http://d.hatena.ne.jp/nowokay/20091030 を参考にしました。
	 */
	private synchronized void GetAndWriteHomeTimeLine(){
		try {
//			webView.clearCache(false);

			HttpGet get = new HttpGet( "http://twitter.com/statuses/home_timeline.json");
			// これで取得するはず
			HttpResponse response = httpClient.execute(get);

			// 失敗時の処理
			if(response.getStatusLine().getStatusCode() != HttpStatus.SC_OK){
				return;
			}

			//解析と出力
    		//サーバーからのデータを取得
			InputStream is = response.getEntity().getContent();
			InputStreamReader isr = new InputStreamReader(is);
			StringWriter strin = new StringWriter();
			BufferedReader buf = new BufferedReader(isr);
			for(String line; (line = buf.readLine()) != null;){
				strin.write(line);
			}
			buf.close();
			isr.close();
			is.close();


            //出力準備
			StringWriter strout = new StringWriter();
			PrintWriter out = new PrintWriter(strout);
			out.println("<html><head><title>Twitter testapites</title></head>");
			out.println("<body>");
			//JSONデータからタイムラインを取得してHTMLを生成
			JSONTokener token = new JSONTokener(strin.toString());
			JSONArray arr = new JSONArray(token);
			for(int i = 0; i < arr.length(); i++){
				JSONObject obj = arr.getJSONObject(i);
				JSONObject user = obj.getJSONObject("user");
				out.println("<div style='border-bottom: 1px solid #888888'>");
				out.println("<img style='width:48px; height:48px;' src='" + user.get("profile_image_url") + "' align='left'>");
				out.println("<bold><font color='#6666ff'>" + user.getString("screen_name") + "</font></bold><br />" );
				out.println(obj.get("text") + "<br clear='all' />");
				// ここで出力を確認しているが、発言内容が含まれているにもかかわらず、
				// loadData一回ではなぜか更新されない。
				Log.i("t_test", "" + obj.get("text"));
				out.println("</div>");
			}
			out.println("</body></html>");

			strin.close();
			out.close();

			// 二回呼び出すと反映される・・・
			// invalidate() の意味は??
			webView.loadData(strout.toString(), "text/html", "utf-8");
			webView.loadData(strout.toString(), "text/html", "utf-8");


			strout.close();

			// 描画更新
			// 本体スレッドからの呼び出しではない場合に備えpostInvalidateを使用。
//			webView.postInvalidate();
//			Log.i("t_test", "Invalidate");


		} catch (ClientProtocolException e) {
			// TODO 自動生成された catch ブロック
		} catch (JSONException e) {
			// TODO 自動生成された catch ブロック
		} catch (IOException e) {
			// TODO 自動生成された catch ブロック
		}

	}
}

一応発言と描画には synchronized をつけているので、重複して呼び出して落ちるってことはないと思いますが、念のため作業中はボタンを無効化しています。
失敗時の処理はめんどいので放置。
こんなソースを参考にする場合は、その辺はきっちりやることをお勧めします。
ちなみにhttp://twitter.com/statuses/home_timeline.json をたたくとこんな感じで返ってきます。
twitter_json_sample.txt



動かすとこんなかんじ。
起動時に取得に行きます。
device0109_01.png
発言すると、発言がきちんと反映
device0109_02.png

関連記事

テーマ : グーグルモバイル
ジャンル : 携帯電話・PHS

tag : android サンプルソース

trackback


この記事にトラックバックする(FC2ブログユーザー)

webview.loadDataを反映させる

webview.loadDataを反映させる Webview.loadDataを2回呼ぶのがよさそう。 その1

コメントの投稿

非公開コメント

プロフィール

駄猫

Author:駄猫

Twitter
その他
最新記事
カテゴリ
月別アーカイブ
検索フォーム
RSSリンクの表示
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。