非同期処理、WebAPIの利用、XMLのパース
非同期処理が自分の中でボトルネックになっていたので、一回やってみた。
今回作ったものは、ATNDからイベントの情報を取得してリストに表示し、リストの中からイベントを選択すると、詳しい情報を表示するというモノ。
AsyncTaskActivity.java
package com.android.yamaguchi.AsyncTaskActivity;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import org.xmlpull.v1.XmlPullParser;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnCancelListener;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.util.Xml;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
//リストを表示するクティビティ
public class AsyncTaskActivity extends Activity implements OnItemClickListener{
private Context context=null;
ProgressDialog dialog;
/** アダプタ */
private MyArrayAdapter adapter = null;
private static int DATA_NUM=100;
int n=0;
//別のActivityにデータを渡すための定数
private static String START="start";
private static String END="end";
private static String UPDATE="update";
private static String TITLE="title";
private static String DESCRIPTION="description";
private static String EVENT_URL="event_url";
private static String OWNER_NICKNAME="owner_nickname";
private static String ADDRESS="address";
private static String PLACE="place";
private static String LIMIT="limit";
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//リストを表示
ListView listView=(ListView)findViewById(R.id.list);
listView.setScrollingCacheEnabled(false);
//アダプタ作成
adapter = new MyArrayAdapter(this);
listView.setOnItemClickListener(this);
listView.setAdapter(adapter);
//リストが空のときに表示されるViewを指定
listView.setEmptyView(findViewById(R.id.empty));
this.context=this;
//非同期処理を開始
new AdapterAsync().execute();
}
/*************************** AsyncTaskを継承したクラスを、内部クラスとして作成 ***********************/
class AdapterAsync extends AsyncTask implements OnCancelListener{
//↑これはdoInBackground、onProgressUpdate、onPostExecuteの
//引数と同じものを指定、と考えればよさそう。
//前処理。ここでプログレスバーの表示などを行う。
@Override
protected void onPreExecute() {
//プログレスバーを表示
dialog = new ProgressDialog(context);
dialog.setTitle("イベント情報を取得中");
dialog.setMessage("もう少しお待ち下さい...");
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setCancelable(true);
dialog.setOnCancelListener(this);
dialog.setMax(DATA_NUM);
dialog.setProgress(0);
dialog.show();
}
//非同期処理
@Override
protected Void doInBackground(Void... params) {
//String ornerTwitter="uni_labo";
//String kenmei="福井県";
final StringBuilder sb_query=new StringBuilder();
//final StringBuilder sb_return=new StringBuilder();
int eventType;
//int eventCount=0;
String start=null;
String end=null;
String update=null;
String title=null;
String description=null;
String event_url=null;
String owner_nickname=null;
String address=null;
String place=null;
String limit=null;
try {
XmlPullParser xmlPullParser = Xml.newPullParser();
//ATNDのAPIからXMLを取得する
sb_query.append("\""+URLEncoder.encode("福井県","UTF-8")+"\"");
sb_query.append(",");
sb_query.append("\""+URLEncoder.encode("京都府","UTF-8")+"");
String urlString="http://api.atnd.org/events/?keyword_or="+
new String(sb_query)+"&count="+DATA_NUM;
Log.v("XmlPullParserSampleUrl",urlString);
URL url = new URL(urlString);
URLConnection connection = url.openConnection();
xmlPullParser.setInput(connection.getInputStream(), "UTF-8");
/********************* XMLをパース ********************/
while *1 != XmlPullParser.END_DOCUMENT) {
//if文で分岐して、XMLから情報を取得。
if (eventType == XmlPullParser.START_TAG && "title".equals(xmlPullParser.getName())) {
title=xmlPullParser.nextText();
}
if (eventType == XmlPullParser.START_TAG && "description".equals(xmlPullParser.getName())) {
description=xmlPullParser.nextText();
}
if (eventType == XmlPullParser.START_TAG && "event_url".equals(xmlPullParser.getName())) {
event_url=xmlPullParser.nextText();
}
if (eventType == XmlPullParser.START_TAG && "owner_nickname".equals(xmlPullParser.getName())) {
owner_nickname=xmlPullParser.nextText();
}
if (eventType == XmlPullParser.START_TAG && "address".equals(xmlPullParser.getName())) {
address=xmlPullParser.nextText();
}
if (eventType == XmlPullParser.START_TAG && "place".equals(xmlPullParser.getName())) {
place=xmlPullParser.nextText();
}
if (eventType == XmlPullParser.START_TAG && "started_at".equals(xmlPullParser.getName())) {
start=xmlPullParser.nextText();
}
if (eventType == XmlPullParser.START_TAG && "ended_at".equals(xmlPullParser.getName())) {
end=xmlPullParser.nextText();
}
if (eventType == XmlPullParser.START_TAG && "updated_at".equals(xmlPullParser.getName())) {
update=xmlPullParser.nextText();
}
if (eventType == XmlPullParser.START_TAG && "limit".equals(xmlPullParser.getName())) {
limit=xmlPullParser.nextText();
}
//eventタグを抜けるときに、リストにアイテムを追加
if (eventType == XmlPullParser.END_TAG && "event".equals(xmlPullParser.getName())) {
/********** publishProgress()は、onProgressUpdateを呼び出す。onProgressUpdate内で
* UIの更新処理(リストへのアイテムの追加や、プログレスバーを更新)を行う。
* *************/
publishProgress(title,start,end,description,event_url,
owner_nickname,address,place,limit,update);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
/**
* UIスレッド上で起動
* UIの更新処理(リストへのアイテムの追加や、プログレスバーを更新)を行う。
*/
protected void onProgressUpdate(String... item) {
//↑可変長引数
//リストに追加するアイテムを作成
MyListViewItem myListViewItem = new MyListViewItem();
myListViewItem.title=item[0];
myListViewItem.started_at=item[1];
myListViewItem.ended_at=item[2];
myListViewItem.description=item[3];
myListViewItem.event_url=item[4];
myListViewItem.owner_nickname=item[5];
myListViewItem.address=item[6];
myListViewItem.place=item[7];
myListViewItem.limit=item[8];
myListViewItem.updated_at=item[9];
addItem(myListViewItem);
n++;
dialog.setProgress(n);
}
//後処理、プログレスバーを消したりする。
@Override
protected void onPostExecute(Void unused) {
dialog.dismiss();
}
@Override
public void onCancel(DialogInterface arg0) {
// TODO 自動生成されたメソッド・スタブ
this.cancel(true);
}
/*********************************** addItemメソッド **************************************/
public void addItem(MyListViewItem item) {
//追加
adapter.add(item);
}
@Override
protected void onCancelled() {
dialog.dismiss();
}
}
@Override
public void onItemClick(AdapterView listView, View view, int position, long id) {
// TODO 自動生成されたメソッド・スタブ
MyListViewItem item = adapter.getItem(position);
String startString="設定されていません";
if(item.started_at != null){
startString=item.started_at.substring(0,9)+":"+item.started_at.substring(11,19);
}
String endString="設定されていません";
Log.v("TEST","ended_at:"+item.ended_at);
if(item.ended_at != ""){
endString=item.ended_at.substring(0,9)+":"+item.ended_at.substring(11,19);
}
/******************* 説明文を表示するActivityを呼び出す。 *****************/
Intent i = new Intent();
//別Actibityに渡すデータを格納
i.putExtra(START, startString);
i.putExtra(END, endString);
i.putExtra(UPDATE, item.updated_at);
i.putExtra(TITLE, item.title);
i.putExtra(DESCRIPTION, item.description);
i.putExtra(EVENT_URL, item.event_url);
i.putExtra(OWNER_NICKNAME, item.owner_nickname);
i.putExtra(ADDRESS, item.address);
i.putExtra(PLACE, item.place);
i.putExtra(LIMIT, item.limit);
i.setClassName(
"com.android.yamaguchi.AsyncTaskActivity",
"com.android.yamaguchi.AsyncTaskActivity.ItemActivity");
startActivity(i);
}
}
イベントの説明文を表示するActivity
ItemActivity.java
package com.android.yamaguchi.AsyncTaskActivity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;
public class ItemActivity extends Activity{
TextView textViewTitle;
TextView textViewStarted_at;
TextView textViewEnded_at;
TextView textViewDescription;
TextView textViewEvent_url;
TextView textViewOwner_nickname;
TextView textViewAddress;
TextView textViewPlace;
TextView textViewLimit;
TextView textViewUpdate_at;
//別のActivityにデータを渡すための定数
private static String START="start";
private static String END="end";
private static String UPDATE="update";
private static String TITLE="title";
private static String DESCRIPTION="description";
private static String EVENT_URL="event_url";
private static String OWNER_NICKNAME="owner_nickname";
private static String ADDRESS="address";
private static String PLACE="place";
private static String LIMIT="limit";
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.item_activity);
textViewTitle=(TextView)findViewById(R.id.title);
textViewStarted_at=(TextView)findViewById(R.id.started_at);
textViewEnded_at=(TextView)findViewById(R.id.ended_at);
textViewDescription=(TextView)findViewById(R.id.description);
textViewEvent_url=(TextView)findViewById(R.id.event_url);
textViewOwner_nickname=(TextView)findViewById(R.id.owner_nickname);
textViewAddress=(TextView)findViewById(R.id.address);
textViewPlace=(TextView)findViewById(R.id.place);
textViewLimit=(TextView)findViewById(R.id.limit);
textViewUpdate_at=(TextView)findViewById(R.id.updated_at);
//説明文の取得
Intent i=getIntent();
textViewTitle.setText(i.getStringExtra(TITLE));
textViewOwner_nickname.setText("主催者名:"+i.getStringExtra(OWNER_NICKNAME));
textViewEvent_url.setText("イベントURL:"+i.getStringExtra(EVENT_URL));
textViewLimit.setText("定員:"+i.getStringExtra(LIMIT)+"\n");
textViewStarted_at.setText("開始時間:"+i.getStringExtra(START));
textViewEnded_at.setText("終了時間:"+i.getStringExtra(END));
textViewPlace.setText("開催場所:"+i.getStringExtra(PLACE));
textViewAddress.setText("住所:"+i.getStringExtra(ADDRESS)+"\n");
textViewDescription.setText(i.getStringExtra(DESCRIPTION)+"\n");
textViewUpdate_at.setText("更新日時:"+i.getStringExtra(UPDATE));
}
}
MyArrayAdapter.java
package com.android.yamaguchi.AsyncTaskActivity;
import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class MyArrayAdapter extends ArrayAdapter {
public MyArrayAdapter(Context context) {
super(context, R.layout.listview_item, R.id.item_text01);
// 第1引数 ... コンテキスト
// 第2引数 ... 表示するレイアウト
// 第3引数 ... 第2引数の中のTextView(何もしなければ、このTextViewにListViewItemのtoString()の結果が表示される)
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//基本的なことは親に任せる
View view = super.getView(position, convertView, parent);
//この時点でviewにはlistview_itemを生成したものが出来ている。
//TextViewはListViewItemのtoString()の結果が入っている。
// ※ここで取得されるViewは、リストのアイテムごとには生成されず、
// ListViewへ一度に表示されるアイテム数分のViewを使いまわすことになる点に注意
//アプリ独自の表示内容に書き換えるために、情報を取得。
MyListViewItem item = getItem(position);
if (item != null) {
//各コントロールを取得
TextView textView01 = (TextView) view.findViewById(R.id.item_text01);
TextView textView02 = (TextView) view.findViewById(R.id.item_text02);
textView01.setTextColor(Color.WHITE);
textView02.setTextColor(Color.WHITE);
if (textView01 != null && item.title != null) {
textView01.setText(item.title);
}
if (textView02 != null && item.started_at!= null) {
textView02.setText(item.started_at.substring(0, 9));
}
}
return view;
}
}
MyListViewItem.java
package com.android.yamaguchi.AsyncTaskActivity;
public class MyListViewItem {
public String title = null;
public String description=null;
public String event_url=null;
public String started_at=null;
public String ended_at=null;
public String limit=null;
public String address=null;
public String place=null;
public String owner_nickname=null;
public String owner_twitter_id=null;
public String updated_at=null;
}
これと、Gmailアカウントを経由してメールを送信するアプリ
参照:http://d.hatena.ne.jp/ttshrk/20110517/1305641955
を組み合わせて、定期的にATNDのイベント情報を通知するアプリを作りたいな、とか考えている。
*1:eventType = xmlPullParser.next(