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>

 

起動時にリストを読み込んでいる。

atnd_event_load

読み込まれた。

atend_event_loaded

以下の書籍を参考に。

Follow me!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です