从Android中的光标填充ListView

时间:2011-04-13 15:55:17

标签: android listview

我花了很多时间搜索和阅读类似的帖子,但似乎没有一个真正反映我的问题,因此我没有找到任何适合我的东西。 我有一个数据库,我在其上执行查询,其结果存储在游标中。这有两件事: - 每次按下某个按钮时执行查询(因此查询位于该Button的OnClickListener内) - 查询返回带有String值的两个不同列,必须单独处理(一列存储必须在ListView中显示的名称,另一列存储与行关联的图像的路径) 我的问题是,我尝试创建一个String [],我需要将其传递给ListView的ArrayAdapter创建者,但尝试为其指定大小为Cursor的getCount()会导致我的活动崩溃。我希望代码更多的是解释:

OnClickListener searchListener = new OnClickListener() {
    public void onClick(View v) {
    CardDatabaseOpenHelper helper = new 
    CardDatabaseOpenHelper(DeckEditorScreen1.this);
    SQLiteDatabase db = helper.getReadableDatabase();

    String columns[] = {"name","number","path"};

    Cursor c = db.query("cards", columns, null, null, null, null, "number");
    int count = c.getCount();
    String[] resultNameStrings;
    if (count != 0) resultNameStrings = new String[count];
        else {resultNameStrings = new String[1]; resultNameStrings[1] = "No results";} 
        // This is the offending code
    //Note that if I assign fixed values to resutNameStrings, the code works just
        //fine
        for (int i = 0; i < count; ++i) {
        c.moveToNext();
        int col = c.getColumnIndex("name");
        String s = c.getString(col);
            //Ideally here I would to something like:
            //resultNameStrings[i] = s;
        col = c.getColumnIndex("number");
        int conv = c.getInt(col);
        col = c.getColumnIndex("path");
        String s2 = c.getString(col);
    }
    db.close();

    ArrayAdapter<?> searchResultItemAdapter = new ArrayAdapter<String>
                                                  (DBScreen.this,
                                                  R.layout.search_result_item,
                                                  resultNameStrings);
    ListView searchResultList = (ListView)
                              DBScreen.this.findViewById(R.id.search_result_list);
    searchResultList.setAdapter(searchResultItemAdapter);
    }
};
Button search_button = (Button) findViewById(R.id.search_button);
search_button.setOnClickListener(searchListener);

2 个答案:

答案 0 :(得分:1)

已编辑 两次:)

在“Android Way”中执行...

首先使用CursorAdapter(fx:具有覆盖的SimpleCursorAdapter

public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
            Cursor cursor = managedQuery(MobileTraderProvider.CONTENT_URI,
                    null, null, new String[] { constraint.toString() }, null);
            return cursor;
        }

然后

customAdapter.getFilter().filter(filterText) 
// it will call runQueryOnBackgroundThread

第二次使用ContentProvider(它将为您管理curosors ......如果数据发生变化,它甚至会重新查询)

编辑:

首先真正使用我的建议

之前的第二个

for (int i = 0; i < count; ++i) {
        c.moveToNext();
//...

添加c.moveToFirst();

thrid:使用

if(c.moveToNext()) 
{ 
  int col = c.getColumnIndex("name"); 
//..... rest goes here
}

第二次编辑:

MyProvider.java

public class MyProvider extends ContentProvider {

    static final String LTAG = "MyAppName";

    public static final Uri CONTENT_URI = Uri.parse("content://my.app.Content");


    static final int CARDS = 1;
    static final int CARD = 2;
    public static final String CARDS_MIME_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/Cards";
    public static final String CARD_MIME_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/Cards";
    static final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
    static final HashMap<String, String> map = new HashMap<String, String>();

    static {
        //static "Constructor"
        matcher.addURI(Constants.AUTHORITY, "Cards", LISTS);
        matcher.addURI(Constants.AUTHORITY, "Cards/*", LIST);
        map.put(BaseColumns._ID, "ROWID AS _id");
        map.put(Tables.Cards.C_NAME, Tables.Cards.C_NAME);
        map.put(Tables.Cards.C_NUMBER, Tables.Cards.C_NUMBER);
        map.put(Tables.Cards.C_PATH, Tables.Cards.C_PATH);
    }

    private CardDatabaseOpenHelper mDB;

    @Override
    public boolean onCreate() {
        try {
            mDB = new CardDatabaseOpenHelper(getContext());
        } catch (Exception e) {
            Log.e(LTAG, e.getLocalizedMessage());
        }
        return true;
    }

    public int delete(Uri uri, String selection, String[] selectionArgs) {
        String table = null;
        switch (matcher.match(uri)) {
            case CARD:
                //overriding selection and selectionArgs
                selection = "ROWID=?";
                selectionArgs = new String[] { uri.getPathSegments().get(1) };
                table = uri.getPathSegments().get(0);
                break;
            case CARDS: 
                //this version will delete all rows if you dont provide selection and selectionargs
                table = uri.getPathSegments().get(0);
                break;
            default:
                throw new IllegalArgumentException("Unknown URL " + uri);
        }
        int ret = mDB.getWritableDatabase().delete(table, selection, selectionArgs);
        getContext().getContentResolver().notifyChange(Uri.withAppendedPath(CONTENT_URI, table), null);
        return ret;     
    }

    @Override
    public String getType(Uri uri) {
        switch (matcher.match(uri)) {
            case CARDS:
                return CARDS_MIME_TYPE;
            case CARD:
                return CARD_MIME_TYPE;
            default:
                throw new IllegalArgumentException("Unknown URL " + uri);
        }
    }

    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        String table, rowid;
        switch (matcher.match(uri)) {
            case CARD:
                //overriding selection and selectionArgs
                selection = "ROWID=?";
                selectionArgs = new String[] { uri.getPathSegments().get(1) };
                table = uri.getPathSegments().get(0);
                break;
            case CARDS: 
                //this version will update all rows if you dont provide selection and selectionargs
                table = uri.getPathSegments().get(0);
                break;
            default:
                throw new IllegalArgumentException("Unknown URL " + uri);
        }
        int ret = mDB.getWritableDatabase().update(table, values, selection, selectionArgs);
        getContext().getContentResolver().notifyChange(Uri.withAppendedPath(CONTENT_URI, table), null);
        return ret;
    }

    public Uri insert(Uri uri, ContentValues values) {
        String table = null;
        switch (matcher.match(uri)) {
            case CARDS:
                table = uri.getPathSegments().get(0);
                break;
            default:
                throw new IllegalArgumentException("Unknown URL " + uri);
        }
        mDB.getWritableDatabase().insert(table, null, values);
        getContext().getContentResolver().notifyChange(Uri.withAppendedPath(CONTENT_URI, table), null);
        return null;
    }

    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
        switch (matcher.match(uri)) {
            case CARDS:
                builder.setTables(uri.getPathSegments().get(0));
                break;
            case CARD:
                builder.setTables(uri.getPathSegments().get(0));
                selection = "ROWID=?";
                selectionArgs = new String[] { uri.getPathSegments().get(1) };  
            default:
                throw new IllegalArgumentException("Unknown URL " + uri);
        }
        builder.setProjectionMap(map);
        Cursor cursor = builder.query(mDB.getReadableDatabase(), projection, selection, selectionArgs, null, null, sortOrder);
        if (cursor == null) {
            return null;
        }
        cursor.setNotificationUri(getContext().getContentResolver(), uri);
        return cursor;      
    }       
}

CardCursorAdapter.java

class CardCursorAdapter extends SimpleCursorAdapter {

    public MyCursorAdapter(Context context, int layout, Cursor c,
            String[] from, int[] to) {
        super(context, layout, c, from, to);
    }

@Override
public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
    //search in cards.name
    String selection = Tables.Cards.C_NAME + " LIKE ?";
    String[] selectionArgs = new String[] {"%" + constraint.toString() + "%"};
    Cursor cursor = managedQuery(Uri.withAppendedPath(MyProvider.CONTENT_URI, Tables.Cards.Name), 
        getCursor().getColumnNames(), selection, selectionArgs, null);
    return cursor;
}
}

Tables.java

public static class Tables {
    //table definition
    public static interface Cards {
        public static final String NAME = "cards";
        public static final String C_NAME = "name";
        public static final String C_NUMBER = "number";
        public static final String C_PATH = "path";
    }
    //other tables go here
}

的AndroidManifest.xml

</manifest> 
        </application>
            <!-- ....... other stuff    ....... -->
            <provider android:name="MyProvider" android:authorities="my.app.Content" />
        </application>
</manifest>

然后在活动中

onCreate(...){

    listView.setAdapter(new CardCursorAdapter(this, R.layout.listrow, 
        managedQuery(Uri.withAppendedPath(MyProvider.CONTENT_URI, Tables.Cards.NAME),
            new String[] { BaseColumns._ID, Tables.Cards.C_NAME, Tables.Cards.C_NUMBER, Tables.Cards.C_PATH },
            null,null, number), 
        new String[] { Tables.Cards.C_NAME, Tables.Cards.C_NUMBER, Tables.Cards.C_PATH  }, 
        new int[] { R.id.tName, R.id.tNumber, R.id.tPath }));
}


OnClickListener searchListener = new OnClickListener() {
    public void onClick(View v) {
        DeckEditorScreen1.this.listView.getAdapter().getFilter().filter("text for search in name column of card table set me to empty for all rows");
    }
}

答案 1 :(得分:0)

好的,我做了一些测试,我想我知道是什么问题。 Java允许构造如:

String[] whatever; 
if (something) whatever = new String[avalue];
else whatever = new String[anothervalue];

如果您没有为[i]的每个字段分配具体值,则会发生崩溃。剩下的代码现在很好,虽然我添加了Selvin的修正

if (c.moveToNext) ...

c.moveToFirst()在我的情况下未正确使用,因为for迭代计数次数。如果先执行moveToFirst,则总是缺少光标指向的第一个元素。