展開可能なリスト ビュー アプリケーション、アダプターをBaseExpandableListAdapter (RuleBookAdapter.java) からSimpleCursorTreeAdapter (RuleBookTreeAdapter.java) に変更して、コンテンツ プロバイダー (TDAProvider) にアクセスしようとしています。
(RuleBookTreeAdapter.java) を作成するためのテンプレートとして、Android SDK ApiDemos ExpandableList2.java を使用しました。私は Android 開発の初心者です。私の目標は、よりプロフェッショナルなアプリケーションを作成できるように、コンテンツ プロバイダーでアダプターを実装することです。これを実装しようとすると、2 つの問題が発生します。
問題 1)メイン アクティビティ (ActivityRuleBook.java) で、次のように新しいアダプターを使用するように変更しました。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_expandable);
elv=(ExpandableListView)findViewById(R.id.expandableListView1);
elv.setAdapter(new RuleBookTreeAdapter());
// elv.setAdapter(new RuleBookAdapter(this));
}
「タイプ ExpandableListView のメソッド setAdapter(ListAdapter) は、引数 (RuleBookTreeAdapter) には適用できません」というエラーが表示されます。どのパラメーターを探しているのかわかりません。Android ApiDemos プログラムで呼び出しプログラムを見つけようとしましたが、役に立たず、インターネットとスタックオーバーフロー (提案と同様の質問) を検索しましたが、ExpandableList2.java 以外の、カーソルに支えられた SimpleCursorTreeAdapter の良い例を見つけることができません。 SDK サンプルから。
問題 2) SimpleCursorTreeAdapter (RuleBookTreeAdapter.getChildrenCursor) では、クエリを正確に作成して子データを取得する方法がわかりません。
これは、関連する列を含む、データベース内の 2 つのテーブルのレイアウトです。
テーブル: chapters (これはアプリケーションの親テーブルです) 列: _id、chapter char(2)、chaptertitle char(70) URI: CONTENT_URI chapters
テーブル: rules (これはアプリケーションの子テーブルです) 列: _id、rule varchar(10)、chapter char(2)、ruletitle char(50) URI: CONTENT_URI_RULES rules
注: rules テーブルの章フィールドは、章テーブルへの外部キーです。これらのテーブルのデータは静的であるため、更新は行われず、各親には少なくとも 1 つ以上の子があります。
ヘルプやコメントをいただければ幸いです。お時間をいただきありがとうございます。すてきな一日を。
メイン アクティビティ ソース コードActivityRuleBook.java
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.widget.ExpandableListView;
import android.widget.ListAdapter;
public class ActivityRuleBook extends Activity {
ExpandableListView elv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_expandable);
elv=(ExpandableListView)findViewById(R.id.expandableListView1);
elv.setAdapter(new RuleBookTreeAdapter());
// elv.setAdapter(new RuleBookAdapter(this));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.expandable, menu);
return true;
}
}
RuleBookAdapter.javaソース コード。私の元の BaseExpandableListAdapter は、私が置き換えようとしている文字列を使用しています。
import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;
public class RuleBookAdapter extends BaseExpandableListAdapter {
private Context context;
String []grouplist={"01 Chapter","02 Chapter"};
String [][]childlist={
{
"01A Follow all rules","01B The USCF RULES"
},
{
"02A The Rules are WRONG","02B The President is right"
}
};
public RuleBookAdapter(Context context) {
this.context=context;
}
@Override
public Object getChild(int arg0, int arg1) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
TextView tv=new TextView(context);
tv.setText(childlist[groupPosition][childPosition]);
tv.setPadding(60, 10, 10, 10);
return tv;
}
@Override
public int getChildrenCount(int groupPosition) {
// TODO Auto-generated method stub
return childlist[groupPosition].length;
}
@Override
public Object getGroup(int groupPosition) {
// TODO Auto-generated method stub
return groupPosition;
}
@Override
public int getGroupCount() {
// TODO Auto-generated method stub
return grouplist.length;
}
@Override
public long getGroupId(int groupPosition) {
// TODO Auto-generated method stub
return groupPosition;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
TextView tv=new TextView(context);
tv.setText(grouplist[groupPosition]);
tv.setPadding(50, 10, 10, 10);
tv.setTextColor(Color.RED);
return tv;
}
@Override
public boolean hasStableIds() {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return true;
}
}
RuleBookTreeAdapter.javaソース コード。私が今実装しようとしているSimpleCursorTreeAdapter (SDK ApiDemos ExpandableList2 から変更) 。getChildrenCursor では、ルールテーブルから子データを取得するクエリを正確に作成する方法がわかりません。ExpandableList2.java の例からはわかりません。
import android.app.ExpandableListActivity;
import android.content.AsyncQueryHandler;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Contacts;
import android.widget.CursorTreeAdapter;
import android.widget.SimpleCursorTreeAdapter;
/**
* Demonstrates expandable lists backed by Cursors
*/
public class RuleBookTreeAdapter extends ExpandableListActivity {
private static final String[] CHAPTERS_PROJECTION = new String[] {
TDAdb.KEY_ROWID,
TDAdb.COL_CHAPTERTITLE
};
private static final int GROUP_ID_COLUMN_INDEX = 0;
private static final String[] RULES_PROJECTION = new String[] {
TDAdb.KEY_ROWID,
TDAdb.COL_RULETITLE
};
private static final int TOKEN_GROUP = 0;
private static final int TOKEN_CHILD = 1;
private static final class QueryHandler extends AsyncQueryHandler {
private CursorTreeAdapter mAdapter;
public QueryHandler(Context context, CursorTreeAdapter adapter) {
super(context.getContentResolver());
this.mAdapter = adapter;
}
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
switch (token) {
case TOKEN_GROUP:
mAdapter.setGroupCursor(cursor);
break;
case TOKEN_CHILD:
int groupPosition = (Integer) cookie;
mAdapter.setChildrenCursor(groupPosition, cursor);
break;
}
}
}
public class MyExpandableListAdapter extends SimpleCursorTreeAdapter {
// Note that the constructor does not take a Cursor. This is done to avoid querying the
// database on the main thread.
public MyExpandableListAdapter(Context context, int groupLayout,
int childLayout, String[] groupFrom, int[] groupTo, String[] childrenFrom,
int[] childrenTo) {
super(context, null, groupLayout, groupFrom, groupTo, childLayout, childrenFrom,
childrenTo);
}
@Override
protected Cursor getChildrenCursor(Cursor groupCursor) {
// Given the group, we return a cursor for all the children within that group
// Return a cursor that points to this chapters rules
Uri.Builder builder = TDAProvider.CONTENT_URI_RULES.buildUpon();
ContentUris.appendId(builder, groupCursor.getLong(GROUP_ID_COLUMN_INDEX));
// builder.appendEncodedPath(TDAProvider.CONTENT_DIRECTORY);
Uri rulesUri = builder.build();
mQueryHandler.startQuery(TOKEN_CHILD, groupCursor.getPosition(), rulesUri,
RULES_PROJECTION, TDAdb.COL_CHAPTER + "=?",
null, null);
// new String[] { TDAProvider.CONTENT_ITEM_TYPE }, null);
return null;
}
}
private QueryHandler mQueryHandler;
private CursorTreeAdapter mAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set up our adapter
mAdapter = new MyExpandableListAdapter(
this,
android.R.layout.simple_expandable_list_item_1,
android.R.layout.simple_expandable_list_item_1,
new String[] { TDAdb.COL_CHAPTERTITLE }, // Name for group layouts
new int[] { android.R.id.text1 },
new String[] { TDAdb.COL_RULETITLE }, // Number for child layouts
new int[] { android.R.id.text1 });
setListAdapter(mAdapter);
mQueryHandler = new QueryHandler(this, mAdapter);
// Query for chapters
mQueryHandler.startQuery(TOKEN_GROUP, null, TDAProvider.CONTENT_URI, CHAPTERS_PROJECTION,
null, null, null);
}
@Override
protected void onDestroy() {
super.onDestroy();
// Null out the group cursor. This will cause the group cursor and all of the child cursors
// to be closed.
mAdapter.changeCursor(null);
mAdapter = null;
}
}
わかりやすく完全にするために、データベース、データベース ヘルパー、コンテンツ プロバイダー、およびレイアウト xml ファイルを含めます。私は自分のプロジェクトの他のバリアントでこのソースを使用しましたが、問題なく動作しているようです。
TDAdb.javaソース コード。
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
public class TDAdb {
public static final String KEY_ROWID = "_id";
public static final String COL_CHAPTER = "chapter";
public static final String COL_CHAPTERTITLE = "chaptertitle";
// public static final String KEY_CONTINENT = "continent";
// Rule Table Columns
public static final String COL_RULE = "rule";
// public static final String COL_CHAPTER = "chapter";
public static final String COL_KEYDESCRIPTOR = "keydescriptor";
public static final String COL_RULETITLE = "ruletitle";
public static final String COL_DESCR = "descr";
public static final String COL_DESCRIPTION = "description"; //LongText
public static final String COL_LABEL = "label";
public static final String COL_USERLABEL = "userlabel";
public static final String COL_LABELID = "labelid"; //Integer
public static final String COL_USERLABELID = "userlabelid"; //Integer
public static final String COL_TDTIP = "tdtip";
public static final String COL_DEFUNCT = "defunct";
public static final String COL_USCFREVISION = "uscfrevision";
public static final String COL_HIGHLIGHT = "highlight"; //LongText
public static final String COL_PAGENO = "pageno";
public static final String COL_CHANGEDATE = "changedate"; //Integer
public static final String COL_REFINC = "refinc";
public static final String COL_RULEINC = "ruleinc";
private static final String LOG_TAG = "CountriesDb";
public static final String CHAPTER_TABLE = "chapters";
public static final String RULE_TABLE = "rules";
public static String SQLITE_TABLE = "chapters";
/* private static final String DATABASE_CREATE =
"CREATE TABLE if not exists " + CHAPTER_TABLE + " (" +
KEY_ROWID + " integer PRIMARY KEY autoincrement," +
COL_CHAPTER + "," +
COL_CHAPTERTITLE + "," +
// KEY_CONTINENT + "," +
" UNIQUE (" + COL_CHAPTER +"));"; */
public static void onCreate(SQLiteDatabase db) {
// Log.w(LOG_TAG, DATABASE_CREATE);
// db.execSQL(DATABASE_CREATE);
Log.i(LOG_TAG, "onCreate");
}
public static void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(LOG_TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
// db.execSQL("DROP TABLE IF EXISTS " + CHAPTER_TABLE);
onCreate(db);
}
}
TDAdbHelper.javaソース コード (完全を期すために含まれています)
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class TDAdbHelper extends SQLiteOpenHelper {
private static String DATABASE_PATH;
private static final String DATABASE_NAME = "tda.db";
private static final int DATABASE_VERSION = 1;
private Context context;
private SQLiteDatabase db;
TDAdbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.context = context;
String packageName = context.getPackageName();
DATABASE_PATH = String.format("//data//data//%s//databases//", packageName);
Log.i(this.getClass().toString(), "... before calling openDatabase ");
openDataBase();
Log.i(this.getClass().toString(), "... after return openDatabase ");
}
@Override
public void onCreate(SQLiteDatabase db) {
Log.i(this.getClass().toString(), "... Starting TDAdb.onCreate ");
TDAdb.onCreate(db);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
TDAdb.onUpgrade(db, oldVersion, newVersion);
}
//Performing a database existence check
private boolean checkDataBase() {
Log.i(this.getClass().toString(), "... Starting checkDatabase ");
SQLiteDatabase checkDb = null;
try {
String path = DATABASE_PATH + DATABASE_NAME;
checkDb = SQLiteDatabase.openDatabase(path, null,
SQLiteDatabase.OPEN_READONLY);
} catch (SQLException e) {
Log.e(this.getClass().toString(), "Error while checking db");
}
//Android doesn’t like resource leaks, everything should
// be closed
if (checkDb != null) {
checkDb.close();
}
return checkDb != null;
}
//Method for copying the database
private void copyDataBase() throws IOException {
//Open a stream for reading from our ready-made database
//The stream source is located in the assets
Log.i(this.getClass().toString(), "... in copyDataBase ");
InputStream externalDbStream = context.getAssets().open(DATABASE_NAME);
//Path to the created empty database on your Android device
String outFileName = DATABASE_PATH + DATABASE_NAME;
//Now create a stream for writing the database byte by byte
OutputStream localDbStream = new FileOutputStream(outFileName);
//Copying the database
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = externalDbStream.read(buffer)) > 0) {
localDbStream.write(buffer, 0, bytesRead);
}
//Don’t forget to close the streams
localDbStream.close();
externalDbStream.close();
}
//This piece of code will create a database if it’s not yet created
public void createDataBase() {
Log.i(this.getClass().toString(), "... in createDataBase ");
boolean dbExist = checkDataBase();
if (!dbExist) {
this.getReadableDatabase();
try {
copyDataBase();
} catch (IOException e) {
Log.e(this.getClass().toString(), "Copying error");
throw new Error("Error copying database!");
}
} else {
Log.i(this.getClass().toString(), "Database already exists");
}
}
public SQLiteDatabase openDataBase() throws SQLException {
String path = DATABASE_PATH + DATABASE_NAME;
Log.i(this.getClass().toString(), "Starting openDatabase " + path);
if (db == null) {
createDataBase();
db = SQLiteDatabase.openDatabase(path, null,
SQLiteDatabase.OPEN_READWRITE);
}
return db;
}
}
TDAProvider.javaソース コード (完全を期すために含まれています)
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
public class TDAProvider extends ContentProvider {
private TDAdbHelper dbHelper;
private static final String TAG = "TDAProvider";
private static final int ALL_CHAPTERS = 1;
private static final int SINGLE_CHAPTER = 2;
private static final int ALL_RULES = 3;
private static final int SINGLE_RULE = 4;
// authority is the symbolic name of your provider
// To avoid conflicts with other providers, you should use
// Internet domain ownership (in reverse) as the basis of your provider
// authority.
private static final String AUTHORITY = "com.birdsall.peter.contentprovider";
// create content URIs from the authority by appending path to database
// table
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
+ "/chapters");
public static final Uri CONTENT_URI_RULES = Uri.parse("content://" + AUTHORITY
+ "/rules");
// a content URI pattern matches content URIs using wildcard characters:
// *: Matches a string of any valid characters of any length.
// #: Matches a string of numeric characters of any length.
private static final UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, "chapters", ALL_CHAPTERS);
uriMatcher.addURI(AUTHORITY, "chapters/#", SINGLE_CHAPTER);
uriMatcher.addURI(AUTHORITY, "rules", ALL_RULES);
uriMatcher.addURI(AUTHORITY, "rules/#", SINGLE_RULE);
}
// system calls onCreate() when it starts up the provider.
@Override
public boolean onCreate() {
// get access to the database helper
Log.i(TAG, "onCreate ");
dbHelper = new TDAdbHelper(getContext());
return false;
}
// Return the MIME type corresponding to a content URI
@Override
public String getType(Uri uri) {
Log.i(TAG, "getType ");
switch (uriMatcher.match(uri)) {
case ALL_CHAPTERS:
return "vnd.android.cursor.dir/vnd.com.birdsall.peter.contentprovider.chapters";
case SINGLE_CHAPTER:
return "vnd.android.cursor.item/vnd.com.birdsall.peter.contentprovider.chapters";
case ALL_RULES:
return "vnd.android.cursor.dir/vnd.com.birdsall.peter.contentprovider.rules";
case SINGLE_RULE:
return "vnd.android.cursor.item/vnd.com.birdsall.peter.contentprovider.rules";
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
// The insert() method adds a new row to the appropriate table, using the
// values
// in the ContentValues argument. If a column name is not in the
// ContentValues argument,
// you may want to provide a default value for it either in your provider
// code or in
// your database schema.
@Override
public Uri insert(Uri uri, ContentValues values) {
Log.i(TAG, "insert ");
SQLiteDatabase db = dbHelper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case ALL_CHAPTERS:
// do nothing
break;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
long id = db.insert(TDAdb.CHAPTER_TABLE, null, values);
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(CONTENT_URI + "/" + id);
}
// The query() method must return a Cursor object, or if it fails,
// throw an Exception. If you are using an SQLite database as your data
// storage,
// you can simply return the Cursor returned by one of the query() methods
// of the
// SQLiteDatabase class. If the query does not match any rows, you should
// return a
// Cursor instance whose getCount() method returns 0. You should return null
// only
// if an internal error occurred during the query process.
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
String id;
Log.i(TAG, "query ");
SQLiteDatabase db = dbHelper.getWritableDatabase();
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
// queryBuilder.setTables(TDAdb.CHAPTER_TABLE);
switch (uriMatcher.match(uri)) {
case ALL_CHAPTERS:
// do nothing
queryBuilder.setTables(TDAdb.CHAPTER_TABLE);
break;
case SINGLE_CHAPTER:
queryBuilder.setTables(TDAdb.CHAPTER_TABLE);
id = uri.getPathSegments().get(1);
queryBuilder.appendWhere(TDAdb.KEY_ROWID + "=" + id);
break;
case ALL_RULES:
// do nothing
queryBuilder.setTables(TDAdb.RULE_TABLE);
break;
case SINGLE_RULE:
queryBuilder.setTables(TDAdb.RULE_TABLE);
id = uri.getPathSegments().get(1);
queryBuilder.appendWhere(TDAdb.KEY_ROWID + "=" + id);
break;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
Cursor cursor = queryBuilder.query(db, projection, selection,
selectionArgs, null, null, sortOrder);
Log.i(TAG, "query return cursor ");
return cursor;
}
// The delete() method deletes rows based on the seletion or if an id is
// provided then it deleted a single row. The methods returns the numbers
// of records delete from the database. If you choose not to delete the data
// physically then just update a flag here.
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
Log.i(TAG, "delete ");
SQLiteDatabase db = dbHelper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case ALL_CHAPTERS:
// do nothing
break;
case SINGLE_CHAPTER:
String id = uri.getPathSegments().get(1);
selection = TDAdb.KEY_ROWID
+ "="
+ id
+ (!TextUtils.isEmpty(selection) ? " AND (" + selection
+ ')' : "");
break;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
int deleteCount = db.delete(TDAdb.CHAPTER_TABLE, selection,
selectionArgs);
getContext().getContentResolver().notifyChange(uri, null);
return deleteCount;
}
// The update method() is same as delete() which updates multiple rows
// based on the selection or a single row if the row id is provided. The
// update method returns the number of updated rows.
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
Log.i(TAG, "update ");
SQLiteDatabase db = dbHelper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case ALL_CHAPTERS:
// do nothing
break;
case SINGLE_CHAPTER:
String id = uri.getPathSegments().get(1);
selection = TDAdb.KEY_ROWID
+ "="
+ id
+ (!TextUtils.isEmpty(selection) ? " AND (" + selection
+ ')' : "");
break;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
int updateCount = db.update(TDAdb.CHAPTER_TABLE, values, selection,
selectionArgs);
getContext().getContentResolver().notifyChange(uri, null);
Log.i(TAG, "update return updateCount ");
return updateCount;
}
}
私のactivity_expadnable.xmlファイル (完全を期すために含まれています)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:background="@drawable/background" >
<ExpandableListView
android:id="@+id/expandableListView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:padding="2dp">
</ExpandableListView>
</RelativeLayout>
リストアダプターを使用するようにメインアクティビティを編集するとき、ケンに感謝します
elv.setAdapter((ListAdapter) new RuleBookTreeAdapter());
logcat から次のエラーが表示されます。
06-07 17:12:31.139: E/AndroidRuntime(2226): FATAL EXCEPTION: main
06-07 17:12:31.139: E/AndroidRuntime(2226): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.birdsall.peter.expandable1/com.birdsall.peter.expandable1.ActivityRuleBook}: java.lang.ClassCastException: com.birdsall.peter.expandable1.RuleBookTreeAdapter cannot be cast to android.widget.ListAdapter
06-07 17:12:31.139: E/AndroidRuntime(2226): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1956)
06-07 17:12:31.139: E/AndroidRuntime(2226): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
06-07 17:12:31.139: E/AndroidRuntime(2226): at android.app.ActivityThread.access$600(ActivityThread.java:123)
06-07 17:12:31.139: E/AndroidRuntime(2226): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
06-07 17:12:31.139: E/AndroidRuntime(2226): at android.os.Handler.dispatchMessage(Handler.java:99)
06-07 17:12:31.139: E/AndroidRuntime(2226): at android.os.Looper.loop(Looper.java:137)
06-07 17:12:31.139: E/AndroidRuntime(2226): at android.app.ActivityThread.main(ActivityThread.java:4424)
06-07 17:12:31.139: E/AndroidRuntime(2226): at java.lang.reflect.Method.invokeNative(Native Method)
06-07 17:12:31.139: E/AndroidRuntime(2226): at java.lang.reflect.Method.invoke(Method.java:511)
06-07 17:12:31.139: E/AndroidRuntime(2226): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
06-07 17:12:31.139: E/AndroidRuntime(2226): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
06-07 17:12:31.139: E/AndroidRuntime(2226): at dalvik.system.NativeStart.main(Native Method)
06-07 17:12:31.139: E/AndroidRuntime(2226): Caused by: java.lang.ClassCastException: com.birdsall.peter.expandable1.RuleBookTreeAdapter cannot be cast to android.widget.ListAdapter
06-07 17:12:31.139: E/AndroidRuntime(2226): at com.birdsall.peter.expandable1.ActivityRuleBook.onCreate(ActivityRuleBook.java:19)
06-07 17:12:31.139: E/AndroidRuntime(2226): at android.app.Activity.performCreate(Activity.java:4465)
06-07 17:12:31.139: E/AndroidRuntime(2226): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
06-07 17:12:31.139: E/AndroidRuntime(2226): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920)
06-07
17:12:31.139: E/AndroidRuntime(2226): ... 11 もっと見る
また、RuleBookTreeAdapter でメソッドを実装すると、ほとんどのコードでエラーが発生します。これは、アダプターの種類が異なるためです。