簡単なRSSリーダーを作ってみる
第4回 簡単なRSSリーダーを作ってみる
第5回 RSSリーダーの要、パース機能を知る
第6回 詳細画面を付けて、簡易RSSリーダーの完成
という記事があって、コードをまとめてみて動かしてみようかと。
XMLの受信、パース、表示の流れはクラウドアプリでは必ず必要だと思うので。
ファイル構成
rssreader |-- AndroidManifest.xml |-- bin |-- build.properties |-- build.xml |-- default.properties |-- libs |-- local.properties |-- res | |-- layout | | |-- main.xml | | `-- item_row.xml | `-- values | `-- strings.xml `-- src `-- com `-- sample `-- rssreader |-- RssReader.java (*RssReaderActivity.java) |-- RssListAdapter.java |-- RssParserTask.java |-- Item.java `-- ItemDetailActivity.java
AndroidManifest.xml
アクティビティは2つ。許可するパーミッションはインターネット接続のみ。
アイコンは画像がないので指定しない。
SDKのバージョンは1.6以上とする。
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.sample.rssreader" android:versionCode="1" android:versionName="1.0"> <application android:label="@string/app_name"> <activity android:name=".RssReader" 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=".ItemDetailActivity" /> </application> <uses-sdk android:minSdkVersion="4" /> <uses-permission android:name="android.permission.INTERNET" /> </manifest>
res/layout/main.xml
メインアクティビティのリストビューのレイアウト。
それぞれのリストひとつひとつは、item_row.xmlで。
<?xml version="1.0" encoding="utf-8"?> <!-- mainアクティビティ用 --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <!-- リストビュー --> <ListView android:id="@android:id/list" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <!-- リストが空のときに表示 --> <TextView android:id="@android:id/empty" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
res/layout/item_row.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout android:id="@+id/item_container" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"> <TextView android:id="@+id/item_title" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textColor="#ffffff" android:textSize="18sp" android:lines="1" /> <TextView android:id="@+id/item_descr" android:layout_width="fill_parent" android:layout_height="wrap_content" android:lines="2" android:ellipsize="end" /> </LinearLayout>
src/com/sample/rssreader/RssReader.java
package com.sample.rssreader; import android.os.Bundle; import android.app.Activity; import android.app.ListActivity; import android.content.Intent; import android.view.View; import android.view.Menu; import android.view.MenuItem; import android.widget.ListView; import java.util.ArrayList; public class RssReader extends ListActivity { private static final String RSS_FEED_URL = "http://itpro.nikkeibp.co.jp/rss/ITpro.rdf"; public static final int MENU_ITEM_RELOAD = Menu.FIRST; private RssListAdapter mAdapter; private ArrayList<Item> mItems; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Itemオブジェクトを保持するためのリストを生成し、アダプタに追加する mItems = new ArrayList<Item>(); mAdapter = new RssListAdapter(this, mItems); // タスクを起動する RssParserTask task = new RssParserTask(this, mAdapter); task.execute(RSS_FEED_URL); } // リストの項目を選択した時の処理 @Override protected void onListItemClick(ListView l, View v, int position, long id) { Item item = mItems.get(position); Intent intent = new Intent(this, ItemDetailActivity.class); intent.putExtra("TITLE", item.getTitle()); intent.putExtra("DESCRIPTION", item.getDescription()); startActivity(intent); } // MENUボタンを押したときの処理 @Override public boolean onCreateOptionsMenu(Menu menu) { boolean result = super.onCreateOptionsMenu(menu); // デフォルトではアイテムを追加した順番通りに表示する menu.add(0, MENU_ITEM_RELOAD, 0, "更新"); return result; } // MENUの項目を押したときの処理 @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { // 更新 case MENU_ITEM_RELOAD: // アダプタを初期化し、タスクを起動する mItems = new ArrayList(); mAdapter = new RssListAdapter(this, mItems); // タスクはその都度生成する RssParserTask task = new RssParserTask(this, mAdapter); task.execute(RSS_FEED_URL); return true; } return super.onOptionsItemSelected(item); } }
src/com/sample/rssreader/RssListAdapter.java
package com.sample.rssreader; import android.view.View; import android.view.ViewGroup; import android.content.Context; import android.widget.TextView; import android.widget.ArrayAdapter; import android.view.LayoutInflater; import java.util.List; public class RssListAdapter extends ArrayAdapter<Item> { private LayoutInflater mInflater; private TextView mTitle; private TextView mDescr; public RssListAdapter(Context context, List<Item> objects) { super(context, 0, objects); mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } // 1行ごとのビューを生成する @Override public View getView(int position, View convertView, ViewGroup parent) { View view = convertView; if (convertView == null) { view = mInflater.inflate(R.layout.item_row, null); } // 現在参照しているリストの位置からItemを取得する Item item = this.getItem(position); if (item != null) { // Itemから必要なデータを取り出し、それぞれTextViewにセットする String title = item.getTitle().toString(); mTitle = (TextView) view.findViewById(R.id.item_title); mTitle.setText(title); String descr = item.getDescription().toString(); mDescr = (TextView) view.findViewById(R.id.item_descr); mDescr.setText(descr); } return view; } }
src/com/sample/rssreader/RssParserTask.java
package com.sample.rssreader; import android.os.AsyncTask; import android.app.ProgressDialog; import android.util.Xml; import java.io.InputStream; import java.io.IOException; import java.net.URL; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; public class RssParserTask extends AsyncTask<String, Integer, RssListAdapter> { private RssReader mActivity; private RssListAdapter mAdapter; private ProgressDialog mProgressDialog; // コンストラクタ public RssParserTask(RssReader activity, RssListAdapter adapter) { mActivity = activity; mAdapter = adapter; } // タスクを実行した直後にコールされる @Override protected void onPreExecute() { // プログレスバーを表示する mProgressDialog = new ProgressDialog(mActivity); mProgressDialog.setMessage("Now Loading..."); mProgressDialog.show(); } // バックグラウンドにおける処理を担う。タスク実行時に渡された値を引数とする @Override protected RssListAdapter doInBackground(String... params) { RssListAdapter result = null; try { // HTTP経由でアクセスし、InputStreamを取得する URL url = new URL(params[0]); InputStream is = url.openConnection().getInputStream(); result = parseXml(is); } catch (Exception e) { e.printStackTrace(); } // ここで返した値は、onPostExecuteメソッドの引数として渡される return result; } // メインスレッド上で実行される @Override protected void onPostExecute(RssListAdapter result) { mProgressDialog.dismiss(); mActivity.setListAdapter(result); } // XMLをパースする public RssListAdapter parseXml(InputStream is) throws IOException, XmlPullParserException { XmlPullParser parser = Xml.newPullParser(); try { parser.setInput(is, null); int eventType = parser.getEventType(); Item currentItem = null; while (eventType != XmlPullParser.END_DOCUMENT) { String tag = null; switch (eventType) { case XmlPullParser.START_TAG: tag = parser.getName(); if (tag.equals("item")) { currentItem = new Item(); } else if (currentItem != null) { if (tag.equals("title")) { currentItem.setTitle(parser.nextText()); } else if (tag.equals("description")) { currentItem.setDescription(parser.nextText()); } } break; case XmlPullParser.END_TAG: tag = parser.getName(); if (tag.equals("item")) { mAdapter.add(currentItem); } break; } eventType = parser.next(); } } catch (Exception e) { e.printStackTrace(); } return mAdapter; } }
src/com/sample/rssreader/Item.java
package com.sample.rssreader; public class Item { // 記事のタイトル // 記事の本文 private CharSequence mTitle; private CharSequence mDescription; public Item() { mTitle = ""; mDescription = ""; } public CharSequence getDescription() { return mDescription; } public void setDescription(CharSequence description) { mDescription = description; } public CharSequence getTitle() { return mTitle; } public void setTitle(CharSequence title) { mTitle = title; } }
src/com/sample/rssreader/ItemDetailActivity.java
package com.sample.rssreader; import android.os.Bundle; import android.app.Activity; import android.widget.TextView; import android.widget.ArrayAdapter; import android.content.Intent; public class ItemDetailActivity extends Activity { private TextView mTitle; private TextView mDescr; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.item_detail); Intent intent = getIntent(); String title = intent.getStringExtra("TITLE"); mTitle = (TextView) findViewById(R.id.item_detail_title); mTitle.setText(title); String descr = intent.getStringExtra("DESCRIPTION"); mDescr = (TextView) findViewById(R.id.item_detail_descr); mDescr.setText(descr); } }