可扩展列表视图应用程序,我试图将我的适配器从BaseExpandableListAdapter (RuleBookAdapter.java) 更改为SimpleCursorTreeAdapter (RuleBookTreeAdapter.java) 以访问我的内容提供程序 (TDAProvider)。
我使用 android SDK ApiDemos ExpandableList2.java 作为模板来创建我的 (RuleBookTreeAdapter.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程序中找到调用程序无济于事,并搜索了互联网和stackoverflow(建议和类似问题),但找不到一个由游标支持的SimpleCursorTreeAdapter的好例子,除了ExpandableList2.java来自 SDK 示例。
问题 2)在 SimpleCursorTreeAdapter (RuleBookTreeAdapter.getChildrenCursor) 中,我不确定如何准确地设计查询以获取子数据。
这是我的数据库中的 2 个表的布局,以及相关的列。
表:章节 (这是应用程序中的父表) 列:_id、章节字符(2)、章节标题字符(70) URI:CONTENT_URI 章节
表:规则 (这是应用程序中的子表) 列:_id、规则 varchar(10)、章节 char(2)、规则标题 char(50) URI:CONTENT_URI_RULES 规则
注意:规则表中的章节字段是章节表的外键。这些表中的数据是静态的,因此不会发生更新,并且每个父级至少有一个或多个子级。
任何帮助或意见将不胜感激,提前感谢您的时间。祝你有美好的一天。
主要Activity源代码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 中实现该方法会导致大多数代码出错,因为它是一种不同类型的适配器。