Android ListFragment と AsyncTaskLoader のメモ
AysncTaskLoader を使用して非同期に、ATND の WebサービスからXMLを取得して表示するメモ。
Activity や Fragment には、サポートライブラリ(android.support.v4) を利用している。
作りが面倒くさいけど、またきっと使うことがあると思うのでメモしておく。
Activity
基本的には一式ここに放り込んである。
XMLの解析には、Simple を利用。Event クラスはATNDのイベントを表すPOJO。
package info.typea.atndcalendar; import info.typea.atndcalendar.model.atnd.Event; import info.typea.atndcalendar.model.atnd.EventSearchResponse; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; 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.simpleframework.xml.Serializer; import org.simpleframework.xml.core.Persister; import android.content.Context; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.ListFragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.AsyncTaskLoader; import android.support.v4.content.Loader; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.TextView; public class AtndCalendarActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_atnd_calendar); FragmentManager fm = getSupportFragmentManager(); if (fm.findFragmentById(android.R.id.content) == null) { EventFragment list = new EventFragment(); fm.beginTransaction().add(android.R.id.content, list).commit(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.atnd_calendar, menu); return true; } public static class EventListAdapter extends ArrayAdapter{ private final LayoutInflater inflater; public EventListAdapter(Context context) { super(context, android.R.layout.simple_list_item_2); inflater = (LayoutInflater)context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); } public void setData(List entities) { clear(); if (entities != null) { for (Event entity : entities) { add(entity); } } } @Override public View getView(int position, View convertView, ViewGroup parent) { View view; if (convertView == null) { view = inflater.inflate(R.layout.event_item, parent, false); } else { view = convertView; } Event item = getItem(position); ((TextView)view.findViewById(R.id.txt_event)) .setText(item.getTitle()); return view; } } public static class EventFragment extends ListFragment implements LoaderManager.LoaderCallbacks
> { private EventListAdapter eventAdapter; @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setEmptyText("No Event"); eventAdapter = new EventListAdapter(getActivity()); setListAdapter(eventAdapter); setListShown(false); getLoaderManager().initLoader(0, null, this); } @Override public Loader
> onCreateLoader(int id, Bundle args) { return new EventLoader(getActivity()); } @Override public void onLoadFinished(Loader
> loader, List data) { eventAdapter.setData(data); setListShown(true); } @Override public void onLoaderReset(Loader
> loader) { eventAdapter.setData(null); } } public static class EventLoader extends AsyncTaskLoader
> { public static final String EVENT_SEARCH_URL = "http://api.atnd.org/eventatnd/event/"; public EventLoader(Context context) { super(context); } @Override public List loadInBackground() { List list = new ArrayList (); try { List queryParms = new ArrayList (); queryParms.add(new BasicNameValuePair("format", "xml")); queryParms.add(new BasicNameValuePair("keyword", "python")); //todo HttpPost post = new HttpPost(EVENT_SEARCH_URL); post.setEntity(new UrlEncodedFormEntity(queryParms,HTTP.UTF_8)); DefaultHttpClient client = new DefaultHttpClient(); HttpResponse res = client.execute(post); InputStream in = res.getEntity().getContent(); StringBuilder buf = new StringBuilder(); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); String l = null; while((l = reader.readLine()) != null) { buf.append(l).append("\r\n"); } Serializer serializer = new Persister(); EventSearchResponse hash = serializer.read(EventSearchResponse.class, buf.toString()); return hash.getEvents(); } catch (Exception e){ Log.e("atnd","", e); } return list; } @Override protected void onStartLoading() { forceLoad(); } @Override protected void onStopLoading() { cancelLoad(); } @Override public void reset() { super.reset(); onStopLoading(); } } }
Activityのレイアウト
activity_atnd_calendar.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <fragment android:id="@+id/fragment_event" android:name="info.typea.atndcalendar.AtndCalendarActivity$EventFragment" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
リストアイテムのレイアウト
event_item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/txt_event" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="" /> </LinearLayout>
起動時にリストを読み込んでいる。
読み込まれた。
以下の書籍を参考に。