1

可扩展列表视图应用程序,我试图将我的适配器从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 中实现该方法会导致大多数代码出错,因为它是一种不同类型的适配器。

4

1 回答 1

0

Ken 对列表适配器的看法是正确的,这是我为 Activity 调整的代码,进行了大量研究。`package com.birdsall.tda;

import android.app.ExpandableListActivity;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.SimpleCursorTreeAdapter;
import android.widget.SimpleCursorTreeAdapter.ViewBinder;
import android.widget.TableRow;
import android.widget.TextView;

public class ActivityChapters extends ExpandableListActivity {

    private Context context;


    private Cursor mChapterCursor = null;
    private ExpandableListAdapter mExpandableListAdapter;
    private static final String TAG = "ActivityChapters";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 65, getResources().getDisplayMetrics());
        ContentResolver cr = this.getContentResolver();
        mChapterCursor = cr.query(TDAProvider.CONTENT_URI,
                TDAdb.PROJECTION_CHAPTER, null, null, TDAdb.COL_CHAPTER);

        setTitle("USCF Rule Book");
        Log.i(this.getClass().toString(), "... setTitle ");

        startManagingCursor(mChapterCursor);

        mExpandableListAdapter = new ChapterExpandableListAdapter(this,
                mChapterCursor, android.R.layout.simple_expandable_list_item_1,
                android.R.layout.simple_expandable_list_item_1,
                new String[] { TDAdb.COL_CHAPTERTITLE },
                new int[] { android.R.id.text1 },
                android.R.layout.simple_expandable_list_item_2,
                new String[] { TDAdb.COL_RULETITLE },
                new int[] { android.R.id.text1 });

        Log.i(this.getClass().toString(), "... after mExpandableListAdapter");
        setListAdapter(mExpandableListAdapter);

        int groupCount = mExpandableListAdapter.getGroupCount();
        ExpandableListView listView = getExpandableListView();


        ((SimpleCursorTreeAdapter) mExpandableListAdapter)
                .setViewBinder(new ViewBinder() {

                    public boolean setViewValue(View view, Cursor cursor,
                            int columnIndex) {
                        // parent
                        if (columnIndex == cursor
                                .getColumnIndex(TDAdb.COL_CHAPTERTITLE)) {
                            TextView v = (TextView) view;
                            v.setText((cursor.getString(cursor
                                    .getColumnIndex(TDAdb.COL_CHAPTER)))
                                    + " - "
                                    + (cursor.getString(cursor
                                            .getColumnIndex(TDAdb.COL_CHAPTERTITLE)))
                                    + " "       
                                    + (cursor.getString(cursor
                                            .getColumnIndex(TDAdb.COL_KEYDESC)))
                                    );
//                          v.setPadding(60, 10, 10, 10);
                            v.setTextColor(getResources().getColor(R.color.solid_red));
                            v.setTextSize(16);
//                          v.setMaxHeight(50);
//                          v.setHeight(50);
                            v.setMinimumHeight(50);
                            return true;
                        } else {
                            // child
                            if (columnIndex == cursor
                                    .getColumnIndex(TDAdb.COL_RULETITLE)) {
                                TextView v = (TextView) view;
                                String currentKeyDescriptor = (cursor.getString(cursor.getColumnIndex(TDAdb.COL_KEYDESCRIPTOR)));
                                String textKeyDescriptor = "";
                                if ((String)currentKeyDescriptor == "1") {
                                    textKeyDescriptor = "Club";
                                } else if ((String)currentKeyDescriptor == "2") {
                                    textKeyDescriptor = "USCF";
                                } else if ((String)currentKeyDescriptor == "3") {
                                    textKeyDescriptor = "TD Tip";
                                } else {
                                    textKeyDescriptor = "???";
                                }

                                Log.i(this.getClass().toString(), "... KeyDescriptor " + currentKeyDescriptor); 
                                v.setText("   "
                                        + (cursor.getString(cursor
                                                .getColumnIndex(TDAdb.COL_RULE)))
                                        + " - "
                                        + (cursor.getString(cursor
                                                .getColumnIndex(TDAdb.COL_RULETITLE)))
                                        + " (" 
                                        + (cursor.getString(cursor
                                                .getColumnIndex(TDAdb.COL_KEYDESCRIPTOR)))  
                                        + ")" + textKeyDescriptor       
                                        );
                                v.setTextColor(getResources().getColor(R.color.solid_blue));


                                return true;
                            }
                        }
                        return false;
                    }
                });

        Log.i(this.getClass().toString(), "... after ExpandableListView");
        setListAdapter(mExpandableListAdapter);
        Log.i(this.getClass().toString(), "... after setListAdapter");


    }

    @Override
    public boolean onChildClick(ExpandableListView parent, View v,
            int groupPosition, int childPosition, long id) {
        // Intent intent = new Intent(this, ExecuteCheckListActivity.class);
        // intent.putExtra("checklist_id", id);
        // startActivity(intent);

        return true;
    }

    public class ChapterExpandableListAdapter extends SimpleCursorTreeAdapter {
        private Cursor dataAdapter;

        public ChapterExpandableListAdapter(Context context, Cursor cursor,
                int collapsedGroupLayout, int expandedGroupLayout,
                String[] groupFrom, int[] groupTo, int childLayout,
                String[] childFrom, int[] childTo) {

            super(context, cursor, collapsedGroupLayout, expandedGroupLayout,
                    groupFrom, groupTo, childLayout, childFrom, childTo);
            Log.i(this.getClass().toString(),
                    "... after super ChapterExpandableListAdapter");
        }

        @Override
        protected Cursor getChildrenCursor(Cursor groupCursor) {

            Log.i(this.getClass().toString(),
                    "... in getChildernCursor before RULES query");
            String[] selectionArgs = new String[] { (String) (groupCursor
                    .getString(groupCursor.getColumnIndex(TDAdb.COL_CHAPTER))) };
            ContentResolver cr = getContentResolver();
            dataAdapter = cr.query(TDAProvider.CONTENT_URI_RULES_DESCRIBED, TDAdb.PROJECTION_RULESDESCRIBED, TDAdb.COL_CHAPTER + " = ? ", selectionArgs, TDAdb.COL_RULE);
            Log.i(this.getClass().toString(),
                    "... in getChildernCursor after RULES query");
            startManagingCursor(dataAdapter);
            Log.i(this.getClass().toString(),
                    "... in getChildernCursor after Managing Cursor");

            return dataAdapter;
        }

    }

    public View getChildView(int groupPosition, int childPosition,
            boolean isLastChild, View convertView, ViewGroup parent) {
        TextView tv = new TextView(context);
        // tv = (TextView) convertView.findViewById(android.R.id.text1);
        tv.setPadding(60, 10, 10, 10);

        return convertView;
    }

}
`
于 2013-06-15T04:00:17.747 回答