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>
起動時にリストを読み込んでいる。
読み込まれた。
以下の書籍を参考に。
