SQLの窓

2016年12月05日


Android Studio で Twitter4J で ListView に検索結果を表示する



Twitter4J

非同期処理は、常に TwitterListener を作成して、AsyncTwitter からの実行を リスナー側で受けるという形になります。( 今回の場合、searched(QueryResult queryResult) で受けて、search(Query query) で呼び出す )

関連する記事

Android Studio で Twitter4J で画像付きツイート

注意する事
1) トークンの保存場所が、app\src\main\resources の twitter4j.properties

2) TwitterListener で受けたところから画面にアクセスするには、UI スレッドに対する考慮が必要
   ( runOnUiThread メソッドが簡単 )

3) ライブラリは twitter4j-core-4.0.4.jar と twitter4j-async-4.0.4.jar をコピーして core のみ Gradle に登録
MainActivity
public class MainActivity extends AppCompatActivity {

    // リストビュー
    private MyArrayAdapter adapter;
    private ListView listview;

    // 日付データ用
    private Calendar cal;
    private SimpleDateFormat sf;

    // Twitter 用
    private TwitterListener listener;
    private AsyncTwitter asyncTwitter;
    private ArrayList<TwitterData> twitterData;

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


        // アダプタを作成
        adapter = new MyArrayAdapter(MainActivity.this,R.layout.list_item);

        // リストビューの取得
        listview = (ListView) MainActivity.this.findViewById(R.id.listView);
        // リストビューにデータを表示
        listview.setAdapter(adapter);

        Button buttonSearch = (Button) MainActivity.this.findViewById(R.id.buttonSearch);
        buttonSearch.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                adapter.clear();
                loadDataList();
            }
        });

        cal = Calendar.getInstance();
        sf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        // リスナーを作成する
        listener = new TwitterAdapter() {
            @Override
            public void searched(QueryResult queryResult) {

                twitterData = new ArrayList<TwitterData>();
                List<Status> list = queryResult.getTweets();

                Iterator<Status> it = list.iterator();
                while( it.hasNext() ) {

                    Status statudData = it.next();

                    twitterData.add(new TwitterData(
                        // ScreenName と Name
                        String.format("%s : %s", statudData.getUser().getScreenName(), statudData.getUser().getName()),
                        sf.format(statudData.getCreatedAt()),
                        statudData.getText()));

                }

                // UI スレッドで アダプタにデータをセット
                MainActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        adapter.addAll(twitterData);
                    }
                });


            }

            @Override
            public void onException(TwitterException te, TwitterMethod method) {

                Log.i("lightbox", "onException");
                te.printStackTrace();

            }

        };

        // リスナーを登録する
        AsyncTwitterFactory factory = new AsyncTwitterFactory();
        asyncTwitter = factory.getInstance();
        asyncTwitter.addListener(listener);

    }

    // *****************************************
    // Twitter から リストビューにデータを表示
    // *****************************************
    public void loadDataList() {

        EditText editSearch = (EditText) MainActivity.this.findViewById(R.id.editSearch);
        String searchString = editSearch.getText().toString();

        Query query = new Query(searchString);
        asyncTwitter.search(query);


    }
}


MyArrayAdapter
public class MyArrayAdapter extends ArrayAdapter<TwitterData> {

	// コンストラクタで渡された画面の保存
	private int mResource;
	// 画面作成用
	LayoutInflater mInflater;

	public MyArrayAdapter(Context context, int resource) {
		super(context, resource);
		// ArrayAdapter でも、このようにして保存して利用してます
		mResource = resource;
		mInflater = LayoutInflater.from(context);
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {

		if (convertView == null) {
			convertView = mInflater.inflate(mResource, parent, false);
		}

		// アダプターより行データを取得
		TwitterData twitterData = MyArrayAdapter.this.getItem(position);

		// 画面にデータをセット
		TextView tv;

		// キー
		tv = (TextView) convertView.findViewById(R.id.textKey);
		tv.setText(twitterData.getScreenName());

		tv	= (TextView) convertView.findViewById(R.id.textItem1);
		tv.setText(twitterData.getStringDate());

		tv = (TextView) convertView.findViewById(R.id.textItem2);
		tv.setText(twitterData.getText());

		// 行の画面をシステムに返す
		return convertView;
	}

}


TwitterData
public class TwitterData {

	private String stringDate;
	private String screenName;
	private String text;

	public TwitterData(String screenName, String stringDate, String text) {
		this.screenName = screenName;
		this.stringDate = stringDate;
		this.text = text;
	}

	public String getScreenName() {
		return screenName;
	}

	public void setScreenName(String screenName) {
		this.screenName = screenName;
	}

	public String getStringDate() {
		return stringDate;
	}

	public void setStringDate(String stringDate) {
		this.stringDate = stringDate;
	}

	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}
}




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

2016年11月29日


Android Studio で Twitter4J で画像付きツイート

Twitter API は使用回数制限があるので、現在それほど魅力的なものではありませんが、BOT 的な使い道や、ログとして使うのならば、Java のサンプルとしては魅力的ではあると思います。特に、Twitter4J を使うと、いとも簡単にツイートは可能なのです。

ダウンロードしてインストール

ダウンロードリンクは Twitter4J にあります。解凍して Android Studio のプロジェクトの libs に twitter4j-core-4.0.4.jar と twitter4j-async-4.0.4.jar をコピーします。

この後、メニューから add as library でもかまいませんが、app の gradle が以下のようになればいいです
dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:22.2.1'
    compile files('libs/twitter4j-core-4.0.4.jar')

}

twitter4j-async-4.0.4.jar は非同期処理に必要ですが、gradle に記述する必要はありません。

ちなみに、他のライブラリを全てコピーするとエラーになります(たぶん内容が重複してるとかかもしれません)

設定ファイル

twitter4j.properties が必要です。場所は app\src\main\resources です。

エクスプローラから作成してテキストファイルを作成して、自分の Twitter から、右下の『開発』をクリックして、My Apps で アプリを作るか既存のアプリからトークンをコピペして twitter4j.properties に書き込むだけです

このへんは、Twitter の API を使った人なら常識の範疇ですが、初めてでもインターネットでたくさん紹介されているので問題は無いはずです。
debug=true
oauth.consumerKey=*********************
oauth.consumerSecret=******************************************
oauth.accessToken=**************************************************
oauth.accessTokenSecret=******************************************

実行コード

画像は、あらかじめ用意しておいてパスを取得しておきます。カメラを使用するなら、ギャラリーに登録までした後のパスをそのまま使えばいいし、一時的に使うだけなら後から削除でいいですね(もちろん終了イベント後に削除)

カメラを起点とした画像データの処理 / Android

配布ページのサンプルコードは、タイプミスがあるので注意

▼ 実行
				// 入力テキストを取得
				EditText editText = (EditText) rootView.findViewById(R.id.tweetText);
				String text = editText.getText().toString();

				// 入力なしなら、テキストを作成
				if ( text.trim().equals("") ) {
					Calendar cal = Calendar.getInstance();
					SimpleDateFormat sf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
					text = String.format( "%s %s", sf.format(cal.getTime()), "に Android からツイートしました");
				}
				// デバッグ用
				Log.i("lightbox",text);

				// 非同期のリスナーを作成
				TwitterListener listener = new TwitterAdapter() {
					@Override
					public void updatedStatus(Status status) {
						System.out.println("Successfully updated the status to [" +
							status.getText() + "].");
					}

					@Override
					public void onException(TwitterException te, TwitterMethod method) {
						if (method == TwitterMethod.UPDATE_STATUS) {
							te.printStackTrace();
						} else {
							throw new AssertionError("Should not happen");
						}
					}

				};

				// 非同期の準備
				AsyncTwitterFactory factory = new AsyncTwitterFactory();
				AsyncTwitter asyncTwitter = factory.getInstance();
				// リスナーを登録
				asyncTwitter.addListener(listener);

				// StatusUpdate ノインスタンスを作成
				// ※ 画像ツイートに必要
				StatusUpdate statusUpdate = new StatusUpdate(text);
				// 画像のファイルオブジェクト
				File file = new File( mainActivity.getimagePath() );
				// 画像を設定
				statusUpdate.media(file);

				// ツイート
				asyncTwitter.updateStatus(statusUpdate);


何故か非同期のサンプルが世の中に無かったですが、Android でツイートしようなんて思う人がたぶんもういないのでしょう( 殆どメリットや魅力が無いので )

updatedStatus イベント内の注意

この中は UI スレッドでは無いようなので、成功の後画面処理する場合は、適宜必要な UI スレッド呼び出しを実装します。

runOnUiThread( android.app.Activity )
UIスレッドで指定されたアクションを実行します。 現在のスレッドがUIスレッドの場合、アクションは直ちに実行されます。 現在のスレッドがUIスレッドでない場合、アクションはUIスレッドのイベントキューにポストされます。
posted by lightbox at 2016-11-29 20:10 | 2016 Android Studio | このブログの読者になる | 更新情報をチェックする

2016年11月08日


内部ストレージを起点とした画像データの処理 / Android


Uri => File => FileInputStream => Bitmap というルートもあります

ストレージから画像を ImageView に表示する

※ ファイル名やフォルダは既知である事を前提としています。
// *************************************
// パスの取得
// *************************************
String path = String.format(
	"%s/firebase/20161108_011922.jpg",
	Environment.getExternalStorageDirectory().getPath()
);

// *************************************
// ImageView
// *************************************
Bitmap image = null;
FileInputStream fis;
try {
	fis	= new FileInputStream(path);
	image = BitmapFactory.decodeStream(fis);
} catch (Exception e) {
	e.printStackTrace();
}

// 画像データが取得されていたら
if ( image != null ) {
	// imageView へ表示
	imageView.setImageBitmap(image);
}

パスから FileInputStream を作成して、BitmapFactory.decodeStream でビットマップに変換します。画像表示は ImageView の setImageBitmap です。

Bitmap を使用した画像の回転
// バイト配列を Bitmap に変換( 内容は既に jpeg )
Bitmap image1 = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
// 90度回転
int width = image1.getWidth();
int height = image1.getHeight();
Matrix matrix = new Matrix();
matrix.postRotate (90);
Bitmap image2 = Bitmap.createBitmap (image1, 0, 0, width, height, matrix, true);
(※参考) ImageView を使用して画像を回転

ギャラリーから画像を ImageView に表示する

ギャラリーから返されるのは、Uri です。Uri を直接使用する setImageURI を使用します。

setImageURI(null) は、キャッシュされないようにする効果が期待できると想像しています。
// ギャラリーの呼び出し
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
startActivityForResult(intent, 10);		// 10 は任意

// -------------------------------

// ギャラリーからの戻り
// ※ onActivityResult は MainActivity のメソッドです
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	super.onActivityResult(requestCode, resultCode, data);

	if (requestCode == 10 && resultCode == Activity.RESULT_OK) {
		if (data != null) {
			Uri uri = data.getData();
			imageView.setImageURI(null);
			imageView.setImageURI(uri);
		}

	}
}

(※参考) Exif情報を利用して、画像を回転

Firebase の putFile と putStream

どちらも大差はありません。アップロード前に加工が必要なら、putStream になるかもしれませんし、コードを簡潔にするには、putFile だと例外処理がありませんから、キャッシュに書き込んでからアップロードしてもいいかもしれません。
// *************************************
// FireBase putFile
// *************************************
Uri file = Uri.fromFile(new File(path));
imageRef = storageRef.child(file.getLastPathSegment());
UploadTask uploadTask = imageRef.putFile(file);
uploadTask.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
	@Override
	public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {

		Log.i("lightbox","アップロードに成功しました");
		long size = taskSnapshot.getMetadata().getSizeBytes();
		Log.i("lightbox",String.format("サイズ : %d",size));

	}
}).addOnFailureListener(new OnFailureListener() {
	@Override
	public void onFailure(@NonNull Exception e) {

		Log.i("lightbox","アップロードに失敗しました");
	}
});


// *************************************
// FireBase putStream
// *************************************
Uri file = Uri.fromFile(new File(path));
imageRef = storageRef.child(file.getLastPathSegment());
InputStream stream = null;
try {
	stream = new FileInputStream(new File(path));
} catch (Exception e) {
	e.printStackTrace();
}
if ( stream != null ) {
	UploadTask uploadTask = imageRef.putStream(stream);
	uploadTask.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
		@Override
		public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {

			Log.i("lightbox", "アップロードに成功しました");
			long size = taskSnapshot.getMetadata().getSizeBytes();
			Log.i("lightbox", String.format("サイズ : %d", size));

		}
	}).addOnFailureListener(new OnFailureListener() {
		@Override
		public void onFailure(@NonNull Exception e) {

			Log.i("lightbox", "アップロードに失敗しました");
		}
	});
}




posted by lightbox at 2016-11-08 13:54 | 2016 Android Studio | このブログの読者になる | 更新情報をチェックする
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 ドロップシャドウの参考デモ
BUTTONS (CSS でボタン)
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり