Software/Android/アプリケーション開発テキスト/Chapter04
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
]
開始行:
[[Software/Android/アプリケーション開発テキスト]]
*Chapter 4 : HTTP通信を使用したアプリケーション開発 [#n25...
この章では簡易RSSリーダーを開発し、HTTP通信を使用するア...
このアプリケーションは設定したRSSを取得して、一覧と詳細...
新規Androidアプリケーションプロジェクトを以下の設定で作...
-Project Nameに「RSSReader」と入力します
-Application Nameに「RSSReader」と入力します
-Package Nameに「com.beatcraft.rssreader」と入力します
-Create Activityにチェックを入れ、「RSSReaderActivity」と...
~
~
**4-1. アプリケーションのレイアウト作成 [#s8ab65c3]
RSSReaderでは3つのアクティビティを使用します。メイン画...
CENTER:&ref(./04_01.png,);
CENTER:図4-1~
~
CENTER:&ref(./04_02.png,);
CENTER:図4-2~
~
CENTER:&ref(./04_03.png,);
CENTER:図4-3~
~
~
各レイアウトを作成する前に、文字列リソースを定義してお...
<string name="get_feed">取得</string>
<string name="config">設定</string>
<string name="regist">登録</string>
<string name="cancel">取消</string>
<string name="back">戻る</string>
<string name="label_number_of_get">取得件数:</string>
<string name="loading">読み込み中...</string>
<string-array name="number_of_get">
<item>1件</item>
<item>3件</item>
<item>5件</item>
</string-array>
~
string-arrayは文字列の配列で、ドロップダウンリスト(Spi...
リスト4-1がメイン/一覧画面のレイアウトファイルになりま...
-リスト4-1 main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/...
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip" >
<Button
android:id="@+id/Get"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_weight="1"
android:text="@string/get_feed" />
<Button
android:id="@+id/Config"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_weight="1"
android:text="@string/config" />
</LinearLayout>
<ListView
android:id="@+id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:fastScrollEnabled="true" >
</ListView>
</LinearLayout>
~
横方向のレイアウトにフィード取得ボタンと設定ボタンが並...
次に一覧表示で使用するリストアイテムのレイアウトを作成...
-リスト4-2 item_channel.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/...
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#cccccc"
android:orientation="vertical" >
<TextView
android:id="@+id/FeedTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="FeedTitle"
android:textColor="#000000"
android:textSize="16dip"
android:textStyle="bold" />
</LinearLayout>
~
-リスト4-3 item_item.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/...
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/ArticleTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="ArticleTitle" />
<TextView
android:id="@+id/PubDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_margin="5dip"
android:text="pubDate" />
</LinearLayout>
~
以上でメイン画面のレイアウト作成は完了です。
続いて詳細表示画面のリストを示します(リスト4-4)。
-リスト4-4 description.xml :
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/ap...
android:id="@+id/ScrollView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/Back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="@string/back" />
<TextView
android:id="@+id/FeedTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:text="FeedTitle"
android:textSize="16dip"
android:textStyle="bold" />
<TextView
android:id="@+id/ArticleTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:text="ArticleTitle" />
<TextView
android:id="@+id/PubDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginRight="10dip"
android:text="pubDate" />
<android.webkit.WebView
android:id="@+id/Description"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_margin="5dip"
android:layout_weight="1" >
</android.webkit.WebView>
</LinearLayout>
</ScrollView>
~
このレイアウトではまず、最上位のレイアウトがLinearLayou...
ScrollViewの下に縦方向のLinearLayoutが配置され、前画面...
WebViewはandroid.webkitに含まれる埋め込みHTMLブラウザ用...
最後に設定画面のレイアウトを作成します(リスト4-5)。
-リスト4-5 config.xml :
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/ap...
android:id="@+id/ScrollView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip" >
<TextView
android:id="@+id/LabelNumOfGet"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:text="@string/label_number_of_ge...
<Spinner
android:id="@+id/NumOfGet"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<EditText
android:id="@+id/FeedURL01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" >
<requestFocus />
</EditText>
<EditText
android:id="@+id/FeedURL02"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL03"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL04"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL05"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL06"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL07"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL08"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL09"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL10"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip" >
<Button
android:id="@+id/Cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_weight="1"
android:text="@string/cancel" />
<Button
android:id="@+id/Regist"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_weight="1"
android:text="@string/regist" />
</LinearLayout>
</LinearLayout>
</ScrollView>
~
設定画面もScrollViewを最上位に置き、スクロール可能にし...
これで全ての画面レイアウトが完成しました。
**4-2. アプリケーションクラスとフィードデータクラスの実装...
各アクティビティを作成する前に、ApplicationクラスとRSS...
Applicationクラスはアプリケーションが起動されると単一の...
android.app.ApplicationをベースクラスとしてRSSReaderApp...
-リスト4-6 :
public class RSSReaderApplication extends Application {
private static final String CONF_NAME = "rssreader....
public static final int DEFAULT_NUM_OF_GET = 3;
public static final int NUM_OF_FEED = 10;
private int mNumOfGet = DEFAULT_NUM_OF_GET;
private String mFeedURL[];
~
CONF_NAMEはこのアプリケーションで使用する設定ファイル名...
DEFAULT_NUM_OF_GETはフィード毎の記事取得デフォルト件数...
mNumOfGetとmFeedURLは現在の設定値を保存するメンバ変数で...
-リスト4-7 :
@Override
public void onCreate() {
mFeedURL = new String[NUM_OF_FEED];
loadConfig();
}
~
onCreateメソッド(リスト4-7)ではフィードURL配列mFeedUR...
-リスト4-8 :
public int numberOfGet() {
return mNumOfGet;
}
public void setNumberOfGet(int numOfGet) {
mNumOfGet = numOfGet;
}
public String feedURL(int index) {
if ((index < 0) || (10 <= index)) {
return null;
}
return mFeedURL[index];
}
public void setFeedURL(int index, String url) {
if ((index < 0) || (NUM_OF_FEED <= index)) {
return;
}
mFeedURL[index] = url;
}
public void clearFeedURL() {
for (int i = 0; i < NUM_OF_FEED; ++i) {
mFeedURL[i] = "";
}
}
~
onCreateに続いて、フィード取得件数と取得フィードURLのア...
-リスト4-9 :
public void loadConfig() {
SharedPreferences pref = getSharedPreferences(...
mNumOfGet = pref.getInt("NumOfGet", DEFAULT_NU...
for (int i = 0; i < NUM_OF_FEED; ++i) {
String key = String.format("FeedURL%02d",...
mFeedURL[i] = pref.getString(key, "");
}
}
public void saveConfig() {
SharedPreferences pref = getSharedPreferences(CO...
Editor pe = pref.edit();
pe.putInt("NumOfGet", mNumOfGet);
for (int i = 0; i < NUM_OF_FEED; ++i) {
String key = String.format("FeedURL%02d", (...
pe.putString(key, mFeedURL[i]);
}
pe.commit();
}
~
loadConfig、saveConfigで設定ファイルの読み書きを行いま...
プリファレンスクラスを利用すると、各設定内容をキーによ...
プリファレンスクラス自体には値の書き換えメソッドは用意...
続いてフィードデータ用のクラスを実装していきます。フィ...
FeedItemクラスの全リストが4-10になります。RSSフィード(...
-リスト4-10 FeedItem.java :
package com.beatcraft.rssreader;
public class FeedItem {
public static final int ITEMTYPE_FEEDCHANNEL = 0;
public static final int ITEMTYPE_FEEDITEM = 1;
private int mItemType;
private String mFeedTitle = "";
private String mArticleTitle = "";
private String mPubDate = "";
private String mDescription = "";
private String mLink = "";
public FeedItem(int itemType) {
mItemType = itemType;
}
public int itemType() {
return mItemType;
}
public String feedTitle() {
return mFeedTitle;
}
public void setFeedTitle(String title) {
mFeedTitle = title;
}
public String articleTitle() {
return mArticleTitle;
}
public void setArticleTitle(String title) {
mArticleTitle = title;
}
public String pubDate() {
return mPubDate;
}
public void setPubDate(String pubDate) {
mPubDate = pubDate;
}
public String description() {
return mDescription;
}
public void setDescription(String description) {
mDescription = description;
}
public String link() {
return mLink;
}
public void setLink(String link) {
mLink = link;
}
}
~
アイテムタイプがITEMTYPE_FEEDCHANNELであればフィードの...
FeedListクラスでは配列リストクラスArrayListにFeedItemを...
-リスト4-11 :
public class FeedList {
private ArrayList<FeedItem> mList = null;
public FeedList() {
mList = new ArrayList<FeedItem>();
}
public ArrayList<FeedItem> getList() {
return mList;
}
public int count() {
if (mList != null) {
return mList.size();
}
return 0;
}
~
FeedItemをテンプレートとしたArrayListのメンバ変数mList...
ここまででHTTP通信によるデータの受け皿が準備出来ました...
-リスト4-12 :
public int get(RSSReaderApplication app) {
int success = 0;
for (int i = 0; i < RSSReaderApplication.NUM_O...
String url = app.feedURL(i);
if (url.equals("") == true) {
continue;
}
DefaultHttpClient client = new DefaultHtt...
if (client != null) {
client.getParams().setParameter("htt...
HttpGet method = null;
try {
method = new HttpGet(url);
}
catch (Exception e) {
e.printStackTrace();
}
if (method == null) {
continue;
}
HttpResponse response = null;
try {
response = client.execute(metho...
int ret = response.getStatusLin...
if (ret == HttpStatus.SC_OK) {
InputStream is = response....
if (parse(is, app.numberOf...
success++;
}
is.close();
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
client.getConnectionManager().s...
}
}
}
return success;
}
~
getメソッドは、引数としてRSSReaderApplicationのインスタ...
まずはDefaultHttpClientのインスタンスを生成します。生成...
次にHTTP通信で使用するメソッドクラスのインスタンスを生...
メソッドの生成に成功したら、HTTPクライアントのexecuteに...
まずはgetStatusLine().getStatusCodeでステータスコードを...
最後にfinallyブロックでHTTPクライアントからコネクション...
RSSフィードはXMLで記述されているため、これを解析する必...
-リスト4-13 :
private int parse(InputStream is, int max) {
int count = 0;
boolean inChannel = false;
boolean inItem = false;
FeedItem item = null;
String feedTitle = "";
XmlPullParser p = Xml.newPullParser();
try {
p.setInput(is, null);
int event = p.getEventType();
while (event != XmlPullParser.END_DOCUMEN...
String elem = null;
String tmp = null;
switch (event) {
case XmlPullParser.START_TAG:
elem = p.getName();
if (elem.equals("channel") == t...
inChannel = true;
item = new FeedItem(FeedIt...
}
else if (elem.equals("item") ==...
if (inChannel == true) {
if (item != null) {
mList.add(item);
item = null;
count++;
}
inChannel = false;
}
inItem = true;
item = new FeedItem(FeedIt...
item.setFeedTitle(feedTitl...
}
else if (elem.equals("title") =...
tmp = p.nextText();
if ((tmp != null) && (item...
if (inChannel == true...
feedTitle = tmp;
item.setFeedTitl...
}
else if (inItem == tr...
item.setArticleT...
}
}
}
else if ((elem.equals("pubDate"...
|| (elem.equals("date...
if (inItem == true) {
tmp = p.nextText();
if ((tmp != null) && ...
item.setPubDate(...
}
}
}
else if (elem.equals("descripti...
if (inItem == true) {
tmp = p.nextText();
if ((tmp != null) && ...
item.setDescript...
}
}
}
else if (elem.equals("link") ==...
if (inItem == true) {
tmp = p.nextText();
if ((tmp != null) && ...
item.setLink(tmp);
}
}
}
break;
case XmlPullParser.END_TAG:
elem = p.getName();
if (elem.equals("channel") == t...
if (inChannel == true) {
if (item != null) {
mList.add(item);
item = null;
count++;
}
inChannel = false;
}
}
else if (elem.equals("item") ==...
if (inItem == true) {
if (item != null) {
mList.add(item);
item = null;
count++;
max--;
if (max == 0) {
return count;
}
}
inItem = false;
}
}
}
event = p.next();
}
}
catch (Exception e) {
e.printStackTrace();
return 0;
}
return count;
}
}
~
まずXml.newPullParserメソッドでXmlPullParserのインスタ...
状態が要素の開始を示すXmlPullParser.START_TAGになったら...
要素名が"item"の場合、フィードタイトルの解析中であれば...
状態がXmlPullParser.END_TAGになったら、解析中のFeedItem...
最後にパーサーのnextメソッドを呼び出し、状態を次に進め...
以上でRSSフィードの解析は完了です。
**4-3. 設定画面の実装 [#je8997f8]
取得するフィードを設定するため、設定画面アクティビティ...
-リスト4-14 :
public class ConfigActivity extends Activity implements ...
private static final int NUM_OF_GET_LIST[] = {1, 3,...
private Spinner mNumOfGet;
private EditText mFeedURL[];
~
NUM_OF_GET_LISTはフィード取得数として選択可能な数を格納...
mNumOfGetとmFeedURLはフィード取得数Spinnerと取得フィー...
-リスト4-15 :
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setSoftInputMode(LayoutParams.S...
setContentView(R.layout.config);
RSSReaderApplication app = (RSSReaderApplication...
ArrayAdapter<CharSequence> adapter;
adapter = ArrayAdapter.createFromResource(this, ...
android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_ite...
mNumOfGet = (Spinner) findViewById(R.id.NumOfGet);
mNumOfGet.setAdapter(adapter);
for (int i = 0; i < 3; ++i) {
if (NUM_OF_GET_LIST[i] == app.numberOfGet()...
mNumOfGet.setSelection(i);
break;
}
}
mFeedURL = new EditText[RSSReaderApplication.NUM...
mFeedURL[0] = (EditText) findViewById(R.id.FeedU...
mFeedURL[1] = (EditText) findViewById(R.id.FeedU...
mFeedURL[2] = (EditText) findViewById(R.id.FeedU...
mFeedURL[3] = (EditText) findViewById(R.id.FeedU...
mFeedURL[4] = (EditText) findViewById(R.id.FeedU...
mFeedURL[5] = (EditText) findViewById(R.id.FeedU...
mFeedURL[6] = (EditText) findViewById(R.id.FeedU...
mFeedURL[7] = (EditText) findViewById(R.id.FeedU...
mFeedURL[8] = (EditText) findViewById(R.id.FeedU...
mFeedURL[9] = (EditText) findViewById(R.id.FeedU...
for (int i = 0; i < RSSReaderApplication.NUM_OF_...
mFeedURL[i].setText(app.feedURL(i));
}
Button button;
button = (Button) findViewById(R.id.Cancel);
button.setOnClickListener(this);
button = (Button) findViewById(R.id.Regist);
button.setOnClickListener(this);
}
~
onCreateメソッド(リスト4-15)では、requestWindowFeatur...
通常、テキストボックス(EditText)を持つアクティビティ...
ここで現在の設定を設定画面に反映させるため、RSSReaderAp...
続いてmNumOfGetに格納したSpinnerに、文字列配列リソースn...
取得フィードURLのEditTextを配列mFeedURLに順次保持したあ...
最後に取消ボタン、登録ボタンのインスタンスを取得して、...
-リスト4-16 :
@Override
public void onClick(View view) {
int id = view.getId();
switch (id) {
case R.id.Cancel:
finish();
break;
case R.id.Regist:
regist();
break;
}
}
~
onClickメソッドでは引数で渡されたViewのIDから、取消(Ca...
リスト4-17がregistメソッドになります。
-リスト4-17 :
private void regist() {
RSSReaderApplication app = (RSSReaderApplicati...
app.setNumberOfGet(NUM_OF_GET_LIST[mNumOfGet.g...
app.clearFeedURL();
for (int i = 0, j = 0; i < RSSReaderApplicatio...
String url = mFeedURL[i].getText().toStri...
if (url.equals("") == false) {
app.setFeedURL(j++, url);
}
}
app.saveConfig();
finish();
}
~
アプリケーションクラスのインスタンスを取得し、これを通...
また、取得フィードURLの設定時には各EditTextの内容をチェ...
最後にsaveConfigメソッドで設定の保存を行い、finishを呼...
以上で設定画面アクティビティの実装は完了です。
**4-4. メイン画面の実装 [#lad27e52]
このアプリケーションのメイン画面であり、RSSフィードを一...
今回はアイテムタイプによってリストビューの各行に設定す...
ベースクラスをArrayAdapter、テンプレートをFeedItemとし...
-リスト4-18 :
public class FeedAdapter extends ArrayAdapter<FeedItem> {
private LayoutInflater mInflate;
public FeedAdapter(Context context, List<FeedItem> ...
super(context, 0, obj);
mInflate = (LayoutInflater) context.getSystemS...
Context.LAYOUT_INFLATER_SERVICE);
}
~
メンバ変数にLayoutInflaterクラスを追加し、コンストラク...
続いてisEnabledメソッドを追加します(リスト4-19)。
-リスト4-19 :
@Override
public boolean isEnabled(int pos) {
FeedItem item = getItem(pos);
if (item.itemType() == FeedItem.ITEMTYPE_FEEDC...
return false;
}
return true;
}
~
isEnabledメソッドはリストビューの各行に対して呼び出され...
-リスト4-20 :
public View getView(final int pos, View convView, V...
View view = convView;
FeedItem item = getItem(pos);
switch (item.itemType()) {
case FeedItem.ITEMTYPE_FEEDCHANNEL:
view = buildChannel(item);
break;
case FeedItem.ITEMTYPE_FEEDITEM:
view = buildItem(item);
break;
}
return view;
}
~
getViewメソッド(リスト4-20)はリストの各行がスクロール...
リスト4-21がbuildChannel/buildItemメソッドになります。
-リスト4-21 :
private View buildChannel(FeedItem item) {
View view = null;
view = mInflate.inflate(R.layout.item_channel,...
TextView tv;
tv = (TextView) view.findViewById(R.id.FeedTit...
tv.setText(item.feedTitle());
return view;
}
private View buildItem(FeedItem item) {
View view = null;
view = mInflate.inflate(R.layout.item_item, nu...
TextView tv;
tv = (TextView) view.findViewById(R.id.Article...
tv.setText(item.articleTitle());
tv = (TextView) view.findViewById(R.id.PubDate);
tv.setText(item.pubDate());
return view;
}
~
それぞれitem_channelレイアウト、item_itemレイアウトを使...
メイン画面ではFeedListを介してHTTP通信を行うことになり...
まずはAsyncTaskから呼び出すメソッドのインターフェースを...
生成されたITaskEntityにbackgroundProcとpostProcという二...
-リスト4-22 :
package com.beatcraft.rssreader;
public interface ITaskEntity {
void backgroundProc();
void postProc();
}
~
続いてAsyncTaskを作成します。ベースクラスをAsyncTask、...
-リスト4-23 :
package com.beatcraft.rssreader;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
public class HttpAccessTask extends AsyncTask<ITaskEntit...
private Activity mActivity;
private ProgressDialog mDialog;
private ITaskEntity mITaskEntity;
public HttpAccessTask(Activity activity) {
mActivity = activity;
}
@Override
protected void onPreExecute() {
mDialog = new ProgressDialog(mActivity);
mDialog.setMessage(mActivity.getString(R.strin...
mDialog.show();
}
@Override
protected Void doInBackground(ITaskEntity... params...
mITaskEntity = params[0];
mITaskEntity.backgroundProc();
return null;
}
@Override
protected void onPostExecute(Void v) {
mITaskEntity.postProc();
mDialog.dismiss();
mDialog = null;
}
}
~
コンストラクタでは引数で受け取ったアクティビティをメン...
doInBackgroundでITaskEntityを受け取って保持し、バックグ...
これでメイン画面を作成する準備が整いました。自動生成さ...
-リスト4-24 :
public class RSSReaderActivity extends ListActivity impl...
private FeedList mList = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
Button button;
button = (Button) findViewById(R.id.Get);
button.setOnClickListener(this);
button = (Button) findViewById(R.id.Config);
button.setOnClickListener(this);
}
~
自動生成されたRSSReaderActivityはベースクラスがActivity...
メンバ変数mListは、HTTP通信により取得したフィードデータ...
onCreateで取得ボタンと設定ボタンをOnClickListenerとして...
-リスト4-25 :
@Override
public void onClick(View view) {
int id = view.getId();
switch (id) {
case R.id.Get:
mList = null;
HttpAccessTask task = new HttpAccessTask(...
task.execute(this);
break;
case R.id.Config:
showConfig();
break;
}
}
~
取得(Get)ボタンではリストを一旦クリアして、HttpAccess...
-リスト4-26 :
@Override
public void backgroundProc() {
RSSReaderApplication app = (RSSReaderApplicati...
mList = new FeedList();
mList.get(app);
}
@Override
public void postProc() {
if (mList.count() > 0) {
ArrayList<FeedItem> list = mList.getList();
if (list != null) {
FeedAdapter adapter = new FeedAdapte...
setListAdapter(adapter);
}
}
else {
Toast.makeText(this, "* NOT FOUND *", Toa...
}
}
~
backgroundProcはHttpAccessTaskによりバックグラウンドス...
postProcはバックグラウンド処理が終了したあと、後処理と...
setListAdapterはListActivityのメソッドで、統合されたリ...
HTTP通信の結果、フィードが一件も取得出来なかった場合に...
-リスト4-27 :
private void showConfig() {
Intent intent = new Intent(getApplicationConte...
com.beatcraft.rssreader.ConfigActivity.cl...
startActivity(intent);
}
~
showConfigメソッドでは設定画面アクティビティ(ConfigAct...
これでメイン画面の実装はひとまず完了です。RSSReaderのマ...
-リスト4-28 :
<manifest xmlns:android="http://schemas.android.com/apk/...
package="com.beatcraft.rssreader"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="7" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:name="com.beatcraft.rssreader.RSSReaderA...
<activity
android:label="@string/app_name"
android:name=".RSSReaderActivity" >
<intent-filter >
<action android:name="android.intent.act...
<category android:name="android.intent.c...
</intent-filter>
</activity>
<activity
android:label="@string/app_name"
android:name=".ConfigActivity" />
</application>
<uses-permission android:name="android.permission.IN...
</uses-permission>
</manifest>
~
まずはapplication要素にRSSReaderApplicationを追加するた...
それから設定画面を呼び出し可能とするためのConfigActivit...
それでは一度実行してみましょう。設定画面で取得フィード...
**4-5. 詳細画面の実装 [#u8e15cd5]
続いて詳細画面アクティビティを作成し、一覧から記事をタ...
-リスト4-29 :
public class DescActivity extends Activity implements Vi...
private static final String WEBVIEW_BEGIN =
"<html><head><meta http-equiv=\"Content-Type\" ...
private static final String WEBVIEW_LINK = "<p><a h...
private static final String WEBVIEW_END = "</body><...
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.description);
Button button = (Button) findViewById(R.id.Back);
button.setOnClickListener(this);
Intent intent = getIntent();
if (intent != null) {
String tmp = "";
String desc = "";
TextView tv;
tv = (TextView) findViewById(R.id.FeedTitle);
tmp = intent.getStringExtra("FeedTitle");
tv.setText(tmp);
tv = (TextView) findViewById(R.id.ArticleTi...
tmp = intent.getStringExtra("ArticleTitle");
tv.setText(tmp);
tv = (TextView) findViewById(R.id.PubDate);
tmp = intent.getStringExtra("PubDate");
tv.setText(tmp);
WebView wv = (WebView) findViewById(R.id.De...
desc = WEBVIEW_BEGIN;
tmp = intent.getStringExtra("Link");
desc += String.format(WEBVIEW_LINK, tmp, tm...
tmp = intent.getStringExtra("Description");
desc += tmp + WEBVIEW_END;
wv.loadDataWithBaseURL("about:blank", desc,...
}
}
~
このアクティビティもrequestWindowFeatureでタイトル行を...
戻る(Back)ボタンのOnClickListenerを設定したあと、getI...
インテントから「FeedTitle(RSSフィードのタイトル)」「A...
次にこのクラスに追加した定数を利用して、WebView「Descri...
HTMLはWEBVIEW_BEGINで始まり、続いてWEBVIEW_LINKを追加し...
続いて、同様に取得した文字列データ「Description(詳細文...
こうして整形したHTML文書をWebViewのloadDataWithBaseURL...
-リスト4-30 :
@Override
public void onClick(View view) {
if (view.getId() == R.id.Back) {
finish();
}
}
~
onClickメソッド(リスト4-30)で戻る(Back)ボタンの処理...
一覧からの記事タップでこのアクティビティを呼び出すため...
-リスト4-31 :
getListView().setOnItemClickListener(new Adapter...
@Override
public void onItemClick(AdapterView<?> pare...
FeedItem item = (FeedItem) getListView()...
Intent intent = new Intent(getApplicatio...
com.beatcraft.rssreader.DescActivit...
intent.putExtra("FeedTitle", item.feedTi...
intent.putExtra("ArticleTitle", item.art...
intent.putExtra("PubDate", item.pubDate(...
intent.putExtra("Description", item.desc...
intent.putExtra("Link", item.link());
startActivity(intent);
}
});
~
getListViewでListActivityの埋め込みリストビューを取得し...
DescActivityを呼び出す明示的なインテントを生成したあと...
このインテントをstartActivityに渡せば、タップした記事を...
最後に詳細画面アクティビティをインテントで呼び出せるよ...
-リスト4-32 :
<activity
android:label="@string/app_name"
android:name=".DescActivity" />
~
以上で完成です。一覧から記事をタップすると、該当記事の...
**4-6. 追加機能:お勧めリスト取得(POST/BASIC認証解説) [...
ここまでで簡易RSSリーダーは完成しましたが、RSSフィード...
-サイト情報
URL: http://labs.beatcraft.com/ja/androidtext/recommend...
BASICユーザー: beatandroid
BASICパスワード: sample
上記URLにPOST変数genreとして、news/music/movieいずれか...
-リスト4-33 :
<?xml version="1.0" encoding="UTF-8"?>
<feedlist>
<genre>news</genre>
<feed>
<title>CNN</title>
<url>http://rss.cnn.com/rss/edition.rss</url>
</feed>
<feed>
<title>The Wall Street Journal</title>
<url>http://online.wsj.com/xml/rss/3_7480.xml</url>
</feed>
<feed>
<title>Reuters</title>
<url>http://feeds.reuters.com/reuters/topNews?format...
</feed>
</feedlist>
~
まずはstrings.xmlに、お勧め選択画面で使用する文字列リソ...
-リスト4-34 :
<string name="recommend">お勧め検索</string>
<string name="search">検索</string>
<string name="addfeed">チェックしたフィードを追加</s...
<string name="label_genre">ジャンル:</string>
<string-array name="genre">
<item>ニュース</item>
<item>音楽</item>
<item>映画</item>
</string-array>
~
続いてレイアウトを作成して行きましょう。recommend.xmlと...
-リスト4-35 recommend.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/...
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip" >
<TextView
android:id="@+id/LabelGenre"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:text="@string/label_genre" />
<Spinner
android:id="@+id/Genre"
android:layout_width="120dip"
android:layout_height="wrap_content" />
<Button
android:id="@+id/Search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_weight="1"
android:text="@string/search" />
</LinearLayout>
<Button
android:id="@+id/Back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="@string/back" />
<CheckBox
android:id="@+id/Feed01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="CheckBox"
android:visibility="invisible" />
<CheckBox
android:id="@+id/Feed02"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="CheckBox"
android:visibility="invisible" />
<CheckBox
android:id="@+id/Feed03"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="CheckBox"
android:visibility="invisible" />
<Button
android:id="@+id/AddFeed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="5dip"
android:text="@string/addfeed"
android:visibility="invisible" />
</LinearLayout>
~
お勧めRSSを取得し、画面に設定したものが図4-4になります。
CENTER:&ref(./04_04.png,);
CENTER:図4-4~
~
~
最上部にはジャンル選択のドロップダウンリスト(Spinner)...
それに続いてお勧めRSSのチェックボックスが三件並び、最後...
続いてこのお勧め画面を呼び出すため、設定画面にボタンを...
-リスト4-36 :
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip" >
<TextView
android:id="@+id/LabelNumOfGet"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:text="@string/label_number_of_ge...
<Spinner
android:id="@+id/NumOfGet"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="@+id/Recommend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_weight="1"
android:text="@string/recommend" />
</LinearLayout>
~
CENTER:&ref(./04_05.png,);
CENTER:図4-5~
~
~
お勧め選択画面の実装を進めていきましょう。android.app.A...
-リスト4-37 :
public class RecommendActivity extends Activity implemen...
private static final String GENRE[] = {"news", "mus...
private static final String POST_DOMAIN = "labs.bea...
private static final String POST_PATH = "/ja/androi...
private static final String POST_USER = "beatandroi...
private static final String POST_PASS = "sample";
private static final int NUM_OF_RECOMMEND = 3;
private Spinner mGenre;
private CheckBox mFeedCheck[];
private String mRecommendTitle[];
private String mRecommendURL[];
private Button mAddFeed;
private int mStat = -1;
~
GENREはお勧めRSSのジャンルとして選択可能な値を格納する...
POST_DOMAINとPOST_PATHは今回用意したお勧めRSS取得用サイ...
NUM_OF_RECOMMENDは各ジャンルでお勧めとして取得可能なRSS...
メンバ変数のうち、mRecommendTitleは取得したお勧めRSSの...
-リスト4-38 :
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.recommend);
ArrayAdapter<CharSequence> adapter;
adapter = ArrayAdapter.createFromResource(this, ...
android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_ite...
mGenre = (Spinner) findViewById(R.id.Genre);
mGenre.setAdapter(adapter);
Button button;
button = (Button) findViewById(R.id.Search);
button.setOnClickListener(this);
button = (Button) findViewById(R.id.Back);
button.setOnClickListener(this);
mAddFeed = (Button) findViewById(R.id.AddFeed);
mAddFeed.setOnClickListener(this);
mFeedCheck = new CheckBox[NUM_OF_RECOMMEND];
mFeedCheck[0] = (CheckBox) findViewById(R.id.Fee...
mFeedCheck[1] = (CheckBox) findViewById(R.id.Fee...
mFeedCheck[2] = (CheckBox) findViewById(R.id.Fee...
mRecommendTitle = new String[NUM_OF_RECOMMEND];
mRecommendURL = new String[NUM_OF_RECOMMEND];
}
~
onCreateメソッド(リスト4-38)でタイトル行の非表示化とr...
検索(Search)ボタン、戻る(Back)ボタン、チェックした...
-リスト4-39 :
@Override
public void onClick(View view) {
int id = view.getId();
switch (id) {
case R.id.Search:
HttpAccessTask task = new HttpAccessTask(...
task.execute(this);
break;
case R.id.Back:
finish();
break;
case R.id.AddFeed:
addFeed();
break;
}
}
~
onClickメソッド(リスト4-39)では検索(Search)ボタンに...
続いてHttpAccessTaskの実行により呼び出されるbackgroundP...
-リスト4-40 :
@Override
public void backgroundProc() {
for (int i = 0; i < NUM_OF_RECOMMEND; ++i) {
mRecommendTitle[i] = "";
mRecommendURL[i] = "";
}
mStat = get(GENRE[mGenre.getSelectedItemPositi...
}
@Override
public void postProc() {
if (mStat == 0) {
for (int i = 0; i < NUM_OF_RECOMMEND; ++i...
mFeedCheck[i].setText(mRecommendTitl...
mFeedCheck[i].setVisibility(View.VIS...
mFeedCheck[i].setChecked(false);
}
mAddFeed.setVisibility(View.VISIBLE);
}
else {
for (int i = 0; i < NUM_OF_RECOMMEND; ++i...
mFeedCheck[i].setText("");
mFeedCheck[i].setVisibility(View.INV...
mFeedCheck[i].setChecked(false);
}
mAddFeed.setVisibility(View.INVISIBLE);
}
}
~
backgroundProcではお勧めRSSを保持する各配列をクリアし、...
postProcではこのmStatをチェックし、0(成功)であればチ...
-リスト4-41 :
private int get(String genre) {
String url = "http://" + POST_DOMAIN + POST_PA...
DefaultHttpClient client = new DefaultHttpClie...
if (client != null) {
client.getParams().setParameter("http.soc...
HttpPost method = null;
try {
method = new HttpPost(url);
}
catch (Exception e) {
e.printStackTrace();
}
if (method == null) {
return -1;
}
HttpResponse response = null;
try {
List<NameValuePair> pair = new Array...
pair.add(new BasicNameValuePair("gen...
method.setEntity(new UrlEncodedFormE...
Credentials cred = new UsernamePassw...
client.getCredentialsProvider().setC...
new AuthScope(POST_DOMAIN, 80),...
response = client.execute(method);
int ret = response.getStatusLine().g...
if (ret == HttpStatus.SC_OK) {
InputStream is = response.getEn...
return parse(is);
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
client.getConnectionManager().shutdo...
}
}
return -1;
}
~
リスト4-41がgetメソッドになります。基本的な内容はRSSフ...
また、生成されたHttpPostのインスタンスに対し、List<Name...
これにより、ジャンルの選択リストから選ばれたニュース(n...
-リスト4-42 :
List<NameValuePair> pair = new Array...
pair.add(new BasicNameValuePair("gen...
method.setEntity(new UrlEncodedFormE...
~
続く二行で、BASIC認証のユーザーとパスワードをHTTPクライ...
-リスト4-43 :
Credentials cred = new UsernamePassw...
client.getCredentialsProvider().setC...
~
まずBASIC認証のユーザー名(定数POST_USER)、パスワード...
この認証情報をHTTPクライアントのgetCredentialsProvider...
getから呼び出されるparseメソッド(リスト4-44)では、フ...
-リスト4-44 :
private int parse(InputStream is) {
int count = 0;
boolean inFeed = false;
XmlPullParser p = Xml.newPullParser();
try {
p.setInput(is, null);
int event = p.getEventType();
while (event != XmlPullParser.END_DOCUMEN...
String elem = null;
String tmp = null;
switch (event) {
case XmlPullParser.START_TAG:
elem = p.getName();
if (elem.equals("feed") == true...
if (inFeed == true) {
count++;
if (count >= NUM_OF_R...
return 0;
}
}
inFeed = true;
}
else if (elem.equals("title") =...
tmp = p.nextText();
if (tmp != null) {
mRecommendTitle[count...
}
}
else if (elem.equals("url") == ...
tmp = p.nextText();
if (tmp != null) {
mRecommendURL[count] ...
}
}
break;
case XmlPullParser.END_TAG:
elem = p.getName();
if (elem.equals("feed") == true...
count++;
if (count >= NUM_OF_RECOMM...
return 0;
}
inFeed = false;
}
break;
}
event = p.next();
}
}
catch (Exception e) {
e.printStackTrace();
return -1;
}
return 0;
}
~
お勧めRSSのタイトルとURLが取得出来たら、それぞれメンバ...
最後にチェックしたフィードを追加(AddFeed)ボタンで呼び...
-リスト4-45 :
private void addFeed() {
int count = 0;
Intent result = new Intent();
for (int i = 0; i < NUM_OF_RECOMMEND; ++i) {
if (mFeedCheck[i].isChecked() == true) {
String key = "";
key = String.format("Recommend%02d",...
result.putExtra(key, mRecommendURL[i...
count++;
}
}
result.putExtra("RecommendCount", count);
setResult(RESULT_OK, result);
finish();
}
~
addFeedではresultというインテントを生成し、チェックされ...
このインテントをsetResultメソッドに定数RESULT_OKととも...
以上でお勧め選択画面の実装は完了です。次は設定画面を修...
ConfigActivityを開き、詳細画面呼び出しで使用する定数を...
public static final int REQUEST_RECOMMEND = 1234;
~
onCreateメソッドの最後に以下を追加し、お勧め検索ボタン...
button = (Button) findViewById(R.id.Recommend);
button.setOnClickListener(this);
~
続いてonClickメソッドのswitch文に、以下のcaseを追加しま...
case R.id.Recommend:
showRecommend();
break;
~
リスト4-46がshowRecommendメソッドになります。
-リスト4-46 :
private void showRecommend() {
Intent intent = new Intent(getApplicationConte...
com.beatcraft.rssreader.RecommendActivity...
startActivityForResult(intent, REQUEST_RECOMME...
}
~
明示的インテントを生成してRecommendActivityを呼び出して...
リスト4-47がonActivityResultになります。
-リスト4-47 :
protected void onActivityResult(int reqCode, int re...
super.onActivityResult(reqCode, result, data);
if (result == RESULT_OK) {
if (reqCode == REQUEST_RECOMMEND) {
int count = 0;
count = data.getIntExtra("RecommendC...
for (int i = 0; i < count; ++i) {
String key = "";
String url = "";
key = String.format("Recommend%...
url = data.getStringExtra(key);
if (url.equals("") == false) {
for (int j = 0; j < RSSRea...
String tmp = mFeedURL...
if (tmp.equals("") ==...
mFeedURL[j].setT...
break;
}
}
}
}
}
}
}
~
結果がRESULT_OKで、リクエストコードがREQUEST_RECOMMEND...
お勧めRSSが一件でも渡されていれば、これを一つずつ取得し...
最後にマニフェストファイルに以下を追加して、お勧め選択...
<activity
android:label="@string/app_name"
android:name=".RecommendActivity" />
~
以上で全ての実装は完了です。実行して動作を確認してみて...
**4-7. RSSReader全ソースコード/XMLファイル [#l297dd24]
-リスト4-48 RSSReaderApplication.java :
package com.beatcraft.rssreader;
import android.app.Application;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
public class RSSReaderApplication extends Application {
private static final String CONF_NAME = "rssreader.c...
public static final int DEFAULT_NUM_OF_GET = 3;
public static final int NUM_OF_FEED = 10;
private int mNumOfGet = DEFAULT_NUM_OF_GET;
private String mFeedURL[];
@Override
public void onCreate() {
mFeedURL = new String[NUM_OF_FEED];
loadConfig();
}
public int numberOfGet() {
return mNumOfGet;
}
public void setNumberOfGet(int numOfGet) {
mNumOfGet = numOfGet;
}
public String feedURL(int index) {
if ((index < 0) || (10 <= index)) {
return null;
}
return mFeedURL[index];
}
public void setFeedURL(int index, String url) {
if ((index < 0) || (NUM_OF_FEED <= index)) {
return;
}
mFeedURL[index] = url;
}
public void clearFeedURL() {
for (int i = 0; i < NUM_OF_FEED; ++i) {
mFeedURL[i] = "";
}
}
public void loadConfig() {
SharedPreferences pref = getSharedPreferences(CO...
mNumOfGet = pref.getInt("NumOfGet", DEFAULT_NUM_...
for (int i = 0; i < NUM_OF_FEED; ++i) {
String key = String.format("FeedURL%02d", (i...
mFeedURL[i] = pref.getString(key, "");
}
}
public void saveConfig() {
SharedPreferences pref = getSharedPreferences(CO...
Editor pe = pref.edit();
pe.putInt("NumOfGet", mNumOfGet);
for (int i = 0; i < NUM_OF_FEED; ++i) {
String key = String.format("FeedURL%02d", (i...
pe.putString(key, mFeedURL[i]);
}
pe.commit();
}
}
~
-リスト4-49 RSSReaderActivity.java :
package com.beatcraft.rssreader;
import java.util.ArrayList;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.Toast;
public class RSSReaderActivity extends ListActivity impl...
private FeedList mList = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
Button button;
button = (Button) findViewById(R.id.Get);
button.setOnClickListener(this);
button = (Button) findViewById(R.id.Config);
button.setOnClickListener(this);
getListView().setOnItemClickListener(new Adapter...
@Override
public void onItemClick(AdapterView<?> paren...
FeedItem item = (FeedItem) getListView()...
Intent intent = new Intent(getApplicatio...
intent.putExtra("FeedTitle", item.feedTi...
intent.putExtra("ArticleTitle", item.art...
intent.putExtra("PubDate", item.pubDate(...
intent.putExtra("Description", item.desc...
intent.putExtra("Link", item.link());
startActivity(intent);
}
});
}
@Override
public void onClick(View view) {
int id = view.getId();
switch (id) {
case R.id.Get:
mList = null;
HttpAccessTask task = new HttpAccessTask(thi...
task.execute(this);
break;
case R.id.Config:
showConfig();
break;
}
}
@Override
public void backgroundProc() {
RSSReaderApplication app = (RSSReaderApplication...
mList = new FeedList();
mList.get(app);
}
@Override
public void postProc() {
if (mList.count() > 0) {
ArrayList<FeedItem> list = mList.getList();
if (list != null) {
FeedAdapter adapter = new FeedAdapter(th...
setListAdapter(adapter);
}
}
else {
Toast.makeText(this, "* NOT FOUND *", Toast....
}
}
private void showConfig() {
Intent intent = new Intent(getApplicationContext...
startActivity(intent);
}
}
~
-リスト4-50 DescActivity.java :
package com.beatcraft.rssreader;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.TextView;
public class DescActivity extends Activity implements Vi...
private static final String WEBVIEW_BEGIN =
"<html><head><meta http-equiv=\"Content-Type\" c...
private static final String WEBVIEW_LINK = "<p><a hr...
private static final String WEBVIEW_END = "</body></...
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.description);
Button button = (Button) findViewById(R.id.Back);
button.setOnClickListener(this);
Intent intent = getIntent();
if (intent != null) {
String tmp = "";
String desc = "";
TextView tv;
tv = (TextView) findViewById(R.id.FeedTitle);
tmp = intent.getStringExtra("FeedTitle");
tv.setText(tmp);
tv = (TextView) findViewById(R.id.ArticleTit...
tmp = intent.getStringExtra("ArticleTitle");
tv.setText(tmp);
tv = (TextView) findViewById(R.id.PubDate);
tmp = intent.getStringExtra("PubDate");
tv.setText(tmp);
WebView wv = (WebView) findViewById(R.id.Des...
desc = WEBVIEW_BEGIN;
tmp = intent.getStringExtra("Link");
desc += String.format(WEBVIEW_LINK, tmp, tmp);
tmp = intent.getStringExtra("Description");
desc += tmp + WEBVIEW_END;
wv.loadDataWithBaseURL("about:blank", desc, ...
}
}
@Override
public void onClick(View view) {
if (view.getId() == R.id.Back) {
finish();
}
}
}
~
-リスト4-51 ConfigActivity.java :
package com.beatcraft.rssreader;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager.LayoutParams;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
public class ConfigActivity extends Activity implements ...
public static final int REQUEST_RECOMMEND = 1234;
private static final int NUM_OF_GET_LIST[] = {1, 3, ...
private Spinner mNumOfGet;
private EditText mFeedURL[];
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setSoftInputMode(LayoutParams.S...
setContentView(R.layout.config);
RSSReaderApplication app = (RSSReaderApplication...
ArrayAdapter<CharSequence> adapter;
adapter = ArrayAdapter.createFromResource(this, ...
adapter.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_ite...
mNumOfGet = (Spinner) findViewById(R.id.NumOfGet);
mNumOfGet.setAdapter(adapter);
for (int i = 0; i < 3; ++i) {
if (NUM_OF_GET_LIST[i] == app.numberOfGet()) {
mNumOfGet.setSelection(i);
break;
}
}
mFeedURL = new EditText[RSSReaderApplication.NUM...
mFeedURL[0] = (EditText) findViewById(R.id.FeedU...
mFeedURL[1] = (EditText) findViewById(R.id.FeedU...
mFeedURL[2] = (EditText) findViewById(R.id.FeedU...
mFeedURL[3] = (EditText) findViewById(R.id.FeedU...
mFeedURL[4] = (EditText) findViewById(R.id.FeedU...
mFeedURL[5] = (EditText) findViewById(R.id.FeedU...
mFeedURL[6] = (EditText) findViewById(R.id.FeedU...
mFeedURL[7] = (EditText) findViewById(R.id.FeedU...
mFeedURL[8] = (EditText) findViewById(R.id.FeedU...
mFeedURL[9] = (EditText) findViewById(R.id.FeedU...
for (int i = 0; i < RSSReaderApplication.NUM_OF_...
mFeedURL[i].setText(app.feedURL(i));
}
Button button;
button = (Button) findViewById(R.id.Recommend);
button.setOnClickListener(this);
button = (Button) findViewById(R.id.Cancel);
button.setOnClickListener(this);
button = (Button) findViewById(R.id.Regist);
button.setOnClickListener(this);
}
@Override
public void onClick(View view) {
int id = view.getId();
switch (id) {
case R.id.Recommend:
showRecommend();
break;
case R.id.Cancel:
finish();
break;
case R.id.Regist:
regist();
break;
}
}
protected void onActivityResult(int reqCode, int res...
super.onActivityResult(reqCode, result, data);
if (result == RESULT_OK) {
if (reqCode == REQUEST_RECOMMEND) {
int count = 0;
count = data.getIntExtra("RecommendCount...
for (int i = 0; i < count; ++i) {
String key = "";
String url = "";
key = String.format("Recommend%02d",...
url = data.getStringExtra(key);
if (url.equals("") == false) {
for (int j = 0; j < RSSReaderApp...
String tmp = mFeedURL[j].get...
if (tmp.equals("") == true) {
mFeedURL[j].setText(url);
break;
}
}
}
}
}
}
}
private void showRecommend() {
Intent intent = new Intent(getApplicationContext...
startActivityForResult(intent, REQUEST_RECOMMEND);
}
private void regist() {
RSSReaderApplication app = (RSSReaderApplication...
app.setNumberOfGet(NUM_OF_GET_LIST[mNumOfGet.get...
app.clearFeedURL();
for (int i = 0, j = 0; i < RSSReaderApplication....
String url = mFeedURL[i].getText().toString(...
if (url.equals("") == false) {
app.setFeedURL(j++, url);
}
}
app.saveConfig();
finish();
}
}
~
-リスト4-52 RecommendActivity.java :
package com.beatcraft.rssreader;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.xmlpull.v1.XmlPullParser;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Xml;
import android.view.View;
import android.view.Window;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.Spinner;
public class RecommendActivity extends Activity implemen...
private static final String GENRE[] = {"news", "musi...
private static final String POST_DOMAIN = "labs.beat...
private static final String POST_PATH = "/ja/android...
private static final String POST_USER = "beatandroid";
private static final String POST_PASS = "sample";
private static final int NUM_OF_RECOMMEND = 3;
private Spinner mGenre;
private CheckBox mFeedCheck[];
private String mRecommendTitle[];
private String mRecommendURL[];
private Button mAddFeed;
private int mStat = -1;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.recommend);
ArrayAdapter<CharSequence> adapter;
adapter = ArrayAdapter.createFromResource(this, ...
adapter.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_ite...
mGenre = (Spinner) findViewById(R.id.Genre);
mGenre.setAdapter(adapter);
Button button;
button = (Button) findViewById(R.id.Search);
button.setOnClickListener(this);
button = (Button) findViewById(R.id.Back);
button.setOnClickListener(this);
mAddFeed = (Button) findViewById(R.id.AddFeed);
mAddFeed.setOnClickListener(this);
mFeedCheck = new CheckBox[NUM_OF_RECOMMEND];
mFeedCheck[0] = (CheckBox) findViewById(R.id.Fee...
mFeedCheck[1] = (CheckBox) findViewById(R.id.Fee...
mFeedCheck[2] = (CheckBox) findViewById(R.id.Fee...
mRecommendTitle = new String[NUM_OF_RECOMMEND];
mRecommendURL = new String[NUM_OF_RECOMMEND];
}
@Override
public void onClick(View view) {
int id = view.getId();
switch (id) {
case R.id.Search:
HttpAccessTask task = new HttpAccessTask(thi...
task.execute(this);
break;
case R.id.Back:
finish();
break;
case R.id.AddFeed:
addFeed();
break;
}
}
@Override
public void backgroundProc() {
for (int i = 0; i < NUM_OF_RECOMMEND; ++i) {
mRecommendTitle[i] = "";
mRecommendURL[i] = "";
}
mStat = get(GENRE[mGenre.getSelectedItemPosition...
}
@Override
public void postProc() {
if (mStat == 0) {
for (int i = 0; i < NUM_OF_RECOMMEND; ++i) {
mFeedCheck[i].setText(mRecommendTitle[i]);
mFeedCheck[i].setVisibility(View.VISIBLE);
mFeedCheck[i].setChecked(false);
}
mAddFeed.setVisibility(View.VISIBLE);
}
else {
for (int i = 0; i < NUM_OF_RECOMMEND; ++i) {
mFeedCheck[i].setText("");
mFeedCheck[i].setVisibility(View.INVISIB...
mFeedCheck[i].setChecked(false);
}
mAddFeed.setVisibility(View.INVISIBLE);
}
}
private int get(String genre) {
String url = "http://" + POST_DOMAIN + POST_PATH;
DefaultHttpClient client = new DefaultHttpClient...
if (client != null) {
client.getParams().setParameter("http.socket...
HttpPost method = null;
try {
method = new HttpPost(url);
}
catch (Exception e) {
e.printStackTrace();
}
if (method == null) {
return -1;
}
HttpResponse response = null;
try {
List<NameValuePair> pair = new ArrayList...
pair.add(new BasicNameValuePair("genre",...
method.setEntity(new UrlEncodedFormEntit...
Credentials cred = new UsernamePasswordC...
client.getCredentialsProvider().setCrede...
response = client.execute(method);
int ret = response.getStatusLine().getSt...
if (ret == HttpStatus.SC_OK) {
InputStream is = response.getEntity(...
return parse(is);
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
client.getConnectionManager().shutdown();
}
}
return -1;
}
private int parse(InputStream is) {
int count = 0;
boolean inFeed = false;
XmlPullParser p = Xml.newPullParser();
try {
p.setInput(is, null);
int event = p.getEventType();
while (event != XmlPullParser.END_DOCUMENT) {
String elem = null;
String tmp = null;
switch (event) {
case XmlPullParser.START_TAG:
elem = p.getName();
if (elem.equals("feed") == true) {
if (inFeed == true) {
count++;
if (count >= NUM_OF_RECOMMEN...
return 0;
}
}
inFeed = true;
}
else if (elem.equals("title") == tru...
tmp = p.nextText();
if (tmp != null) {
mRecommendTitle[count] = tmp;
}
}
else if (elem.equals("url") == true) {
tmp = p.nextText();
if (tmp != null) {
mRecommendURL[count] = tmp;
}
}
break;
case XmlPullParser.END_TAG:
elem = p.getName();
if (elem.equals("feed") == true) {
count++;
if (count >= NUM_OF_RECOMMEND) {
return 0;
}
inFeed = false;
}
break;
}
event = p.next();
}
}
catch (Exception e) {
e.printStackTrace();
return -1;
}
return 0;
}
private void addFeed() {
int count = 0;
Intent result = new Intent();
for (int i = 0; i < NUM_OF_RECOMMEND; ++i) {
if (mFeedCheck[i].isChecked() == true) {
String key = "";
key = String.format("Recommend%02d", (co...
result.putExtra(key, mRecommendURL[i]);
count++;
}
}
result.putExtra("RecommendCount", count);
setResult(RESULT_OK, result);
finish();
}
}
~
-リスト4-53 FeedItem.java :
package com.beatcraft.rssreader;
public class FeedItem {
public static final int ITEMTYPE_FEEDCHANNEL = 0;
public static final int ITEMTYPE_FEEDITEM = 1;
private int mItemType;
private String mFeedTitle = "";
private String mArticleTitle = "";
private String mPubDate = "";
private String mDescription = "";
private String mLink = "";
public FeedItem(int itemType) {
mItemType = itemType;
}
public int itemType() {
return mItemType;
}
public String feedTitle() {
return mFeedTitle;
}
public void setFeedTitle(String title) {
mFeedTitle = title;
}
public String articleTitle() {
return mArticleTitle;
}
public void setArticleTitle(String title) {
mArticleTitle = title;
}
public String pubDate() {
return mPubDate;
}
public void setPubDate(String pubDate) {
mPubDate = pubDate;
}
public String description() {
return mDescription;
}
public void setDescription(String description) {
mDescription = description;
}
public String link() {
return mLink;
}
public void setLink(String link) {
mLink = link;
}
}
~
-リスト4-54 FeedList.java :
package com.beatcraft.rssreader;
import java.io.InputStream;
import java.util.ArrayList;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.xmlpull.v1.XmlPullParser;
import android.util.Xml;
public class FeedList {
private ArrayList<FeedItem> mList = null;
public FeedList() {
mList = new ArrayList<FeedItem>();
}
public ArrayList<FeedItem> getList() {
return mList;
}
public int count() {
if (mList != null) {
return mList.size();
}
return 0;
}
public int get(RSSReaderApplication app) {
int success = 0;
for (int i = 0; i < RSSReaderApplication.NUM_OF_...
String url = app.feedURL(i);
if (url.equals("") == true) {
continue;
}
DefaultHttpClient client = new DefaultHttpCl...
if (client != null) {
client.getParams().setParameter("http.so...
HttpGet method = null;
try {
method = new HttpGet(url);
}
catch (Exception e) {
e.printStackTrace();
}
if (method == null) {
continue;
}
HttpResponse response = null;
try {
response = client.execute(method);
int ret = response.getStatusLine().g...
if (ret == HttpStatus.SC_OK) {
InputStream is = response.getEnt...
if (parse(is, app.numberOfGet())...
success++;
}
is.close();
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
client.getConnectionManager().shutdo...
}
}
}
return success;
}
private int parse(InputStream is, int max) {
int count = 0;
boolean inChannel = false;
boolean inItem = false;
FeedItem item = null;
String feedTitle = "";
XmlPullParser p = Xml.newPullParser();
try {
p.setInput(is, null);
int event = p.getEventType();
while (event != XmlPullParser.END_DOCUMENT) {
String elem = null;
String tmp = null;
switch (event) {
case XmlPullParser.START_TAG:
elem = p.getName();
if (elem.equals("channel") == true) {
inChannel = true;
item = new FeedItem(FeedItem.ITE...
}
else if (elem.equals("item") == true...
if (inChannel == true) {
if (item != null) {
mList.add(item);
item = null;
count++;
}
inChannel = false;
}
inItem = true;
item = new FeedItem(FeedItem.ITE...
item.setFeedTitle(feedTitle);
}
else if (elem.equals("title") == tru...
tmp = p.nextText();
if ((tmp != null) && (item != nu...
if (inChannel == true) {
feedTitle = tmp;
item.setFeedTitle(tmp);
}
else if (inItem == true) {
item.setArticleTitle(tmp);
}
}
}
else if ((elem.equals("pubDate") == ...
|| (elem.equals("date") == t...
if (inItem == true) {
tmp = p.nextText();
if ((tmp != null) && (item !...
item.setPubDate(tmp);
}
}
}
else if (elem.equals("description") ...
if (inItem == true) {
tmp = p.nextText();
if ((tmp != null) && (item !...
item.setDescription(tmp);
}
}
}
else if (elem.equals("link") == true...
if (inItem == true) {
tmp = p.nextText();
if ((tmp != null) && (item !...
item.setLink(tmp);
}
}
}
break;
case XmlPullParser.END_TAG:
elem = p.getName();
if (elem.equals("channel") == true) {
if (inChannel == true) {
if (item != null) {
mList.add(item);
item = null;
count++;
}
inChannel = false;
}
}
else if (elem.equals("item") == true...
if (inItem == true) {
if (item != null) {
mList.add(item);
item = null;
count++;
max--;
if (max == 0) {
return count;
}
}
inItem = false;
}
}
}
event = p.next();
}
}
catch (Exception e) {
e.printStackTrace();
return 0;
}
return count;
}
}
~
-リスト4-55 FeedAdapter.java :
package com.beatcraft.rssreader;
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class FeedAdapter extends ArrayAdapter<FeedItem> {
private LayoutInflater mInflate;
public FeedAdapter(Context context, List<FeedItem> o...
super(context, 0, obj);
mInflate = (LayoutInflater) context.getSystemSer...
}
@Override
public boolean isEnabled(int pos) {
FeedItem item = getItem(pos);
if (item.itemType() == FeedItem.ITEMTYPE_FEEDCHA...
return false;
}
return true;
}
public View getView(final int pos, View convView, Vi...
View view = convView;
FeedItem item = getItem(pos);
switch (item.itemType()) {
case FeedItem.ITEMTYPE_FEEDCHANNEL:
view = buildChannel(item);
break;
case FeedItem.ITEMTYPE_FEEDITEM:
view = buildItem(item);
break;
}
return view;
}
private View buildChannel(FeedItem item) {
View view = null;
view = mInflate.inflate(R.layout.item_channel, n...
TextView tv;
tv = (TextView) view.findViewById(R.id.FeedTitle);
tv.setText(item.feedTitle());
return view;
}
private View buildItem(FeedItem item) {
View view = null;
view = mInflate.inflate(R.layout.item_item, null);
TextView tv;
tv = (TextView) view.findViewById(R.id.ArticleTi...
tv.setText(item.articleTitle());
tv = (TextView) view.findViewById(R.id.PubDate);
tv.setText(item.pubDate());
return view;
}
}
~
-リスト4-56 ITaskEntity.java :
package com.beatcraft.rssreader;
public interface ITaskEntity {
void backgroundProc();
void postProc();
}
~
-リスト4-57 HttpAccessTask.java :
package com.beatcraft.rssreader;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
public class HttpAccessTask extends AsyncTask<ITaskEntit...
private Activity mActivity;
private ProgressDialog mDialog;
private ITaskEntity mITaskEntity;
public HttpAccessTask(Activity activity) {
mActivity = activity;
}
@Override
protected void onPreExecute() {
mDialog = new ProgressDialog(mActivity);
mDialog.setMessage(mActivity.getString(R.string....
mDialog.show();
}
@Override
protected Void doInBackground(ITaskEntity... params) {
mITaskEntity = params[0];
mITaskEntity.backgroundProc();
return null;
}
@Override
protected void onPostExecute(Void v) {
mITaskEntity.postProc();
mDialog.dismiss();
mDialog = null;
}
}
~
-リスト4-58 main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/...
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip" >
<Button
android:id="@+id/Get"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_weight="1"
android:text="@string/get_feed" />
<Button
android:id="@+id/Config"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_weight="1"
android:text="@string/config" />
</LinearLayout>
<ListView
android:id="@+id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:fastScrollEnabled="true" >
</ListView>
</LinearLayout>
~
-リスト4-59 item_channel.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/...
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#cccccc"
android:orientation="vertical" >
<TextView
android:id="@+id/FeedTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="FeedTitle"
android:textColor="#000000"
android:textSize="16dip"
android:textStyle="bold" />
</LinearLayout>
~
-リスト4-60 item_item.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/...
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/ArticleTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="ArticleTitle" />
<TextView
android:id="@+id/PubDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_margin="5dip"
android:text="pubDate" />
</LinearLayout>
~
-リスト4-61 description.xml :
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/ap...
android:id="@+id/ScrollView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/Back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="@string/back" />
<TextView
android:id="@+id/FeedTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:text="FeedTitle"
android:textSize="16dip"
android:textStyle="bold" />
<TextView
android:id="@+id/ArticleTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:text="ArticleTitle" />
<TextView
android:id="@+id/PubDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginRight="10dip"
android:text="pubDate" />
<android.webkit.WebView
android:id="@+id/Description"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_margin="5dip"
android:layout_weight="1" >
</android.webkit.WebView>
</LinearLayout>
</ScrollView>
~
-リスト4-62 config.xml :
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/ap...
android:id="@+id/ScrollView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip" >
<TextView
android:id="@+id/LabelNumOfGet"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:text="@string/label_number_of_ge...
<Spinner
android:id="@+id/NumOfGet"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="@+id/Recommend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_weight="1"
android:text="@string/recommend" />
</LinearLayout>
<EditText
android:id="@+id/FeedURL01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" >
<requestFocus />
</EditText>
<EditText
android:id="@+id/FeedURL02"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL03"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL04"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL05"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL06"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL07"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL08"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL09"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL10"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip" >
<Button
android:id="@+id/Cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_weight="1"
android:text="@string/cancel" />
<Button
android:id="@+id/Regist"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_weight="1"
android:text="@string/regist" />
</LinearLayout>
</LinearLayout>
</ScrollView>
~
-リスト4-63 recommend.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/...
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip" >
<TextView
android:id="@+id/LabelGenre"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:text="@string/label_genre" />
<Spinner
android:id="@+id/Genre"
android:layout_width="120dip"
android:layout_height="wrap_content" />
<Button
android:id="@+id/Search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_weight="1"
android:text="@string/search" />
</LinearLayout>
<Button
android:id="@+id/Back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="@string/back" />
<CheckBox
android:id="@+id/Feed01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="CheckBox"
android:visibility="invisible" />
<CheckBox
android:id="@+id/Feed02"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="CheckBox"
android:visibility="invisible" />
<CheckBox
android:id="@+id/Feed03"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="CheckBox"
android:visibility="invisible" />
<Button
android:id="@+id/AddFeed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="5dip"
android:text="@string/addfeed"
android:visibility="invisible" />
</LinearLayout>
~
-リスト4-64 AndroidManifest.xml :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/...
package="com.beatcraft.rssreader"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="7" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:name="com.beatcraft.rssreader.RSSReaderA...
<activity
android:label="@string/app_name"
android:name=".RSSReaderActivity" >
<intent-filter >
<action android:name="android.intent.act...
<category android:name="android.intent.c...
</intent-filter>
</activity>
<activity
android:label="@string/app_name"
android:name=".ConfigActivity" />
<activity
android:label="@string/app_name"
android:name=".DescActivity" />
<activity
android:label="@string/app_name"
android:name=".RecommendActivity" />
</application>
<uses-permission android:name="android.permission.IN...
</uses-permission>
</manifest>
~
----
RIGHT:内藤
終了行:
[[Software/Android/アプリケーション開発テキスト]]
*Chapter 4 : HTTP通信を使用したアプリケーション開発 [#n25...
この章では簡易RSSリーダーを開発し、HTTP通信を使用するア...
このアプリケーションは設定したRSSを取得して、一覧と詳細...
新規Androidアプリケーションプロジェクトを以下の設定で作...
-Project Nameに「RSSReader」と入力します
-Application Nameに「RSSReader」と入力します
-Package Nameに「com.beatcraft.rssreader」と入力します
-Create Activityにチェックを入れ、「RSSReaderActivity」と...
~
~
**4-1. アプリケーションのレイアウト作成 [#s8ab65c3]
RSSReaderでは3つのアクティビティを使用します。メイン画...
CENTER:&ref(./04_01.png,);
CENTER:図4-1~
~
CENTER:&ref(./04_02.png,);
CENTER:図4-2~
~
CENTER:&ref(./04_03.png,);
CENTER:図4-3~
~
~
各レイアウトを作成する前に、文字列リソースを定義してお...
<string name="get_feed">取得</string>
<string name="config">設定</string>
<string name="regist">登録</string>
<string name="cancel">取消</string>
<string name="back">戻る</string>
<string name="label_number_of_get">取得件数:</string>
<string name="loading">読み込み中...</string>
<string-array name="number_of_get">
<item>1件</item>
<item>3件</item>
<item>5件</item>
</string-array>
~
string-arrayは文字列の配列で、ドロップダウンリスト(Spi...
リスト4-1がメイン/一覧画面のレイアウトファイルになりま...
-リスト4-1 main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/...
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip" >
<Button
android:id="@+id/Get"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_weight="1"
android:text="@string/get_feed" />
<Button
android:id="@+id/Config"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_weight="1"
android:text="@string/config" />
</LinearLayout>
<ListView
android:id="@+id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:fastScrollEnabled="true" >
</ListView>
</LinearLayout>
~
横方向のレイアウトにフィード取得ボタンと設定ボタンが並...
次に一覧表示で使用するリストアイテムのレイアウトを作成...
-リスト4-2 item_channel.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/...
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#cccccc"
android:orientation="vertical" >
<TextView
android:id="@+id/FeedTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="FeedTitle"
android:textColor="#000000"
android:textSize="16dip"
android:textStyle="bold" />
</LinearLayout>
~
-リスト4-3 item_item.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/...
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/ArticleTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="ArticleTitle" />
<TextView
android:id="@+id/PubDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_margin="5dip"
android:text="pubDate" />
</LinearLayout>
~
以上でメイン画面のレイアウト作成は完了です。
続いて詳細表示画面のリストを示します(リスト4-4)。
-リスト4-4 description.xml :
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/ap...
android:id="@+id/ScrollView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/Back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="@string/back" />
<TextView
android:id="@+id/FeedTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:text="FeedTitle"
android:textSize="16dip"
android:textStyle="bold" />
<TextView
android:id="@+id/ArticleTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:text="ArticleTitle" />
<TextView
android:id="@+id/PubDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginRight="10dip"
android:text="pubDate" />
<android.webkit.WebView
android:id="@+id/Description"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_margin="5dip"
android:layout_weight="1" >
</android.webkit.WebView>
</LinearLayout>
</ScrollView>
~
このレイアウトではまず、最上位のレイアウトがLinearLayou...
ScrollViewの下に縦方向のLinearLayoutが配置され、前画面...
WebViewはandroid.webkitに含まれる埋め込みHTMLブラウザ用...
最後に設定画面のレイアウトを作成します(リスト4-5)。
-リスト4-5 config.xml :
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/ap...
android:id="@+id/ScrollView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip" >
<TextView
android:id="@+id/LabelNumOfGet"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:text="@string/label_number_of_ge...
<Spinner
android:id="@+id/NumOfGet"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<EditText
android:id="@+id/FeedURL01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" >
<requestFocus />
</EditText>
<EditText
android:id="@+id/FeedURL02"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL03"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL04"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL05"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL06"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL07"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL08"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL09"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL10"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip" >
<Button
android:id="@+id/Cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_weight="1"
android:text="@string/cancel" />
<Button
android:id="@+id/Regist"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_weight="1"
android:text="@string/regist" />
</LinearLayout>
</LinearLayout>
</ScrollView>
~
設定画面もScrollViewを最上位に置き、スクロール可能にし...
これで全ての画面レイアウトが完成しました。
**4-2. アプリケーションクラスとフィードデータクラスの実装...
各アクティビティを作成する前に、ApplicationクラスとRSS...
Applicationクラスはアプリケーションが起動されると単一の...
android.app.ApplicationをベースクラスとしてRSSReaderApp...
-リスト4-6 :
public class RSSReaderApplication extends Application {
private static final String CONF_NAME = "rssreader....
public static final int DEFAULT_NUM_OF_GET = 3;
public static final int NUM_OF_FEED = 10;
private int mNumOfGet = DEFAULT_NUM_OF_GET;
private String mFeedURL[];
~
CONF_NAMEはこのアプリケーションで使用する設定ファイル名...
DEFAULT_NUM_OF_GETはフィード毎の記事取得デフォルト件数...
mNumOfGetとmFeedURLは現在の設定値を保存するメンバ変数で...
-リスト4-7 :
@Override
public void onCreate() {
mFeedURL = new String[NUM_OF_FEED];
loadConfig();
}
~
onCreateメソッド(リスト4-7)ではフィードURL配列mFeedUR...
-リスト4-8 :
public int numberOfGet() {
return mNumOfGet;
}
public void setNumberOfGet(int numOfGet) {
mNumOfGet = numOfGet;
}
public String feedURL(int index) {
if ((index < 0) || (10 <= index)) {
return null;
}
return mFeedURL[index];
}
public void setFeedURL(int index, String url) {
if ((index < 0) || (NUM_OF_FEED <= index)) {
return;
}
mFeedURL[index] = url;
}
public void clearFeedURL() {
for (int i = 0; i < NUM_OF_FEED; ++i) {
mFeedURL[i] = "";
}
}
~
onCreateに続いて、フィード取得件数と取得フィードURLのア...
-リスト4-9 :
public void loadConfig() {
SharedPreferences pref = getSharedPreferences(...
mNumOfGet = pref.getInt("NumOfGet", DEFAULT_NU...
for (int i = 0; i < NUM_OF_FEED; ++i) {
String key = String.format("FeedURL%02d",...
mFeedURL[i] = pref.getString(key, "");
}
}
public void saveConfig() {
SharedPreferences pref = getSharedPreferences(CO...
Editor pe = pref.edit();
pe.putInt("NumOfGet", mNumOfGet);
for (int i = 0; i < NUM_OF_FEED; ++i) {
String key = String.format("FeedURL%02d", (...
pe.putString(key, mFeedURL[i]);
}
pe.commit();
}
~
loadConfig、saveConfigで設定ファイルの読み書きを行いま...
プリファレンスクラスを利用すると、各設定内容をキーによ...
プリファレンスクラス自体には値の書き換えメソッドは用意...
続いてフィードデータ用のクラスを実装していきます。フィ...
FeedItemクラスの全リストが4-10になります。RSSフィード(...
-リスト4-10 FeedItem.java :
package com.beatcraft.rssreader;
public class FeedItem {
public static final int ITEMTYPE_FEEDCHANNEL = 0;
public static final int ITEMTYPE_FEEDITEM = 1;
private int mItemType;
private String mFeedTitle = "";
private String mArticleTitle = "";
private String mPubDate = "";
private String mDescription = "";
private String mLink = "";
public FeedItem(int itemType) {
mItemType = itemType;
}
public int itemType() {
return mItemType;
}
public String feedTitle() {
return mFeedTitle;
}
public void setFeedTitle(String title) {
mFeedTitle = title;
}
public String articleTitle() {
return mArticleTitle;
}
public void setArticleTitle(String title) {
mArticleTitle = title;
}
public String pubDate() {
return mPubDate;
}
public void setPubDate(String pubDate) {
mPubDate = pubDate;
}
public String description() {
return mDescription;
}
public void setDescription(String description) {
mDescription = description;
}
public String link() {
return mLink;
}
public void setLink(String link) {
mLink = link;
}
}
~
アイテムタイプがITEMTYPE_FEEDCHANNELであればフィードの...
FeedListクラスでは配列リストクラスArrayListにFeedItemを...
-リスト4-11 :
public class FeedList {
private ArrayList<FeedItem> mList = null;
public FeedList() {
mList = new ArrayList<FeedItem>();
}
public ArrayList<FeedItem> getList() {
return mList;
}
public int count() {
if (mList != null) {
return mList.size();
}
return 0;
}
~
FeedItemをテンプレートとしたArrayListのメンバ変数mList...
ここまででHTTP通信によるデータの受け皿が準備出来ました...
-リスト4-12 :
public int get(RSSReaderApplication app) {
int success = 0;
for (int i = 0; i < RSSReaderApplication.NUM_O...
String url = app.feedURL(i);
if (url.equals("") == true) {
continue;
}
DefaultHttpClient client = new DefaultHtt...
if (client != null) {
client.getParams().setParameter("htt...
HttpGet method = null;
try {
method = new HttpGet(url);
}
catch (Exception e) {
e.printStackTrace();
}
if (method == null) {
continue;
}
HttpResponse response = null;
try {
response = client.execute(metho...
int ret = response.getStatusLin...
if (ret == HttpStatus.SC_OK) {
InputStream is = response....
if (parse(is, app.numberOf...
success++;
}
is.close();
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
client.getConnectionManager().s...
}
}
}
return success;
}
~
getメソッドは、引数としてRSSReaderApplicationのインスタ...
まずはDefaultHttpClientのインスタンスを生成します。生成...
次にHTTP通信で使用するメソッドクラスのインスタンスを生...
メソッドの生成に成功したら、HTTPクライアントのexecuteに...
まずはgetStatusLine().getStatusCodeでステータスコードを...
最後にfinallyブロックでHTTPクライアントからコネクション...
RSSフィードはXMLで記述されているため、これを解析する必...
-リスト4-13 :
private int parse(InputStream is, int max) {
int count = 0;
boolean inChannel = false;
boolean inItem = false;
FeedItem item = null;
String feedTitle = "";
XmlPullParser p = Xml.newPullParser();
try {
p.setInput(is, null);
int event = p.getEventType();
while (event != XmlPullParser.END_DOCUMEN...
String elem = null;
String tmp = null;
switch (event) {
case XmlPullParser.START_TAG:
elem = p.getName();
if (elem.equals("channel") == t...
inChannel = true;
item = new FeedItem(FeedIt...
}
else if (elem.equals("item") ==...
if (inChannel == true) {
if (item != null) {
mList.add(item);
item = null;
count++;
}
inChannel = false;
}
inItem = true;
item = new FeedItem(FeedIt...
item.setFeedTitle(feedTitl...
}
else if (elem.equals("title") =...
tmp = p.nextText();
if ((tmp != null) && (item...
if (inChannel == true...
feedTitle = tmp;
item.setFeedTitl...
}
else if (inItem == tr...
item.setArticleT...
}
}
}
else if ((elem.equals("pubDate"...
|| (elem.equals("date...
if (inItem == true) {
tmp = p.nextText();
if ((tmp != null) && ...
item.setPubDate(...
}
}
}
else if (elem.equals("descripti...
if (inItem == true) {
tmp = p.nextText();
if ((tmp != null) && ...
item.setDescript...
}
}
}
else if (elem.equals("link") ==...
if (inItem == true) {
tmp = p.nextText();
if ((tmp != null) && ...
item.setLink(tmp);
}
}
}
break;
case XmlPullParser.END_TAG:
elem = p.getName();
if (elem.equals("channel") == t...
if (inChannel == true) {
if (item != null) {
mList.add(item);
item = null;
count++;
}
inChannel = false;
}
}
else if (elem.equals("item") ==...
if (inItem == true) {
if (item != null) {
mList.add(item);
item = null;
count++;
max--;
if (max == 0) {
return count;
}
}
inItem = false;
}
}
}
event = p.next();
}
}
catch (Exception e) {
e.printStackTrace();
return 0;
}
return count;
}
}
~
まずXml.newPullParserメソッドでXmlPullParserのインスタ...
状態が要素の開始を示すXmlPullParser.START_TAGになったら...
要素名が"item"の場合、フィードタイトルの解析中であれば...
状態がXmlPullParser.END_TAGになったら、解析中のFeedItem...
最後にパーサーのnextメソッドを呼び出し、状態を次に進め...
以上でRSSフィードの解析は完了です。
**4-3. 設定画面の実装 [#je8997f8]
取得するフィードを設定するため、設定画面アクティビティ...
-リスト4-14 :
public class ConfigActivity extends Activity implements ...
private static final int NUM_OF_GET_LIST[] = {1, 3,...
private Spinner mNumOfGet;
private EditText mFeedURL[];
~
NUM_OF_GET_LISTはフィード取得数として選択可能な数を格納...
mNumOfGetとmFeedURLはフィード取得数Spinnerと取得フィー...
-リスト4-15 :
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setSoftInputMode(LayoutParams.S...
setContentView(R.layout.config);
RSSReaderApplication app = (RSSReaderApplication...
ArrayAdapter<CharSequence> adapter;
adapter = ArrayAdapter.createFromResource(this, ...
android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_ite...
mNumOfGet = (Spinner) findViewById(R.id.NumOfGet);
mNumOfGet.setAdapter(adapter);
for (int i = 0; i < 3; ++i) {
if (NUM_OF_GET_LIST[i] == app.numberOfGet()...
mNumOfGet.setSelection(i);
break;
}
}
mFeedURL = new EditText[RSSReaderApplication.NUM...
mFeedURL[0] = (EditText) findViewById(R.id.FeedU...
mFeedURL[1] = (EditText) findViewById(R.id.FeedU...
mFeedURL[2] = (EditText) findViewById(R.id.FeedU...
mFeedURL[3] = (EditText) findViewById(R.id.FeedU...
mFeedURL[4] = (EditText) findViewById(R.id.FeedU...
mFeedURL[5] = (EditText) findViewById(R.id.FeedU...
mFeedURL[6] = (EditText) findViewById(R.id.FeedU...
mFeedURL[7] = (EditText) findViewById(R.id.FeedU...
mFeedURL[8] = (EditText) findViewById(R.id.FeedU...
mFeedURL[9] = (EditText) findViewById(R.id.FeedU...
for (int i = 0; i < RSSReaderApplication.NUM_OF_...
mFeedURL[i].setText(app.feedURL(i));
}
Button button;
button = (Button) findViewById(R.id.Cancel);
button.setOnClickListener(this);
button = (Button) findViewById(R.id.Regist);
button.setOnClickListener(this);
}
~
onCreateメソッド(リスト4-15)では、requestWindowFeatur...
通常、テキストボックス(EditText)を持つアクティビティ...
ここで現在の設定を設定画面に反映させるため、RSSReaderAp...
続いてmNumOfGetに格納したSpinnerに、文字列配列リソースn...
取得フィードURLのEditTextを配列mFeedURLに順次保持したあ...
最後に取消ボタン、登録ボタンのインスタンスを取得して、...
-リスト4-16 :
@Override
public void onClick(View view) {
int id = view.getId();
switch (id) {
case R.id.Cancel:
finish();
break;
case R.id.Regist:
regist();
break;
}
}
~
onClickメソッドでは引数で渡されたViewのIDから、取消(Ca...
リスト4-17がregistメソッドになります。
-リスト4-17 :
private void regist() {
RSSReaderApplication app = (RSSReaderApplicati...
app.setNumberOfGet(NUM_OF_GET_LIST[mNumOfGet.g...
app.clearFeedURL();
for (int i = 0, j = 0; i < RSSReaderApplicatio...
String url = mFeedURL[i].getText().toStri...
if (url.equals("") == false) {
app.setFeedURL(j++, url);
}
}
app.saveConfig();
finish();
}
~
アプリケーションクラスのインスタンスを取得し、これを通...
また、取得フィードURLの設定時には各EditTextの内容をチェ...
最後にsaveConfigメソッドで設定の保存を行い、finishを呼...
以上で設定画面アクティビティの実装は完了です。
**4-4. メイン画面の実装 [#lad27e52]
このアプリケーションのメイン画面であり、RSSフィードを一...
今回はアイテムタイプによってリストビューの各行に設定す...
ベースクラスをArrayAdapter、テンプレートをFeedItemとし...
-リスト4-18 :
public class FeedAdapter extends ArrayAdapter<FeedItem> {
private LayoutInflater mInflate;
public FeedAdapter(Context context, List<FeedItem> ...
super(context, 0, obj);
mInflate = (LayoutInflater) context.getSystemS...
Context.LAYOUT_INFLATER_SERVICE);
}
~
メンバ変数にLayoutInflaterクラスを追加し、コンストラク...
続いてisEnabledメソッドを追加します(リスト4-19)。
-リスト4-19 :
@Override
public boolean isEnabled(int pos) {
FeedItem item = getItem(pos);
if (item.itemType() == FeedItem.ITEMTYPE_FEEDC...
return false;
}
return true;
}
~
isEnabledメソッドはリストビューの各行に対して呼び出され...
-リスト4-20 :
public View getView(final int pos, View convView, V...
View view = convView;
FeedItem item = getItem(pos);
switch (item.itemType()) {
case FeedItem.ITEMTYPE_FEEDCHANNEL:
view = buildChannel(item);
break;
case FeedItem.ITEMTYPE_FEEDITEM:
view = buildItem(item);
break;
}
return view;
}
~
getViewメソッド(リスト4-20)はリストの各行がスクロール...
リスト4-21がbuildChannel/buildItemメソッドになります。
-リスト4-21 :
private View buildChannel(FeedItem item) {
View view = null;
view = mInflate.inflate(R.layout.item_channel,...
TextView tv;
tv = (TextView) view.findViewById(R.id.FeedTit...
tv.setText(item.feedTitle());
return view;
}
private View buildItem(FeedItem item) {
View view = null;
view = mInflate.inflate(R.layout.item_item, nu...
TextView tv;
tv = (TextView) view.findViewById(R.id.Article...
tv.setText(item.articleTitle());
tv = (TextView) view.findViewById(R.id.PubDate);
tv.setText(item.pubDate());
return view;
}
~
それぞれitem_channelレイアウト、item_itemレイアウトを使...
メイン画面ではFeedListを介してHTTP通信を行うことになり...
まずはAsyncTaskから呼び出すメソッドのインターフェースを...
生成されたITaskEntityにbackgroundProcとpostProcという二...
-リスト4-22 :
package com.beatcraft.rssreader;
public interface ITaskEntity {
void backgroundProc();
void postProc();
}
~
続いてAsyncTaskを作成します。ベースクラスをAsyncTask、...
-リスト4-23 :
package com.beatcraft.rssreader;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
public class HttpAccessTask extends AsyncTask<ITaskEntit...
private Activity mActivity;
private ProgressDialog mDialog;
private ITaskEntity mITaskEntity;
public HttpAccessTask(Activity activity) {
mActivity = activity;
}
@Override
protected void onPreExecute() {
mDialog = new ProgressDialog(mActivity);
mDialog.setMessage(mActivity.getString(R.strin...
mDialog.show();
}
@Override
protected Void doInBackground(ITaskEntity... params...
mITaskEntity = params[0];
mITaskEntity.backgroundProc();
return null;
}
@Override
protected void onPostExecute(Void v) {
mITaskEntity.postProc();
mDialog.dismiss();
mDialog = null;
}
}
~
コンストラクタでは引数で受け取ったアクティビティをメン...
doInBackgroundでITaskEntityを受け取って保持し、バックグ...
これでメイン画面を作成する準備が整いました。自動生成さ...
-リスト4-24 :
public class RSSReaderActivity extends ListActivity impl...
private FeedList mList = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
Button button;
button = (Button) findViewById(R.id.Get);
button.setOnClickListener(this);
button = (Button) findViewById(R.id.Config);
button.setOnClickListener(this);
}
~
自動生成されたRSSReaderActivityはベースクラスがActivity...
メンバ変数mListは、HTTP通信により取得したフィードデータ...
onCreateで取得ボタンと設定ボタンをOnClickListenerとして...
-リスト4-25 :
@Override
public void onClick(View view) {
int id = view.getId();
switch (id) {
case R.id.Get:
mList = null;
HttpAccessTask task = new HttpAccessTask(...
task.execute(this);
break;
case R.id.Config:
showConfig();
break;
}
}
~
取得(Get)ボタンではリストを一旦クリアして、HttpAccess...
-リスト4-26 :
@Override
public void backgroundProc() {
RSSReaderApplication app = (RSSReaderApplicati...
mList = new FeedList();
mList.get(app);
}
@Override
public void postProc() {
if (mList.count() > 0) {
ArrayList<FeedItem> list = mList.getList();
if (list != null) {
FeedAdapter adapter = new FeedAdapte...
setListAdapter(adapter);
}
}
else {
Toast.makeText(this, "* NOT FOUND *", Toa...
}
}
~
backgroundProcはHttpAccessTaskによりバックグラウンドス...
postProcはバックグラウンド処理が終了したあと、後処理と...
setListAdapterはListActivityのメソッドで、統合されたリ...
HTTP通信の結果、フィードが一件も取得出来なかった場合に...
-リスト4-27 :
private void showConfig() {
Intent intent = new Intent(getApplicationConte...
com.beatcraft.rssreader.ConfigActivity.cl...
startActivity(intent);
}
~
showConfigメソッドでは設定画面アクティビティ(ConfigAct...
これでメイン画面の実装はひとまず完了です。RSSReaderのマ...
-リスト4-28 :
<manifest xmlns:android="http://schemas.android.com/apk/...
package="com.beatcraft.rssreader"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="7" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:name="com.beatcraft.rssreader.RSSReaderA...
<activity
android:label="@string/app_name"
android:name=".RSSReaderActivity" >
<intent-filter >
<action android:name="android.intent.act...
<category android:name="android.intent.c...
</intent-filter>
</activity>
<activity
android:label="@string/app_name"
android:name=".ConfigActivity" />
</application>
<uses-permission android:name="android.permission.IN...
</uses-permission>
</manifest>
~
まずはapplication要素にRSSReaderApplicationを追加するた...
それから設定画面を呼び出し可能とするためのConfigActivit...
それでは一度実行してみましょう。設定画面で取得フィード...
**4-5. 詳細画面の実装 [#u8e15cd5]
続いて詳細画面アクティビティを作成し、一覧から記事をタ...
-リスト4-29 :
public class DescActivity extends Activity implements Vi...
private static final String WEBVIEW_BEGIN =
"<html><head><meta http-equiv=\"Content-Type\" ...
private static final String WEBVIEW_LINK = "<p><a h...
private static final String WEBVIEW_END = "</body><...
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.description);
Button button = (Button) findViewById(R.id.Back);
button.setOnClickListener(this);
Intent intent = getIntent();
if (intent != null) {
String tmp = "";
String desc = "";
TextView tv;
tv = (TextView) findViewById(R.id.FeedTitle);
tmp = intent.getStringExtra("FeedTitle");
tv.setText(tmp);
tv = (TextView) findViewById(R.id.ArticleTi...
tmp = intent.getStringExtra("ArticleTitle");
tv.setText(tmp);
tv = (TextView) findViewById(R.id.PubDate);
tmp = intent.getStringExtra("PubDate");
tv.setText(tmp);
WebView wv = (WebView) findViewById(R.id.De...
desc = WEBVIEW_BEGIN;
tmp = intent.getStringExtra("Link");
desc += String.format(WEBVIEW_LINK, tmp, tm...
tmp = intent.getStringExtra("Description");
desc += tmp + WEBVIEW_END;
wv.loadDataWithBaseURL("about:blank", desc,...
}
}
~
このアクティビティもrequestWindowFeatureでタイトル行を...
戻る(Back)ボタンのOnClickListenerを設定したあと、getI...
インテントから「FeedTitle(RSSフィードのタイトル)」「A...
次にこのクラスに追加した定数を利用して、WebView「Descri...
HTMLはWEBVIEW_BEGINで始まり、続いてWEBVIEW_LINKを追加し...
続いて、同様に取得した文字列データ「Description(詳細文...
こうして整形したHTML文書をWebViewのloadDataWithBaseURL...
-リスト4-30 :
@Override
public void onClick(View view) {
if (view.getId() == R.id.Back) {
finish();
}
}
~
onClickメソッド(リスト4-30)で戻る(Back)ボタンの処理...
一覧からの記事タップでこのアクティビティを呼び出すため...
-リスト4-31 :
getListView().setOnItemClickListener(new Adapter...
@Override
public void onItemClick(AdapterView<?> pare...
FeedItem item = (FeedItem) getListView()...
Intent intent = new Intent(getApplicatio...
com.beatcraft.rssreader.DescActivit...
intent.putExtra("FeedTitle", item.feedTi...
intent.putExtra("ArticleTitle", item.art...
intent.putExtra("PubDate", item.pubDate(...
intent.putExtra("Description", item.desc...
intent.putExtra("Link", item.link());
startActivity(intent);
}
});
~
getListViewでListActivityの埋め込みリストビューを取得し...
DescActivityを呼び出す明示的なインテントを生成したあと...
このインテントをstartActivityに渡せば、タップした記事を...
最後に詳細画面アクティビティをインテントで呼び出せるよ...
-リスト4-32 :
<activity
android:label="@string/app_name"
android:name=".DescActivity" />
~
以上で完成です。一覧から記事をタップすると、該当記事の...
**4-6. 追加機能:お勧めリスト取得(POST/BASIC認証解説) [...
ここまでで簡易RSSリーダーは完成しましたが、RSSフィード...
-サイト情報
URL: http://labs.beatcraft.com/ja/androidtext/recommend...
BASICユーザー: beatandroid
BASICパスワード: sample
上記URLにPOST変数genreとして、news/music/movieいずれか...
-リスト4-33 :
<?xml version="1.0" encoding="UTF-8"?>
<feedlist>
<genre>news</genre>
<feed>
<title>CNN</title>
<url>http://rss.cnn.com/rss/edition.rss</url>
</feed>
<feed>
<title>The Wall Street Journal</title>
<url>http://online.wsj.com/xml/rss/3_7480.xml</url>
</feed>
<feed>
<title>Reuters</title>
<url>http://feeds.reuters.com/reuters/topNews?format...
</feed>
</feedlist>
~
まずはstrings.xmlに、お勧め選択画面で使用する文字列リソ...
-リスト4-34 :
<string name="recommend">お勧め検索</string>
<string name="search">検索</string>
<string name="addfeed">チェックしたフィードを追加</s...
<string name="label_genre">ジャンル:</string>
<string-array name="genre">
<item>ニュース</item>
<item>音楽</item>
<item>映画</item>
</string-array>
~
続いてレイアウトを作成して行きましょう。recommend.xmlと...
-リスト4-35 recommend.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/...
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip" >
<TextView
android:id="@+id/LabelGenre"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:text="@string/label_genre" />
<Spinner
android:id="@+id/Genre"
android:layout_width="120dip"
android:layout_height="wrap_content" />
<Button
android:id="@+id/Search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_weight="1"
android:text="@string/search" />
</LinearLayout>
<Button
android:id="@+id/Back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="@string/back" />
<CheckBox
android:id="@+id/Feed01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="CheckBox"
android:visibility="invisible" />
<CheckBox
android:id="@+id/Feed02"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="CheckBox"
android:visibility="invisible" />
<CheckBox
android:id="@+id/Feed03"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="CheckBox"
android:visibility="invisible" />
<Button
android:id="@+id/AddFeed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="5dip"
android:text="@string/addfeed"
android:visibility="invisible" />
</LinearLayout>
~
お勧めRSSを取得し、画面に設定したものが図4-4になります。
CENTER:&ref(./04_04.png,);
CENTER:図4-4~
~
~
最上部にはジャンル選択のドロップダウンリスト(Spinner)...
それに続いてお勧めRSSのチェックボックスが三件並び、最後...
続いてこのお勧め画面を呼び出すため、設定画面にボタンを...
-リスト4-36 :
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip" >
<TextView
android:id="@+id/LabelNumOfGet"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:text="@string/label_number_of_ge...
<Spinner
android:id="@+id/NumOfGet"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="@+id/Recommend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_weight="1"
android:text="@string/recommend" />
</LinearLayout>
~
CENTER:&ref(./04_05.png,);
CENTER:図4-5~
~
~
お勧め選択画面の実装を進めていきましょう。android.app.A...
-リスト4-37 :
public class RecommendActivity extends Activity implemen...
private static final String GENRE[] = {"news", "mus...
private static final String POST_DOMAIN = "labs.bea...
private static final String POST_PATH = "/ja/androi...
private static final String POST_USER = "beatandroi...
private static final String POST_PASS = "sample";
private static final int NUM_OF_RECOMMEND = 3;
private Spinner mGenre;
private CheckBox mFeedCheck[];
private String mRecommendTitle[];
private String mRecommendURL[];
private Button mAddFeed;
private int mStat = -1;
~
GENREはお勧めRSSのジャンルとして選択可能な値を格納する...
POST_DOMAINとPOST_PATHは今回用意したお勧めRSS取得用サイ...
NUM_OF_RECOMMENDは各ジャンルでお勧めとして取得可能なRSS...
メンバ変数のうち、mRecommendTitleは取得したお勧めRSSの...
-リスト4-38 :
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.recommend);
ArrayAdapter<CharSequence> adapter;
adapter = ArrayAdapter.createFromResource(this, ...
android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_ite...
mGenre = (Spinner) findViewById(R.id.Genre);
mGenre.setAdapter(adapter);
Button button;
button = (Button) findViewById(R.id.Search);
button.setOnClickListener(this);
button = (Button) findViewById(R.id.Back);
button.setOnClickListener(this);
mAddFeed = (Button) findViewById(R.id.AddFeed);
mAddFeed.setOnClickListener(this);
mFeedCheck = new CheckBox[NUM_OF_RECOMMEND];
mFeedCheck[0] = (CheckBox) findViewById(R.id.Fee...
mFeedCheck[1] = (CheckBox) findViewById(R.id.Fee...
mFeedCheck[2] = (CheckBox) findViewById(R.id.Fee...
mRecommendTitle = new String[NUM_OF_RECOMMEND];
mRecommendURL = new String[NUM_OF_RECOMMEND];
}
~
onCreateメソッド(リスト4-38)でタイトル行の非表示化とr...
検索(Search)ボタン、戻る(Back)ボタン、チェックした...
-リスト4-39 :
@Override
public void onClick(View view) {
int id = view.getId();
switch (id) {
case R.id.Search:
HttpAccessTask task = new HttpAccessTask(...
task.execute(this);
break;
case R.id.Back:
finish();
break;
case R.id.AddFeed:
addFeed();
break;
}
}
~
onClickメソッド(リスト4-39)では検索(Search)ボタンに...
続いてHttpAccessTaskの実行により呼び出されるbackgroundP...
-リスト4-40 :
@Override
public void backgroundProc() {
for (int i = 0; i < NUM_OF_RECOMMEND; ++i) {
mRecommendTitle[i] = "";
mRecommendURL[i] = "";
}
mStat = get(GENRE[mGenre.getSelectedItemPositi...
}
@Override
public void postProc() {
if (mStat == 0) {
for (int i = 0; i < NUM_OF_RECOMMEND; ++i...
mFeedCheck[i].setText(mRecommendTitl...
mFeedCheck[i].setVisibility(View.VIS...
mFeedCheck[i].setChecked(false);
}
mAddFeed.setVisibility(View.VISIBLE);
}
else {
for (int i = 0; i < NUM_OF_RECOMMEND; ++i...
mFeedCheck[i].setText("");
mFeedCheck[i].setVisibility(View.INV...
mFeedCheck[i].setChecked(false);
}
mAddFeed.setVisibility(View.INVISIBLE);
}
}
~
backgroundProcではお勧めRSSを保持する各配列をクリアし、...
postProcではこのmStatをチェックし、0(成功)であればチ...
-リスト4-41 :
private int get(String genre) {
String url = "http://" + POST_DOMAIN + POST_PA...
DefaultHttpClient client = new DefaultHttpClie...
if (client != null) {
client.getParams().setParameter("http.soc...
HttpPost method = null;
try {
method = new HttpPost(url);
}
catch (Exception e) {
e.printStackTrace();
}
if (method == null) {
return -1;
}
HttpResponse response = null;
try {
List<NameValuePair> pair = new Array...
pair.add(new BasicNameValuePair("gen...
method.setEntity(new UrlEncodedFormE...
Credentials cred = new UsernamePassw...
client.getCredentialsProvider().setC...
new AuthScope(POST_DOMAIN, 80),...
response = client.execute(method);
int ret = response.getStatusLine().g...
if (ret == HttpStatus.SC_OK) {
InputStream is = response.getEn...
return parse(is);
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
client.getConnectionManager().shutdo...
}
}
return -1;
}
~
リスト4-41がgetメソッドになります。基本的な内容はRSSフ...
また、生成されたHttpPostのインスタンスに対し、List<Name...
これにより、ジャンルの選択リストから選ばれたニュース(n...
-リスト4-42 :
List<NameValuePair> pair = new Array...
pair.add(new BasicNameValuePair("gen...
method.setEntity(new UrlEncodedFormE...
~
続く二行で、BASIC認証のユーザーとパスワードをHTTPクライ...
-リスト4-43 :
Credentials cred = new UsernamePassw...
client.getCredentialsProvider().setC...
~
まずBASIC認証のユーザー名(定数POST_USER)、パスワード...
この認証情報をHTTPクライアントのgetCredentialsProvider...
getから呼び出されるparseメソッド(リスト4-44)では、フ...
-リスト4-44 :
private int parse(InputStream is) {
int count = 0;
boolean inFeed = false;
XmlPullParser p = Xml.newPullParser();
try {
p.setInput(is, null);
int event = p.getEventType();
while (event != XmlPullParser.END_DOCUMEN...
String elem = null;
String tmp = null;
switch (event) {
case XmlPullParser.START_TAG:
elem = p.getName();
if (elem.equals("feed") == true...
if (inFeed == true) {
count++;
if (count >= NUM_OF_R...
return 0;
}
}
inFeed = true;
}
else if (elem.equals("title") =...
tmp = p.nextText();
if (tmp != null) {
mRecommendTitle[count...
}
}
else if (elem.equals("url") == ...
tmp = p.nextText();
if (tmp != null) {
mRecommendURL[count] ...
}
}
break;
case XmlPullParser.END_TAG:
elem = p.getName();
if (elem.equals("feed") == true...
count++;
if (count >= NUM_OF_RECOMM...
return 0;
}
inFeed = false;
}
break;
}
event = p.next();
}
}
catch (Exception e) {
e.printStackTrace();
return -1;
}
return 0;
}
~
お勧めRSSのタイトルとURLが取得出来たら、それぞれメンバ...
最後にチェックしたフィードを追加(AddFeed)ボタンで呼び...
-リスト4-45 :
private void addFeed() {
int count = 0;
Intent result = new Intent();
for (int i = 0; i < NUM_OF_RECOMMEND; ++i) {
if (mFeedCheck[i].isChecked() == true) {
String key = "";
key = String.format("Recommend%02d",...
result.putExtra(key, mRecommendURL[i...
count++;
}
}
result.putExtra("RecommendCount", count);
setResult(RESULT_OK, result);
finish();
}
~
addFeedではresultというインテントを生成し、チェックされ...
このインテントをsetResultメソッドに定数RESULT_OKととも...
以上でお勧め選択画面の実装は完了です。次は設定画面を修...
ConfigActivityを開き、詳細画面呼び出しで使用する定数を...
public static final int REQUEST_RECOMMEND = 1234;
~
onCreateメソッドの最後に以下を追加し、お勧め検索ボタン...
button = (Button) findViewById(R.id.Recommend);
button.setOnClickListener(this);
~
続いてonClickメソッドのswitch文に、以下のcaseを追加しま...
case R.id.Recommend:
showRecommend();
break;
~
リスト4-46がshowRecommendメソッドになります。
-リスト4-46 :
private void showRecommend() {
Intent intent = new Intent(getApplicationConte...
com.beatcraft.rssreader.RecommendActivity...
startActivityForResult(intent, REQUEST_RECOMME...
}
~
明示的インテントを生成してRecommendActivityを呼び出して...
リスト4-47がonActivityResultになります。
-リスト4-47 :
protected void onActivityResult(int reqCode, int re...
super.onActivityResult(reqCode, result, data);
if (result == RESULT_OK) {
if (reqCode == REQUEST_RECOMMEND) {
int count = 0;
count = data.getIntExtra("RecommendC...
for (int i = 0; i < count; ++i) {
String key = "";
String url = "";
key = String.format("Recommend%...
url = data.getStringExtra(key);
if (url.equals("") == false) {
for (int j = 0; j < RSSRea...
String tmp = mFeedURL...
if (tmp.equals("") ==...
mFeedURL[j].setT...
break;
}
}
}
}
}
}
}
~
結果がRESULT_OKで、リクエストコードがREQUEST_RECOMMEND...
お勧めRSSが一件でも渡されていれば、これを一つずつ取得し...
最後にマニフェストファイルに以下を追加して、お勧め選択...
<activity
android:label="@string/app_name"
android:name=".RecommendActivity" />
~
以上で全ての実装は完了です。実行して動作を確認してみて...
**4-7. RSSReader全ソースコード/XMLファイル [#l297dd24]
-リスト4-48 RSSReaderApplication.java :
package com.beatcraft.rssreader;
import android.app.Application;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
public class RSSReaderApplication extends Application {
private static final String CONF_NAME = "rssreader.c...
public static final int DEFAULT_NUM_OF_GET = 3;
public static final int NUM_OF_FEED = 10;
private int mNumOfGet = DEFAULT_NUM_OF_GET;
private String mFeedURL[];
@Override
public void onCreate() {
mFeedURL = new String[NUM_OF_FEED];
loadConfig();
}
public int numberOfGet() {
return mNumOfGet;
}
public void setNumberOfGet(int numOfGet) {
mNumOfGet = numOfGet;
}
public String feedURL(int index) {
if ((index < 0) || (10 <= index)) {
return null;
}
return mFeedURL[index];
}
public void setFeedURL(int index, String url) {
if ((index < 0) || (NUM_OF_FEED <= index)) {
return;
}
mFeedURL[index] = url;
}
public void clearFeedURL() {
for (int i = 0; i < NUM_OF_FEED; ++i) {
mFeedURL[i] = "";
}
}
public void loadConfig() {
SharedPreferences pref = getSharedPreferences(CO...
mNumOfGet = pref.getInt("NumOfGet", DEFAULT_NUM_...
for (int i = 0; i < NUM_OF_FEED; ++i) {
String key = String.format("FeedURL%02d", (i...
mFeedURL[i] = pref.getString(key, "");
}
}
public void saveConfig() {
SharedPreferences pref = getSharedPreferences(CO...
Editor pe = pref.edit();
pe.putInt("NumOfGet", mNumOfGet);
for (int i = 0; i < NUM_OF_FEED; ++i) {
String key = String.format("FeedURL%02d", (i...
pe.putString(key, mFeedURL[i]);
}
pe.commit();
}
}
~
-リスト4-49 RSSReaderActivity.java :
package com.beatcraft.rssreader;
import java.util.ArrayList;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.Toast;
public class RSSReaderActivity extends ListActivity impl...
private FeedList mList = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
Button button;
button = (Button) findViewById(R.id.Get);
button.setOnClickListener(this);
button = (Button) findViewById(R.id.Config);
button.setOnClickListener(this);
getListView().setOnItemClickListener(new Adapter...
@Override
public void onItemClick(AdapterView<?> paren...
FeedItem item = (FeedItem) getListView()...
Intent intent = new Intent(getApplicatio...
intent.putExtra("FeedTitle", item.feedTi...
intent.putExtra("ArticleTitle", item.art...
intent.putExtra("PubDate", item.pubDate(...
intent.putExtra("Description", item.desc...
intent.putExtra("Link", item.link());
startActivity(intent);
}
});
}
@Override
public void onClick(View view) {
int id = view.getId();
switch (id) {
case R.id.Get:
mList = null;
HttpAccessTask task = new HttpAccessTask(thi...
task.execute(this);
break;
case R.id.Config:
showConfig();
break;
}
}
@Override
public void backgroundProc() {
RSSReaderApplication app = (RSSReaderApplication...
mList = new FeedList();
mList.get(app);
}
@Override
public void postProc() {
if (mList.count() > 0) {
ArrayList<FeedItem> list = mList.getList();
if (list != null) {
FeedAdapter adapter = new FeedAdapter(th...
setListAdapter(adapter);
}
}
else {
Toast.makeText(this, "* NOT FOUND *", Toast....
}
}
private void showConfig() {
Intent intent = new Intent(getApplicationContext...
startActivity(intent);
}
}
~
-リスト4-50 DescActivity.java :
package com.beatcraft.rssreader;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.TextView;
public class DescActivity extends Activity implements Vi...
private static final String WEBVIEW_BEGIN =
"<html><head><meta http-equiv=\"Content-Type\" c...
private static final String WEBVIEW_LINK = "<p><a hr...
private static final String WEBVIEW_END = "</body></...
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.description);
Button button = (Button) findViewById(R.id.Back);
button.setOnClickListener(this);
Intent intent = getIntent();
if (intent != null) {
String tmp = "";
String desc = "";
TextView tv;
tv = (TextView) findViewById(R.id.FeedTitle);
tmp = intent.getStringExtra("FeedTitle");
tv.setText(tmp);
tv = (TextView) findViewById(R.id.ArticleTit...
tmp = intent.getStringExtra("ArticleTitle");
tv.setText(tmp);
tv = (TextView) findViewById(R.id.PubDate);
tmp = intent.getStringExtra("PubDate");
tv.setText(tmp);
WebView wv = (WebView) findViewById(R.id.Des...
desc = WEBVIEW_BEGIN;
tmp = intent.getStringExtra("Link");
desc += String.format(WEBVIEW_LINK, tmp, tmp);
tmp = intent.getStringExtra("Description");
desc += tmp + WEBVIEW_END;
wv.loadDataWithBaseURL("about:blank", desc, ...
}
}
@Override
public void onClick(View view) {
if (view.getId() == R.id.Back) {
finish();
}
}
}
~
-リスト4-51 ConfigActivity.java :
package com.beatcraft.rssreader;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager.LayoutParams;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
public class ConfigActivity extends Activity implements ...
public static final int REQUEST_RECOMMEND = 1234;
private static final int NUM_OF_GET_LIST[] = {1, 3, ...
private Spinner mNumOfGet;
private EditText mFeedURL[];
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setSoftInputMode(LayoutParams.S...
setContentView(R.layout.config);
RSSReaderApplication app = (RSSReaderApplication...
ArrayAdapter<CharSequence> adapter;
adapter = ArrayAdapter.createFromResource(this, ...
adapter.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_ite...
mNumOfGet = (Spinner) findViewById(R.id.NumOfGet);
mNumOfGet.setAdapter(adapter);
for (int i = 0; i < 3; ++i) {
if (NUM_OF_GET_LIST[i] == app.numberOfGet()) {
mNumOfGet.setSelection(i);
break;
}
}
mFeedURL = new EditText[RSSReaderApplication.NUM...
mFeedURL[0] = (EditText) findViewById(R.id.FeedU...
mFeedURL[1] = (EditText) findViewById(R.id.FeedU...
mFeedURL[2] = (EditText) findViewById(R.id.FeedU...
mFeedURL[3] = (EditText) findViewById(R.id.FeedU...
mFeedURL[4] = (EditText) findViewById(R.id.FeedU...
mFeedURL[5] = (EditText) findViewById(R.id.FeedU...
mFeedURL[6] = (EditText) findViewById(R.id.FeedU...
mFeedURL[7] = (EditText) findViewById(R.id.FeedU...
mFeedURL[8] = (EditText) findViewById(R.id.FeedU...
mFeedURL[9] = (EditText) findViewById(R.id.FeedU...
for (int i = 0; i < RSSReaderApplication.NUM_OF_...
mFeedURL[i].setText(app.feedURL(i));
}
Button button;
button = (Button) findViewById(R.id.Recommend);
button.setOnClickListener(this);
button = (Button) findViewById(R.id.Cancel);
button.setOnClickListener(this);
button = (Button) findViewById(R.id.Regist);
button.setOnClickListener(this);
}
@Override
public void onClick(View view) {
int id = view.getId();
switch (id) {
case R.id.Recommend:
showRecommend();
break;
case R.id.Cancel:
finish();
break;
case R.id.Regist:
regist();
break;
}
}
protected void onActivityResult(int reqCode, int res...
super.onActivityResult(reqCode, result, data);
if (result == RESULT_OK) {
if (reqCode == REQUEST_RECOMMEND) {
int count = 0;
count = data.getIntExtra("RecommendCount...
for (int i = 0; i < count; ++i) {
String key = "";
String url = "";
key = String.format("Recommend%02d",...
url = data.getStringExtra(key);
if (url.equals("") == false) {
for (int j = 0; j < RSSReaderApp...
String tmp = mFeedURL[j].get...
if (tmp.equals("") == true) {
mFeedURL[j].setText(url);
break;
}
}
}
}
}
}
}
private void showRecommend() {
Intent intent = new Intent(getApplicationContext...
startActivityForResult(intent, REQUEST_RECOMMEND);
}
private void regist() {
RSSReaderApplication app = (RSSReaderApplication...
app.setNumberOfGet(NUM_OF_GET_LIST[mNumOfGet.get...
app.clearFeedURL();
for (int i = 0, j = 0; i < RSSReaderApplication....
String url = mFeedURL[i].getText().toString(...
if (url.equals("") == false) {
app.setFeedURL(j++, url);
}
}
app.saveConfig();
finish();
}
}
~
-リスト4-52 RecommendActivity.java :
package com.beatcraft.rssreader;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.xmlpull.v1.XmlPullParser;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Xml;
import android.view.View;
import android.view.Window;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.Spinner;
public class RecommendActivity extends Activity implemen...
private static final String GENRE[] = {"news", "musi...
private static final String POST_DOMAIN = "labs.beat...
private static final String POST_PATH = "/ja/android...
private static final String POST_USER = "beatandroid";
private static final String POST_PASS = "sample";
private static final int NUM_OF_RECOMMEND = 3;
private Spinner mGenre;
private CheckBox mFeedCheck[];
private String mRecommendTitle[];
private String mRecommendURL[];
private Button mAddFeed;
private int mStat = -1;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.recommend);
ArrayAdapter<CharSequence> adapter;
adapter = ArrayAdapter.createFromResource(this, ...
adapter.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_ite...
mGenre = (Spinner) findViewById(R.id.Genre);
mGenre.setAdapter(adapter);
Button button;
button = (Button) findViewById(R.id.Search);
button.setOnClickListener(this);
button = (Button) findViewById(R.id.Back);
button.setOnClickListener(this);
mAddFeed = (Button) findViewById(R.id.AddFeed);
mAddFeed.setOnClickListener(this);
mFeedCheck = new CheckBox[NUM_OF_RECOMMEND];
mFeedCheck[0] = (CheckBox) findViewById(R.id.Fee...
mFeedCheck[1] = (CheckBox) findViewById(R.id.Fee...
mFeedCheck[2] = (CheckBox) findViewById(R.id.Fee...
mRecommendTitle = new String[NUM_OF_RECOMMEND];
mRecommendURL = new String[NUM_OF_RECOMMEND];
}
@Override
public void onClick(View view) {
int id = view.getId();
switch (id) {
case R.id.Search:
HttpAccessTask task = new HttpAccessTask(thi...
task.execute(this);
break;
case R.id.Back:
finish();
break;
case R.id.AddFeed:
addFeed();
break;
}
}
@Override
public void backgroundProc() {
for (int i = 0; i < NUM_OF_RECOMMEND; ++i) {
mRecommendTitle[i] = "";
mRecommendURL[i] = "";
}
mStat = get(GENRE[mGenre.getSelectedItemPosition...
}
@Override
public void postProc() {
if (mStat == 0) {
for (int i = 0; i < NUM_OF_RECOMMEND; ++i) {
mFeedCheck[i].setText(mRecommendTitle[i]);
mFeedCheck[i].setVisibility(View.VISIBLE);
mFeedCheck[i].setChecked(false);
}
mAddFeed.setVisibility(View.VISIBLE);
}
else {
for (int i = 0; i < NUM_OF_RECOMMEND; ++i) {
mFeedCheck[i].setText("");
mFeedCheck[i].setVisibility(View.INVISIB...
mFeedCheck[i].setChecked(false);
}
mAddFeed.setVisibility(View.INVISIBLE);
}
}
private int get(String genre) {
String url = "http://" + POST_DOMAIN + POST_PATH;
DefaultHttpClient client = new DefaultHttpClient...
if (client != null) {
client.getParams().setParameter("http.socket...
HttpPost method = null;
try {
method = new HttpPost(url);
}
catch (Exception e) {
e.printStackTrace();
}
if (method == null) {
return -1;
}
HttpResponse response = null;
try {
List<NameValuePair> pair = new ArrayList...
pair.add(new BasicNameValuePair("genre",...
method.setEntity(new UrlEncodedFormEntit...
Credentials cred = new UsernamePasswordC...
client.getCredentialsProvider().setCrede...
response = client.execute(method);
int ret = response.getStatusLine().getSt...
if (ret == HttpStatus.SC_OK) {
InputStream is = response.getEntity(...
return parse(is);
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
client.getConnectionManager().shutdown();
}
}
return -1;
}
private int parse(InputStream is) {
int count = 0;
boolean inFeed = false;
XmlPullParser p = Xml.newPullParser();
try {
p.setInput(is, null);
int event = p.getEventType();
while (event != XmlPullParser.END_DOCUMENT) {
String elem = null;
String tmp = null;
switch (event) {
case XmlPullParser.START_TAG:
elem = p.getName();
if (elem.equals("feed") == true) {
if (inFeed == true) {
count++;
if (count >= NUM_OF_RECOMMEN...
return 0;
}
}
inFeed = true;
}
else if (elem.equals("title") == tru...
tmp = p.nextText();
if (tmp != null) {
mRecommendTitle[count] = tmp;
}
}
else if (elem.equals("url") == true) {
tmp = p.nextText();
if (tmp != null) {
mRecommendURL[count] = tmp;
}
}
break;
case XmlPullParser.END_TAG:
elem = p.getName();
if (elem.equals("feed") == true) {
count++;
if (count >= NUM_OF_RECOMMEND) {
return 0;
}
inFeed = false;
}
break;
}
event = p.next();
}
}
catch (Exception e) {
e.printStackTrace();
return -1;
}
return 0;
}
private void addFeed() {
int count = 0;
Intent result = new Intent();
for (int i = 0; i < NUM_OF_RECOMMEND; ++i) {
if (mFeedCheck[i].isChecked() == true) {
String key = "";
key = String.format("Recommend%02d", (co...
result.putExtra(key, mRecommendURL[i]);
count++;
}
}
result.putExtra("RecommendCount", count);
setResult(RESULT_OK, result);
finish();
}
}
~
-リスト4-53 FeedItem.java :
package com.beatcraft.rssreader;
public class FeedItem {
public static final int ITEMTYPE_FEEDCHANNEL = 0;
public static final int ITEMTYPE_FEEDITEM = 1;
private int mItemType;
private String mFeedTitle = "";
private String mArticleTitle = "";
private String mPubDate = "";
private String mDescription = "";
private String mLink = "";
public FeedItem(int itemType) {
mItemType = itemType;
}
public int itemType() {
return mItemType;
}
public String feedTitle() {
return mFeedTitle;
}
public void setFeedTitle(String title) {
mFeedTitle = title;
}
public String articleTitle() {
return mArticleTitle;
}
public void setArticleTitle(String title) {
mArticleTitle = title;
}
public String pubDate() {
return mPubDate;
}
public void setPubDate(String pubDate) {
mPubDate = pubDate;
}
public String description() {
return mDescription;
}
public void setDescription(String description) {
mDescription = description;
}
public String link() {
return mLink;
}
public void setLink(String link) {
mLink = link;
}
}
~
-リスト4-54 FeedList.java :
package com.beatcraft.rssreader;
import java.io.InputStream;
import java.util.ArrayList;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.xmlpull.v1.XmlPullParser;
import android.util.Xml;
public class FeedList {
private ArrayList<FeedItem> mList = null;
public FeedList() {
mList = new ArrayList<FeedItem>();
}
public ArrayList<FeedItem> getList() {
return mList;
}
public int count() {
if (mList != null) {
return mList.size();
}
return 0;
}
public int get(RSSReaderApplication app) {
int success = 0;
for (int i = 0; i < RSSReaderApplication.NUM_OF_...
String url = app.feedURL(i);
if (url.equals("") == true) {
continue;
}
DefaultHttpClient client = new DefaultHttpCl...
if (client != null) {
client.getParams().setParameter("http.so...
HttpGet method = null;
try {
method = new HttpGet(url);
}
catch (Exception e) {
e.printStackTrace();
}
if (method == null) {
continue;
}
HttpResponse response = null;
try {
response = client.execute(method);
int ret = response.getStatusLine().g...
if (ret == HttpStatus.SC_OK) {
InputStream is = response.getEnt...
if (parse(is, app.numberOfGet())...
success++;
}
is.close();
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
client.getConnectionManager().shutdo...
}
}
}
return success;
}
private int parse(InputStream is, int max) {
int count = 0;
boolean inChannel = false;
boolean inItem = false;
FeedItem item = null;
String feedTitle = "";
XmlPullParser p = Xml.newPullParser();
try {
p.setInput(is, null);
int event = p.getEventType();
while (event != XmlPullParser.END_DOCUMENT) {
String elem = null;
String tmp = null;
switch (event) {
case XmlPullParser.START_TAG:
elem = p.getName();
if (elem.equals("channel") == true) {
inChannel = true;
item = new FeedItem(FeedItem.ITE...
}
else if (elem.equals("item") == true...
if (inChannel == true) {
if (item != null) {
mList.add(item);
item = null;
count++;
}
inChannel = false;
}
inItem = true;
item = new FeedItem(FeedItem.ITE...
item.setFeedTitle(feedTitle);
}
else if (elem.equals("title") == tru...
tmp = p.nextText();
if ((tmp != null) && (item != nu...
if (inChannel == true) {
feedTitle = tmp;
item.setFeedTitle(tmp);
}
else if (inItem == true) {
item.setArticleTitle(tmp);
}
}
}
else if ((elem.equals("pubDate") == ...
|| (elem.equals("date") == t...
if (inItem == true) {
tmp = p.nextText();
if ((tmp != null) && (item !...
item.setPubDate(tmp);
}
}
}
else if (elem.equals("description") ...
if (inItem == true) {
tmp = p.nextText();
if ((tmp != null) && (item !...
item.setDescription(tmp);
}
}
}
else if (elem.equals("link") == true...
if (inItem == true) {
tmp = p.nextText();
if ((tmp != null) && (item !...
item.setLink(tmp);
}
}
}
break;
case XmlPullParser.END_TAG:
elem = p.getName();
if (elem.equals("channel") == true) {
if (inChannel == true) {
if (item != null) {
mList.add(item);
item = null;
count++;
}
inChannel = false;
}
}
else if (elem.equals("item") == true...
if (inItem == true) {
if (item != null) {
mList.add(item);
item = null;
count++;
max--;
if (max == 0) {
return count;
}
}
inItem = false;
}
}
}
event = p.next();
}
}
catch (Exception e) {
e.printStackTrace();
return 0;
}
return count;
}
}
~
-リスト4-55 FeedAdapter.java :
package com.beatcraft.rssreader;
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class FeedAdapter extends ArrayAdapter<FeedItem> {
private LayoutInflater mInflate;
public FeedAdapter(Context context, List<FeedItem> o...
super(context, 0, obj);
mInflate = (LayoutInflater) context.getSystemSer...
}
@Override
public boolean isEnabled(int pos) {
FeedItem item = getItem(pos);
if (item.itemType() == FeedItem.ITEMTYPE_FEEDCHA...
return false;
}
return true;
}
public View getView(final int pos, View convView, Vi...
View view = convView;
FeedItem item = getItem(pos);
switch (item.itemType()) {
case FeedItem.ITEMTYPE_FEEDCHANNEL:
view = buildChannel(item);
break;
case FeedItem.ITEMTYPE_FEEDITEM:
view = buildItem(item);
break;
}
return view;
}
private View buildChannel(FeedItem item) {
View view = null;
view = mInflate.inflate(R.layout.item_channel, n...
TextView tv;
tv = (TextView) view.findViewById(R.id.FeedTitle);
tv.setText(item.feedTitle());
return view;
}
private View buildItem(FeedItem item) {
View view = null;
view = mInflate.inflate(R.layout.item_item, null);
TextView tv;
tv = (TextView) view.findViewById(R.id.ArticleTi...
tv.setText(item.articleTitle());
tv = (TextView) view.findViewById(R.id.PubDate);
tv.setText(item.pubDate());
return view;
}
}
~
-リスト4-56 ITaskEntity.java :
package com.beatcraft.rssreader;
public interface ITaskEntity {
void backgroundProc();
void postProc();
}
~
-リスト4-57 HttpAccessTask.java :
package com.beatcraft.rssreader;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
public class HttpAccessTask extends AsyncTask<ITaskEntit...
private Activity mActivity;
private ProgressDialog mDialog;
private ITaskEntity mITaskEntity;
public HttpAccessTask(Activity activity) {
mActivity = activity;
}
@Override
protected void onPreExecute() {
mDialog = new ProgressDialog(mActivity);
mDialog.setMessage(mActivity.getString(R.string....
mDialog.show();
}
@Override
protected Void doInBackground(ITaskEntity... params) {
mITaskEntity = params[0];
mITaskEntity.backgroundProc();
return null;
}
@Override
protected void onPostExecute(Void v) {
mITaskEntity.postProc();
mDialog.dismiss();
mDialog = null;
}
}
~
-リスト4-58 main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/...
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip" >
<Button
android:id="@+id/Get"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_weight="1"
android:text="@string/get_feed" />
<Button
android:id="@+id/Config"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_weight="1"
android:text="@string/config" />
</LinearLayout>
<ListView
android:id="@+id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:fastScrollEnabled="true" >
</ListView>
</LinearLayout>
~
-リスト4-59 item_channel.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/...
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#cccccc"
android:orientation="vertical" >
<TextView
android:id="@+id/FeedTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="FeedTitle"
android:textColor="#000000"
android:textSize="16dip"
android:textStyle="bold" />
</LinearLayout>
~
-リスト4-60 item_item.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/...
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/ArticleTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="ArticleTitle" />
<TextView
android:id="@+id/PubDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_margin="5dip"
android:text="pubDate" />
</LinearLayout>
~
-リスト4-61 description.xml :
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/ap...
android:id="@+id/ScrollView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/Back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="@string/back" />
<TextView
android:id="@+id/FeedTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:text="FeedTitle"
android:textSize="16dip"
android:textStyle="bold" />
<TextView
android:id="@+id/ArticleTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:text="ArticleTitle" />
<TextView
android:id="@+id/PubDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginRight="10dip"
android:text="pubDate" />
<android.webkit.WebView
android:id="@+id/Description"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_margin="5dip"
android:layout_weight="1" >
</android.webkit.WebView>
</LinearLayout>
</ScrollView>
~
-リスト4-62 config.xml :
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/ap...
android:id="@+id/ScrollView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip" >
<TextView
android:id="@+id/LabelNumOfGet"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:text="@string/label_number_of_ge...
<Spinner
android:id="@+id/NumOfGet"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="@+id/Recommend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_weight="1"
android:text="@string/recommend" />
</LinearLayout>
<EditText
android:id="@+id/FeedURL01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" >
<requestFocus />
</EditText>
<EditText
android:id="@+id/FeedURL02"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL03"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL04"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL05"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL06"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL07"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL08"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL09"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<EditText
android:id="@+id/FeedURL10"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:inputType="textUri" />
<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip" >
<Button
android:id="@+id/Cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_weight="1"
android:text="@string/cancel" />
<Button
android:id="@+id/Regist"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_weight="1"
android:text="@string/regist" />
</LinearLayout>
</LinearLayout>
</ScrollView>
~
-リスト4-63 recommend.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/...
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip" >
<TextView
android:id="@+id/LabelGenre"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:text="@string/label_genre" />
<Spinner
android:id="@+id/Genre"
android:layout_width="120dip"
android:layout_height="wrap_content" />
<Button
android:id="@+id/Search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_weight="1"
android:text="@string/search" />
</LinearLayout>
<Button
android:id="@+id/Back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="@string/back" />
<CheckBox
android:id="@+id/Feed01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="CheckBox"
android:visibility="invisible" />
<CheckBox
android:id="@+id/Feed02"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="CheckBox"
android:visibility="invisible" />
<CheckBox
android:id="@+id/Feed03"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="CheckBox"
android:visibility="invisible" />
<Button
android:id="@+id/AddFeed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="5dip"
android:text="@string/addfeed"
android:visibility="invisible" />
</LinearLayout>
~
-リスト4-64 AndroidManifest.xml :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/...
package="com.beatcraft.rssreader"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="7" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:name="com.beatcraft.rssreader.RSSReaderA...
<activity
android:label="@string/app_name"
android:name=".RSSReaderActivity" >
<intent-filter >
<action android:name="android.intent.act...
<category android:name="android.intent.c...
</intent-filter>
</activity>
<activity
android:label="@string/app_name"
android:name=".ConfigActivity" />
<activity
android:label="@string/app_name"
android:name=".DescActivity" />
<activity
android:label="@string/app_name"
android:name=".RecommendActivity" />
</application>
<uses-permission android:name="android.permission.IN...
</uses-permission>
</manifest>
~
----
RIGHT:内藤
ページ名:
BC::labsへの質問は、bc9-dev @ googlegroups.com までお願い致します。