最近のAndroidでのデータの読み込みはLoaderというものを使うらしいです。ちょっとやってみました。
オレオレ仕様にカスタムできるLoader
カーソル前提のLoaderもあるんですが、自前のデータ読み込み処理を書けるAsyncTaskLoader
AsyncTaskLoader
// めんどいのでActivityの内部クラスにした public static class Person { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return this.name; } }
適当にこのクラスを生成する実装は以下のようになります。画面にeditTextという名前のEditTextを置いていて、そいつから取得したテキストをベースに先ほどのPersonクラスを組み立てては、Listに突っ込んでいます。時間のかかる処理っぽく少しSleepも入れています。
final Random r = new Random(); final String input = this.editText.getText().toString(); AsyncTaskLoader<List<Person>> loader = new AsyncTaskLoader<List<Person>>(this) { @Override public List<Person> loadInBackground() { Log.d("MyActivity", "loadInBackground"); int count = r.nextInt(100); List<Person> result = new ArrayList<Person>(); for (int i = 0; i < count; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } Person p = new Person(); p.setName(input + " " + i); result.add(p); } return result; } };
Loaderを使うためのコールバックインターフェース
Javaってコールバック地獄でめんどくさいですよね…。Loaderをバックグラウンドで実行するために、以下のインターフェースを実装しないといけません。これは先ほど示したAsyncTaskLoaderクラスとは別ものです。LoaderManager.LoaderCallbacks
LoaderCallbacks
- onCreateLoader: Loaderを作るメソッド
- onLoadFinished: Loaderの処理が終わった後に呼ばれるメソッド
- onLoaderReset: リセットしたときに呼ばれるメソッド
ActivityにLoaderCallbacks
まず、onCreateLoaderメソッドです。こいつはさっきのAsyncTaskLoaderを作成しています。 そして、Loaderの処理をキックするforceLoadメソッドを呼んでいます(大事)
@Override public Loader<List<Person>> onCreateLoader(int id, Bundle args) { Log.d("MyActivity", "onCreateLoader"); Random r = new Random(); final String input = this.editText.getText().toString(); AsyncTaskLoader<List<Person>> loader = new AsyncTaskLoader<List<Person>>(this) { @Override public List<Person> loadInBackground() { Log.d("MyActivity", "loadInBackground"); int count = r.nextInt(100); List<Person> result = new ArrayList<Person>(); for (int i = 0; i < count; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } Person p = new Person(); p.setName(input + " " + i); result.add(p); } return result; } }; loader.forceLoad(); return loader; }
そして、onLoadFinishedメソッドで読み込みが終わったときの処理を書きます。ここではArrayAdapterにデータをセットしています。
@Override public void onLoadFinished(Loader<List<Person>> loader, List<Person> data) { Log.d("MyActivity", "onLoadFinished"); this.peopleAdapter.clear(); this.peopleAdapter.addAll(data); } @Override public void onLoaderReset(Loader<List<Person>> loader) { }
ついでに、何もしないonLoaderResetも書いておきました。
コード全体
レイアウトファイル。EditTextとListView置いただけの画面
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/editText" /> <ListView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/listView" /> </LinearLayout>
Activityに全部処理かいてます///
package com.example.kazuki.myapplication; import android.app.Activity; import android.app.LoaderManager; import android.content.AsyncTaskLoader; import android.content.Loader; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.ListView; import java.util.ArrayList; import java.util.List; import java.util.Random; public class MyActivity extends Activity implements LoaderManager.LoaderCallbacks<List<MyActivity.Person>> { private EditText editText; private ListView listView; private ArrayAdapter<Person> peopleAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my); this.editText = (EditText) this.findViewById(R.id.editText); this.listView = (ListView) this.findViewById(R.id.listView); this.peopleAdapter = new ArrayAdapter<Person>(this, android.R.layout.simple_list_item_1); this.listView.setAdapter(this.peopleAdapter); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.my, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { Log.d("MyActivity", "onOptionsItemSelected"); this.getLoaderManager().restartLoader(0, null, this); return true; } return super.onOptionsItemSelected(item); } @Override public Loader<List<Person>> onCreateLoader(int id, Bundle args) { Log.d("MyActivity", "onCreateLoader"); final Random r = new Random(); final String input = this.editText.getText().toString(); AsyncTaskLoader<List<Person>> loader = new AsyncTaskLoader<List<Person>>(this) { @Override public List<Person> loadInBackground() { Log.d("MyActivity", "loadInBackground"); int count = r.nextInt(100); List<Person> result = new ArrayList<Person>(); for (int i = 0; i < count; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } Person p = new Person(); p.setName(input + " " + i); result.add(p); } return result; } }; loader.forceLoad(); return loader; } @Override public void onLoadFinished(Loader<List<Person>> loader, List<Person> data) { Log.d("MyActivity", "onLoadFinished"); this.peopleAdapter.clear(); this.peopleAdapter.addAll(data); } @Override public void onLoaderReset(Loader<List<Person>> loader) { } public static class Person { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return this.name; } } }