SQLの窓

2013年10月13日


Android : ListView Twitter 検索テンプレート



OneDrive へ移動




ListView で表示されている画像は、『private Drawable[] image_icon = new Drawable[100];』を定義しておいて、検索結果分を保存しておくようにしています。アダプタ内の getView で行うと、Android の仕様により、画像の表示がスクロールに追いつかない状態になります。

TwitterSearch.java
package com.example.listviewobjectjson;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import android.os.AsyncTask;
import android.util.Base64;

public class TwitterSearch {

	// AsyncTask のインラインで参照する為の final
	private final String _consumer_key;
	private final String _consumer_secret;
	private final String _token;
	private final String _secret;

	// API
	private final String _tweet_api = "https://api.twitter.com/1.1/search/tweets.json";
	
	// **************************************************************
	// コンストラクタ
	// **************************************************************
	public TwitterSearch(String _consumer_key, String _consumer_secret,
			String _token, String _secret) {
		this._consumer_key = _consumer_key;
		this._consumer_secret = _consumer_secret;
		this._token = _token;
		this._secret = _secret;
	}

	// **************************************************************
	// AsyncTask の onPostExecute から外部イベントとして呼び出す為のインターフェイス
	// **************************************************************
	public interface Searched {
		public void onSearchResult(String result);
   	}
	
	// **************************************************************
	// Twitter 投稿
	// **************************************************************
	public void Search(String query, int count, final Searched OnSearchResult) {
		
		new AsyncTask<String, Void, String>() {

			// **************************************************************
			// 非同期処理
			// **************************************************************
			@Override
			protected String doInBackground(String... params) {

				ArrayList<String> lst = new ArrayList<String>();
				String nonce = getNonce();
				String timeStamp = getTimeStamp();
				String result_string = "";
				try {
				
					// *********************************
					// 投稿に必要なデータ (1)
					// *********************************
					lst.add("count=" + params[1]);
					lst.add("oauth_consumer_key=" + _consumer_key);
					lst.add("oauth_nonce=" + nonce);
					lst.add("oauth_signature_method=" + "HMAC-SHA1");
					lst.add("oauth_timestamp=" + timeStamp);
					lst.add("oauth_token=" + _token);
					lst.add("oauth_version=1.0");				
					lst.add("q=" + rfc3986(URLEncoder.encode(params[0], "utf-8")));	

					Collections.sort(lst);
					
					String work = "";
					for(int i = 0; i < lst.size() ; i++ ){
						if ( i != 0 ) {
							work += "&";
						}
						work += lst.get(i);
					}
					
					// *********************************
					// 投稿に必要なデータ (2)
					// *********************************
					String work2 = "GET" + "&";
					// API のエントリポイント
					work2 += rfc3986(URLEncoder.encode(_tweet_api,"utf-8")) + "&";
					// 投稿に必要なデータ (1)
					work2 += rfc3986(URLEncoder.encode(work,"utf-8"));
					
					// *********************************
					// 投稿に必要なデータ (3)
					// *********************************
					String oauth_signature = getSignature(work2);
					
					// *********************************
					// 投稿に必要なデータ (4) / ヘッダ
					// *********************************
					String data = "oauth_consumer_key=" + dD(_consumer_key) +
						",oauth_nonce=" + dD(nonce) +
						",oauth_signature=" + dD(rfc3986(URLEncoder.encode(oauth_signature, "utf-8"))) +
						",oauth_signature_method=" + dD("HMAC-SHA1") +
						",oauth_timestamp=" + dD(timeStamp) +
						",oauth_token=" + dD(_token) +
						",oauth_version=" + dD("1.0");

					// 投稿先
					URL url = new URL(_tweet_api + "?q="
						+ rfc3986(URLEncoder.encode(params[0], "utf-8"))
						+ "&count=" + params[1]
					);

					// 接続準備
					HttpURLConnection http = (HttpURLConnection)url.openConnection();
					http.setConnectTimeout(30000);
					http.setReadTimeout(30000);
					http.setRequestMethod("GET");					
					// ヘッダ
					http.setRequestProperty("Authorization", "OAuth " + data);
					
					InputStreamReader isr = null;
					try {
						// 受信用ストリーム
						isr = new InputStreamReader(http.getInputStream(), "UTF-8");
					}
					catch( Exception e ) {
						isr = new InputStreamReader(http.getErrorStream(), "UTF-8");
					}
					
					// 受信
					BufferedReader br = new BufferedReader(isr);   
					String line_buffer;   
					while ( null != (line_buffer = br.readLine() ) ) {   
						// コマンドプロンプトに表示   
						result_string += line_buffer;
					}

					// 終了処理
					br.close();
					isr.close();
					http.disconnect();
				}
				catch( Exception e ) {
					result_string = "{\"errors\":\"unknown\"}"; 
				}
				
				return result_string;
			}

			// **************************************************************
			// 非同期処理終了後の処理( 画面へのアクセスが可能 )
			// **************************************************************
			@Override
			protected void onPostExecute(String result) {
				// Tweet メソッドの引数のインターフェイス内のメソッドを呼び出す
				OnSearchResult.onSearchResult(result);
			}
			
		}.execute(query,String.valueOf(count));
	
	}
	
	private String rfc3986( String param ) {
		param = param.replace("+", "%20");
		param = param.replace("*", "%2A");
		param = param.replace("%7E","~");
		return param;
	}
	
	private String dD(String param){
		return "\""+param+"\"";
	}

	private String getNonce(){
		Random random = new Random(); 
		return String.valueOf(random.nextInt(1000000000));
	}
	
	private String getTimeStamp(){
		return String.valueOf(System.currentTimeMillis() / 1000L);
	}		
	
	private String getSignature(String baseString){
		
		String work = "";
		work += _consumer_secret;
		work += "&";
		work += _secret;
		   
		String signature = "";
		SecretKeySpec key = new SecretKeySpec(work.getBytes(), "HmacSHA1");
		
		try {
			
			Mac mac = Mac.getInstance(key.getAlgorithm());
			try{
				mac.init(key);
			} catch(InvalidKeyException ike){
			}
			
			byte[] rawHmac = mac.doFinal(baseString.getBytes());
			signature = new String (Base64.encodeToString(rawHmac, Base64.NO_WRAP));
			
		} catch(NoSuchAlgorithmException e){
		}
		
		return signature;
	}
	
}

※ リストビューの処理(MyListview.java)
ソース全体


posted by lightbox at 2013-10-13 20:19 | Android | このブログの読者になる | 更新情報をチェックする

2013年10月12日


トラブル : AndroidManifest.xml に XML 宣言があるとエラーになる???

ちょっと前に作ったプロジェクトが動かなくなったので、現在動作中のプロジェクトと比べてみると、動いているほうには XML 宣言がありません・・・・。

Android ドキュメントの The AndroidManifest.xml File には、XML 宣言あるんですけれど・・・
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.posttest"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.posttest.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name="NextPage">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
            </intent-filter>
        </activity>
	</application>

</manifest>
1行目を削除すると動いてくれます。

ですが、わけが解らないのでいろいろ更新をかけていくうちに・・・・Eclipse の Android 部分が動かなくなりました。

なもんで、Google より最新版をダウンロードして日本語化して Window Builder をインストールしました。

Android は、4.3 になったので、AndroidManifest.xml の android:targetSdkVersion="17" を android:targetSdkVersion="18" に変えて動作確認しました。

※ 以下はプロジェクトのプロパティの変更です。


※ ようこそがちょっと違う???


関連する記事ADT( Android Development Tools ) Eclipse の導入(日本語化手順はこの中)
■ ADT( Android Development Tools ) Eclipse に Window Builder をインストールして Swing アプリケーションを作成する(1)ADT( Android Development Tools ) Eclipse に Window Builder をインストールして Swing アプリケーションを作成する(2)

結局今は、どちらの AndroidManifest.xml でも動作しています(なにがなんだか)。



最新の ADT の Eclipse は、特に変わらず Juno でした。
『.eclipseproduct』
name=Eclipse Platform
id=org.eclipse.platform
version=4.2.0


posted by lightbox at 2013-10-12 20:19 | Android | このブログの読者になる | 更新情報をチェックする

Twitter API の自分のアプリのトークンを使って投稿するだけの class Android_Twitter

更新履歴
2013-07-11 : 初回投稿
2013-08-24 : Twitter がエラーを返す場合は、getErrorStream を使う必要があったので修正
2013-10-12 : rfc3986 内部メソッドを追加( やはりきっちりしないとエラーになりました )

Twitter がエラーを返す場合( 例えば投稿データか空の場合 )は、getInputStream では無く getErrorStream を使わないと、エラー内容が取得できなかったので修正しました
Android なので、非同期処理は AsyncTask です。クラスのメソッド内で匿名のインナー型を使用して実装しています。終了時のイベントは、専用のインターフェイスを作成して、onPostExecute から呼び出しています。 Android_Twitter.java
package com.example.posttest;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import android.os.AsyncTask;
import android.util.Base64;
import android.widget.EditText;

public class Android_Twitter {

	// AsyncTask のインラインで参照する為の final
	private final String _consumer_key;
	private final String _consumer_secret;
	private final String _token;
	private final String _secret;

	// API
	private final String _tweet_api = "https://api.twitter.com/1.1/statuses/update.json";
	
	// **************************************************************
	// コンストラクタ
	// **************************************************************
	public Android_Twitter(String _consumer_key, String _consumer_secret,
			String _token, String _secret) {
		this._consumer_key = _consumer_key;
		this._consumer_secret = _consumer_secret;
		this._token = _token;
		this._secret = _secret;
	}

	// **************************************************************
	// AsyncTask の onPostExecute から外部イベントとして呼び出す為のインターフェイス
	// **************************************************************
	public interface Tweeted {
		public void onTweetResult(String result);
   	}
	
	// **************************************************************
	// Twitter 投稿
	// **************************************************************
	public void Tweet(String text, final Tweeted OnTweetResult) {
		
		new AsyncTask<String, Void, String>() {

			// **************************************************************
			// 非同期処理
			// **************************************************************
			@Override
			protected String doInBackground(String... params) {

				ArrayList<String> lst = new ArrayList<String>();
				String nonce = getNonce();
				String timeStamp = getTimeStamp();
				String result_string = "";
				try {
				
					// *********************************
					// 投稿に必要なデータ (1)
					// *********************************
					lst.add("oauth_consumer_key=" + _consumer_key);
					lst.add("oauth_nonce=" + nonce);
					lst.add("oauth_signature_method=" + "HMAC-SHA1");
					lst.add("oauth_timestamp=" + timeStamp);
					lst.add("oauth_token=" + _token);
					lst.add("oauth_version=1.0");				
					lst.add("status=" + rfc3986(URLEncoder.encode(params[0], "utf-8")));	

					Collections.sort(lst);
					
					String work = "";
					for(int i = 0; i < lst.size() ; i++ ){
						if ( i != 0 ) {
							work += "&";
						}
						work += lst.get(i);
					}
					
					// *********************************
					// 投稿に必要なデータ (2)
					// *********************************
					String work2 = "POST" + "&";
					// API のエントリポイント
					work2 += rfc3986(URLEncoder.encode(_tweet_api,"utf-8")) + "&";
					// 投稿に必要なデータ (1)
					work2 += rfc3986(URLEncoder.encode(work,"utf-8"));
					
					// *********************************
					// 投稿に必要なデータ (3)
					// *********************************
					String oauth_signature = getSignature(work2);
					
					// *********************************
					// 投稿に必要なデータ (4) / ヘッダ
					// *********************************
					String data = "oauth_consumer_key=" + dD(_consumer_key) +
						",oauth_nonce=" + dD(nonce) +
						",oauth_signature=" + dD(rfc3986(URLEncoder.encode(oauth_signature, "utf-8"))) +
						",oauth_signature_method=" + dD("HMAC-SHA1") +
						",oauth_timestamp=" + dD(timeStamp) +
						",oauth_token=" + dD(_token) +
						",oauth_version=" + dD("1.0");

					// 投稿先
					URL url = new URL(_tweet_api);

					// 接続準備
					HttpURLConnection http = (HttpURLConnection)url.openConnection();
					http.setConnectTimeout(30000);
					http.setReadTimeout(30000);
					http.setDoInput(true);
					// ヘッダ
					http.setRequestProperty("Authorization", "OAuth " + data);
					http.setRequestMethod("POST");					

					// 送信用ストリーム
					OutputStreamWriter osw = new OutputStreamWriter(http.getOutputStream());
					BufferedWriter bw = new BufferedWriter(osw);
					
					// 送信データの書き込み
					bw.write("status=" + rfc3986(URLEncoder.encode(params[0], "utf-8")));
					bw.close();
					osw.close();
					
					InputStreamReader isr = null;
					try {
					// 受信用ストリーム
						isr = new InputStreamReader(http.getInputStream(), "UTF-8");
					}
					catch( Exception e ) {
						isr = new InputStreamReader(http.getErrorStream(), "UTF-8");
					}
					
					// 受信
					BufferedReader br = new BufferedReader(isr);   
					String line_buffer;   
					while ( null != (line_buffer = br.readLine() ) ) {   
						// コマンドプロンプトに表示   
						result_string += line_buffer;
					}

					// 終了処理
					br.close();
					isr.close();
					http.disconnect();
				}
				catch( Exception e ) {
					result_string = "{\"errors\":\"unknown\"}"; 
				}
				
				return result_string;
			}

			// **************************************************************
			// 非同期処理終了後の処理( 画面へのアクセスが可能 )
			// **************************************************************
			@Override
			protected void onPostExecute(String result) {
				// Tweet メソッドの引数のインターフェイス内のメソッドを呼び出す
				OnTweetResult.onTweetResult(result);
			}
			
		}.execute(text);
	
	}
	
	private String rfc3986( String param ) {
		param = param.replace("+", "%20");
		param = param.replace("*", "%2A");
		param = param.replace("%7E","~");
		return param;
	}
	
	private String dD(String param){
		return "\""+param+"\"";
	}

	private String getNonce(){
		Random random = new Random(); 
		return String.valueOf(random.nextInt(1000000000));
	}
	
	private String getTimeStamp(){
		return String.valueOf(System.currentTimeMillis() / 1000L);
	}		
	
	private String getSignature(String baseString){
		
		String work = "";
		work += _consumer_secret;
		work += "&";
		work += _secret;
		   
		String signature = "";
		SecretKeySpec key = new SecretKeySpec(work.getBytes(), "HmacSHA1");
		
		try {
			
			Mac mac = Mac.getInstance(key.getAlgorithm());
			try{
				mac.init(key);
			} catch(InvalidKeyException ike){
			}
			
			byte[] rawHmac = mac.doFinal(baseString.getBytes());
			signature = new String (Base64.encodeToString(rawHmac, Base64.NO_WRAP));
			
		} catch(NoSuchAlgorithmException e){
		}
		
		return signature;
	}

}

処理が完了すると、onTweetResult が実行されます。

MainActivity.java
package com.example.posttest;

import com.example.posttest.Android_Twitter.Tweeted;

import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.widget.EditText;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

	public void postAction(View view) {
		
		EditText et = (EditText)this.findViewById(R.id.editText1);
		
		new Android_Twitter(
                    "Consumer key",
                    "Consumer secret",
                    "Access token",
                    "Access token secret").Tweet(et.getText().toString(), new Tweeted() {
			
			@Override
			public void onTweetResult(String result) {
				System.out.println(result);
			}
		});

	}
   
}

関連する記事

Twitter API の自分のアプリのトークンを使って投稿するだけの class VS2010_Twitter

Twitter API の自分のアプリのトークンを使って投稿するだけの class VS2012_Twitter

WSH : VBScript と JavaScript で Twitter に投稿する

PHP : Twitter 投稿関数( twitter_update ) / cURL 関数

Twitter アプリの登録方法と、API キーの利用



タグ:twitter API
posted by lightbox at 2013-10-12 17:39 | Android | このブログの読者になる | 更新情報をチェックする

2013年09月28日


Android 単純リストビューを google-gson で最速構築



このままでは使い物にはなりませんが、基本コードとしてのテンプレートになります。ですから、この後、ListView と Gson 用クラスををカスタマイズして項目を増やしていくだけでリストビューの部分の作成は容易になります。
package com.example.listviewobjectjson;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.List;

import com.google.gson.Gson;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

public class MyListview extends Activity {
	
	private Gson gson = null;
	private WebGet task;
	private JSON_STRING js;
	private ArrayAdapter<MyObject> basicAdapter;
	
	// ************************************************************
	// Android 用初期処理
	// ************************************************************
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_my_listview);

		Button button = (Button) findViewById(R.id.button1);
		button.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				// AsyncTask に引数を与えて呼び出す
				// 1) doInBackground, 2) onProgressUpdate, 3) onPostExecute
				task = new WebGet();
				task.execute( "http://10.0.2.2/lightbox/php_json/log.php" );
			}
		});
 	}
	
	// ************************************************************
	// Android 用非同期処理
	// ************************************************************
	private class WebGet extends AsyncTask<String, String, String> {
		
		// ここは使っていません
		@Override
		protected void onPreExecute() {
			super.onPreExecute();
		}
		
		// *******************************************************
		// UI スレッド側の処理 ( 引数は JSON 文字列 )
		// *******************************************************
		@Override
		protected void onPostExecute(String result) {
			// UI スレッドとして処理される
			System.out.println(result);

			// gson インスタンス
			gson = new Gson();
			
			// JSON を クラスインスタンスに変換
			js = gson.fromJson(result,JSON_STRING.class);
			
			// js.item は List<MyObjecyt>
			basicAdapter = new ArrayAdapter<MyObject>(
					MyListview.this,
					R.layout.textview,
					js.item
			);
			
			// リストビューにアダプタをセット
			ListView listView = (ListView)MyListview.this.findViewById(R.id.listView1);
			listView.setAdapter(basicAdapter);			

		}

		// *******************************************************
		// 非同期スレッドの呼び出し
		// *******************************************************
		@Override
		protected String doInBackground(String... aurl) {

			Log.i("MyListview2:","開始");
			String json_string = "";

			try {

				// 引数の URL を使用して実行
				URL url = new URL(aurl[0]);
				// 接続オブジェクト( getInputStream をする為のもの )
				HttpURLConnection http = (HttpURLConnection)url.openConnection();
				http.setConnectTimeout(30000);
				http.setReadTimeout(30000);
				http.setRequestMethod("GET");
				
				// 以下読み込み3セット
				InputStream i_stream = http.getInputStream();
				// UTF-8 でリーダーを作成
				InputStreamReader i_stream_reader = new InputStreamReader(i_stream, "UTF-8");
				// 行単位で読み込む為の準備   
				BufferedReader b_reader = new BufferedReader(i_stream_reader);
				
				// 行の一括読みこみ
				String line_buffer;   
				// BufferedReader は、readLine が null を返すと読み込み終了 
				while ( null != (line_buffer = b_reader.readLine() ) ) {   
					// コマンドプロンプトに表示   
					json_string += line_buffer;
				}
	 
				// 後処理
				b_reader.close();
				i_stream_reader.close();
				i_stream.close();

				http.disconnect();
			}
			catch (Exception e) {
				e.printStackTrace();
			}
			
			// JSON 文字列を onPostExecute に対して送る
			return json_string;
		}

	}	
	
	// ************************************************************
	// GSON で使う為の JSON 文字列の構造を定義したクラス
	// ************************************************************
	private class JSON_STRING {
		List<MyObject> item;
	}

	private class MyObject {
		String text;
		
		// 単純リストビューなので、toString で 内容を返すようにしておく
		public String toString() {
			return this.text;
		}
	}
	
	// ************************************************************
	// メニュー( 未使用 )
	// ************************************************************
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.activity_my_listview, menu);
		return true;
	}
}


関連する記事

Android をテストするのにほんの少し楽になるかもしれないクラス
( このクラスでもう少しコードがすっきりします )



posted by lightbox at 2013-09-28 23:19 | Android | このブログの読者になる | 更新情報をチェックする

2013年09月14日


Android をテストするのにほんの少し楽になるかもしれないクラス



例えばここでテストしたいのは、Twitter の投稿なのですが、そのたびに一からイベントやらキャストやらファイル読み書きとか面倒なので作りました。
2013-09-12 : 初回投稿
2013-09-14 : ダイアログ処理とラベル(TextView)処理を追加しました
メソッドの引数でクラスのオブジェクトが必要なところで new と 入力して CTRL+SPACE で Eclipse が匿名のインナー型の候補を出してくれる事を期待しています。
util.buttonClick(R.id.button1, new OnClickListener() {
			
	@Override
	public void onClick(View v) {
		// TODO 自動生成されたメソッド・スタブ
				
	}
});
util. と 最後のセミコロンを除いて、殆ど Eclipse が候補を出してくれます。 Util.java
package com.example.textfile;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Calendar;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.app.DatePickerDialog.OnDateSetListener;
import android.content.DialogInterface;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class Util {
	
	public Activity cur = null;
	public final Calendar c = Calendar.getInstance();
	public final int year = c.get(Calendar.YEAR);
	public final int month = c.get(Calendar.MONTH);
	public final int day = c.get(Calendar.DAY_OF_MONTH);

	public Util(Activity ma) {
		cur = ma;
	}
	
	// ******************************************
	// その他
	// ******************************************
	public void toast(String message) {
        Toast.makeText(cur, message, Toast.LENGTH_LONG).show();    	
	}
	
	// ******************************************
	// 入力
	// ******************************************
	public String getFieldStr(int id) {
		
		return ((EditText)cur.findViewById(id)).getText().toString();
		
	}
	public void setFieldStr(int id,String text) {
		
		((EditText)cur.findViewById(id)).setText(text);
		
	}

	// ******************************************
	// ラベル
	// ******************************************
	public String getViewStr(int id) {
		
		return ((TextView)cur.findViewById(id)).getText().toString();
		
	}
	public void setViewStr(int id,String text) {
		
		((TextView)cur.findViewById(id)).setText(text);
		
	}
	
	// ******************************************
	// ボタン
	// ******************************************
	public Button getButton(int id) {

		return (Button) cur.findViewById(id);

	}
	public void buttonClick(int id,OnClickListener I) {

		((Button) cur.findViewById(id)).setOnClickListener(I);

	}
	
	// ******************************************
	// テキストファイル
	// ******************************************
	public void saveText( String name, String text) throws Exception  {
        
		FileOutputStream outStream = cur.openFileOutput(name, android.content.Context.MODE_PRIVATE);
        OutputStreamWriter writer = new OutputStreamWriter(outStream);
		writer.write(text);
        writer.flush();
        writer.close();
		
	}
	public String getText( String name ) throws Exception {
		
        FileInputStream fis = cur.openFileInput(name);
        int size = fis.available();
        InputStreamReader isr = new InputStreamReader( fis );
        BufferedReader br = new BufferedReader(isr);
        StringBuffer all_string = new StringBuffer( size ); 
        String str;
        while((str = br.readLine()) != null){
        	all_string.append(str);
        }
        br.close();
        
        return all_string.toString();
		
	}
	
	// ******************************************
	// ダイアログ
	// ******************************************
	public DatePickerDialog dateDialog(OnDateSetListener listener) {
	
			return new DatePickerDialog(cur,listener,year,month,day);
			
	}
	
	public AlertDialog messageBox(String title,String message,DialogInterface.OnClickListener onClickListener1,DialogInterface.OnClickListener onClickListener2) {

		AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(cur);
		alertDialogBuilder.setTitle(title);
		alertDialogBuilder.setMessage(message);
		
		alertDialogBuilder.setPositiveButton("YES",onClickListener1);
		alertDialogBuilder.setNegativeButton("NO", onClickListener2);
		alertDialogBuilder.setCancelable(true);

		return alertDialogBuilder.create();
		
	}

}


MainActivity.java
package com.example.textfile;

import com.example.textfile.Android_Twitter.Tweeted;

import android.os.Bundle;
import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.DatePickerDialog.OnDateSetListener;
import android.content.DialogInterface;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.DatePicker;

public class MainActivity extends Activity {

	private Util util = new Util( this );
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // ボタンイベント
        util.buttonClick(R.id.button1,new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				
				// Twitter 投稿
				new Android_Twitter(
					"",
					"",
					"",
					"").Tweet(
							util.getFieldStr(R.id.editText1), new Tweeted() {
			
					// 投稿結果
					@Override
					public void onTweetResult(String result) {
						try {
							// 内部ストレージへのファイル保存
							util.saveText("json.txt", result);
						}
						catch( Exception ex ) {
							ex.printStackTrace();
						}
					}
		        });    	

				// メッセージ
				util.toast("投稿しました!!");
				
			}
		});

        // 初期処理として、内部ストレージから文字列を取得
        try{
            util.setFieldStr(R.id.editText1, util.getText("file1.txt"));
        }
        catch(Exception ex){
			ex.printStackTrace();
        }
        
        // ボタンイベント
        util.buttonClick(R.id.button2, new OnClickListener() {
			
			@Override
			public void onClick(View v) {

				// 日付ダイアログ
				util.dateDialog(new OnDateSetListener() {
					
					@Override
					public void onDateSet(DatePicker view, int year, int monthOfYear,
							int dayOfMonth) {

						// 結果を表示
						util.setViewStr(R.id.textView1, year + "/" + (monthOfYear+1)+"/"+dayOfMonth);
						
					}
				}).show();	// 表示
				
			}
		});

        // ホダンイベント
        util.buttonClick(R.id.button3, new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				
				// 選択肢応答ダイアログ
				util.messageBox("メッセージボックス", "Yes または No による選択処理",
						// YES の処理
						new DialogInterface.OnClickListener() {
					
							@Override
							public void onClick(DialogInterface dialog,
									int which) {
								System.out.println("YES");
								
							}
							
						},
						// NO の処理
						new DialogInterface.OnClickListener() {

							@Override
							public void onClick(DialogInterface dialog,
									int which) {
								System.out.println("NO");
								
							}
						}
				).show();	// 表示
			}
		});
    }

    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
    
}



posted by lightbox at 2013-09-14 16:33 | Android | このブログの読者になる | 更新情報をチェックする

2013年08月31日


Android : Google Spreadsheets API version 3.0でGoogleスプレッドシートを参照

SkyDrive へ移動



Google のライブラリのダウンロード

gdata-java-client

かなり多くのライブラリが中に入っていますが、実際使うのは 5つです。

1) gdata-client-1.0.jar
2) gdata-core-1.0.jar
3) gdata-spreadsheet-3.0.jar
4) guava-11.0.2.jar
5) jsr305.jar

1〜3 は、lib ディレクトリ内で、4〜5 は、deps 内です。Google 的には、gdata を使うのは spreadsheet のみのようで、他の機能( 例えばカレンダー ) は他の API を使うようになっています。また、認証も本来は OAuth を推奨しているようですが、機能の説明に重点を置くために、簡単にユーザーとパスワードのログインで処理しています。


package com.example.posttest;

import java.net.URL;
import java.util.List;

import com.google.gdata.client.spreadsheet.*;
import com.google.gdata.data.spreadsheet.*;
import com.google.gdata.util.*;

import android.os.AsyncTask;
import android.widget.EditText;

public class Android_Spreadsheet {

	// AsyncTask のインラインで参照する為の final
	private final String _userid;
	private final String _password;

	// **************************************************************
	// コンストラクタ
	// **************************************************************
	public Android_Spreadsheet(String _userid, String _password) {
		this._userid = _userid;
		this._password = _password;
	}

	// **************************************************************
	// AsyncTask の onPostExecute から外部イベントとして呼び出す為のインターフェイス
	// **************************************************************
	public interface SendMailed {
		public void onTweetResult(List<CellEntry> result);
   	}
	
	// **************************************************************
	// 通信処理
	// **************************************************************
	public void GetCells(String FileName, String SheetName,final SendMailed OnTweetResult) {
		
		new AsyncTask<String, Void, List<CellEntry>>() {

			// **************************************************************
			// 非同期処理
			// **************************************************************
			@Override
			protected List<CellEntry> doInBackground(String... params) {
				
				List<CellEntry> cells = null;

				String result_string = "";
				try {
					
					// *************************************************
					// ClientLogin
					// *************************************************
				    String USERNAME = _userid;
				    String PASSWORD = _password;

				    SpreadsheetService service = new SpreadsheetService("MySpreadsheetIntegration-v1");
				    service.setUserCredentials(USERNAME, PASSWORD);
				    
					// *************************************************
				    // バージョン3
					// *************************************************
				    SpreadsheetService sss = new SpreadsheetService("MySpreadsheetIntegration");
				    sss.setProtocolVersion(SpreadsheetService.Versions.V3);
				    
					// *************************************************
				    // 一覧を取得
					// *************************************************
				    URL SPREADSHEET_FEED_URL = new URL(
				        "https://spreadsheets.google.com/feeds/spreadsheets/private/full");
				    SpreadsheetFeed feed = service.getFeed(SPREADSHEET_FEED_URL, SpreadsheetFeed.class);
				    // 一覧用のリスト
				    List<SpreadsheetEntry> spreadsheets = feed.getEntries();
				    
				    // スプレッドシート一覧より目的のインデックスを取得
				    int target = 0;
				    for (SpreadsheetEntry Spreadsheet : spreadsheets) {

				    	System.out.println( Spreadsheet.getTitle().getPlainText() );
				    	
				    	if ( Spreadsheet.getTitle().getPlainText().equals(params[0]) ) {
				    		break; 
				    	}
				    	
				    	target++;
				    	
				    }				    
				    

				    SpreadsheetEntry spreadsheet = spreadsheets.get(target);
				    WorksheetFeed worksheetFeed = service.getFeed(
					        spreadsheet.getWorksheetFeedUrl(), WorksheetFeed.class);
				    List<WorksheetEntry> worksheets = worksheetFeed.getEntries();

				    target = 0;
				    for (WorksheetEntry worksheet : worksheets) {

				    	System.out.println( worksheet.getTitle().getPlainText() );
				    	
				    	if ( worksheet.getTitle().getPlainText().equals(params[1]) ) {
				    		break; 
				    	}
				    	
				    	target++;
				    	
				    }				    
				    
				    WorksheetEntry worksheet = worksheets.get(target);

				    URL cellFeedUrl = worksheet.getCellFeedUrl();
				    CellFeed cellFeed = service.getFeed(cellFeedUrl, CellFeed.class);
				    cells = cellFeed.getEntries();
					
				}
				catch( Exception e ) {
					System.out.println(e.getMessage());
				}
				
				return cells;
			}

			// **************************************************************
			// 非同期処理終了後の処理( 画面へのアクセスが可能 )
			// **************************************************************
			@Override
			protected void onPostExecute(List<CellEntry> result) {
				// 引数のインターフェイス内のメソッドを呼び出す
				OnTweetResult.onTweetResult(result);
			}
			
		}.execute(FileName,SheetName);
	
	}

}

スプレッドシートの一覧や、シートの一覧等、それぞれで通信処理をするので、Android では AsyncTask を用いて全て一括で処理を行って、最後の一覧のみを終了イベントとして処理するようにしています。

package com.example.posttest;

import java.net.URL;
import java.util.List;

import com.example.posttest.Android_Spreadsheet;
import com.google.gdata.data.spreadsheet.CellEntry;
import com.google.gdata.data.spreadsheet.CellFeed;
import com.google.gdata.data.spreadsheet.SpreadsheetEntry;
import com.google.gdata.data.spreadsheet.WorksheetEntry;
import com.google.gdata.data.spreadsheet.WorksheetFeed;

import android.os.Bundle;
import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;

public class MainActivity extends Activity {

	private Android_Spreadsheet as = null;
	private ArrayAdapter<String> adapter = null;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		as = new Android_Spreadsheet(
			"", // アカウント
			"" // パスワード
			);
		
		adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1);
		
	}

	public void postAction(View view) {
		
	    
	    new MessageBox(this,"確認","送信しますか?") {

			@Override
			void onYesClick(DialogInterface dialog, int which) {

				System.out.println("onYesClick");
				
				as.GetCells( "In Googleドライブ", "シート2" ,new Android_Spreadsheet.SendMailed() {
					
						@Override
						public void onTweetResult(List<CellEntry> result) {
							
							ListView listView = (ListView)MainActivity.this.findViewById(R.id.listView1);
							listView.setAdapter(adapter);
							
						    for (CellEntry cell : result) {
						    	
						    	adapter.add( cell.getCell().getValue().toString() );
						    	// System.out.println( cell.getCell().getValue().toString() );
						    	
						    }				    
						    
						}
				});
				
			}
			
		}.show();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		
		// 選択されたメニュー項目の ID
		int menuId = item.getItemId();
		
		switch(menuId){
		case R.id.action_settings:
			System.out.println("action_settings が選択されました");
			break;
		case R.id.menu_action1:
			System.out.println("menu_action1  が選択されました");
			
			Intent intent = new Intent();
			intent.putExtra("data", "メッセージを別のページに引き渡します");
			intent.setClassName("com.example.posttest", "com.example.posttest.NextPage");
			startActivity(intent);		
			
			break;
		}

		return true;
	}		
	
}




posted by lightbox at 2013-08-31 01:10 | Android | このブログの読者になる | 更新情報をチェックする
Seesaa の各ページの表示について
Seesaa の 記事がたまに全く表示されない場合があります。その場合は、設定> 詳細設定> ブログ設定 で 最新の情報に更新の『実行ボタン』で記事やアーカイブが最新にビルドされます。

Seesaa のページで、アーカイブとタグページは要注意です。タグページはコンテンツが全く無い状態になりますし、アーカイブページも歯抜けページはコンテンツが存在しないのにページが表示されてしまいます。

また、カテゴリページもそういう意味では完全ではありません。『カテゴリID-番号』というフォーマットで表示されるページですが、実際存在するより大きな番号でも表示されてしまいます。

※ インデックスページのみ、実際の記事数を超えたページを指定しても最後のページが表示されるようです

対処としては、このようなヘルプ的な情報を固定でページの最後に表示するようにするといいでしょう。具体的には、メインの記事コンテンツの下に『自由形式』を追加し、アーカイブとカテゴリページでのみ表示するように設定し、コンテンツを用意するといいと思います。


※ エキスパートモードで表示しています

アーカイブとカテゴリページはこのように簡単に設定できますが、タグページは HTML 設定を直接変更して、以下の『タグページでのみ表示される内容』の記述方法で設定する必要があります

<% if:page_name eq 'archive' -%>
アーカイブページでのみ表示される内容
<% /if %>

<% if:page_name eq 'category' -%>
カテゴリページでのみ表示される内容
<% /if %>

<% if:page_name eq 'tag' -%>
タグページでのみ表示される内容
<% /if %>
この記述は、以下の場所で使用します
container 終わり



フリーフォントで簡単ロゴ作成
フリーフォントでボタン素材作成
フリーフォントで吹き出し画像作成
フリーフォントではんこ画像作成
ほぼ自由に利用できるフリーフォント
フリーフォントの書体見本とサンプル
画像を大きく見る為のウインドウを開くボタンの作成

CSS ドロップシャドウの参考デモ
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり