Java SQLite中的ListView显示得很奇怪

Java SQLite中的ListView显示得很奇怪,java,android,sqlite,listview,android-sqlite,Java,Android,Sqlite,Listview,Android Sqlite,我试图从SQLite数据库填充ListView,但是日志显示:com.example.apple.bookshelf。Book@3d3844f2。Gradle构建时没有任何错误或警告 知道怎么了吗 我的数据库设置有名为id、title、author、collection和body的字段 MainActivity.java package com.example.apple.bookshelf; import android.database.Cursor; import android.dat

我试图从SQLite数据库填充ListView,但是
日志显示:
com.example.apple.bookshelf。Book@3d3844f2
。Gradle构建时没有任何错误或警告

知道怎么了吗

我的数据库设置有名为
id
title
author
collection
body
的字段

MainActivity.java

package com.example.apple.bookshelf;

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import com.readystatesoftware.sqliteasset.SQLiteAssetHelper;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private ListView authorsListView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        authorsListView = (ListView) findViewById(R.id.authors_list_view);
        String[] authors = {"Christie, Agatha","Conan Doyle, Arthur","James, M.R."};

        DatabaseHelper db = new DatabaseHelper(this);

        List bookList = db.getAllBooks();

        /*
        ArrayAdapter<String> arrayAdapter =
                new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, bookList);

        authorsListView.setAdapter(arrayAdapter);
        */

        Log.i("test", bookList.toString());

    }

}
package com.example.apple.bookshelf;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.readystatesoftware.sqliteasset.SQLiteAssetHelper;

import java.util.ArrayList;
import java.util.List;

public class DatabaseHelper extends SQLiteAssetHelper {

    private static final int DATABASE_VERSION = 1;

    private static final String DATABASE_NAME = "books.db";
    private static final String TABLE_NAME = "books";

    public DatabaseHelper (Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    // Getting All Contacts
    public List<String> getAllBooks() {

        List bookList = new ArrayList();

        // Select All Query
        String selectQuery = "SELECT * FROM " + TABLE_NAME;

        SQLiteDatabase db = this.getWritableDatabase();
        Cursor cursor = db.rawQuery(selectQuery, null);

        // looping through all rows and adding to list
        if (cursor.moveToFirst()) {
            do {
                Book book = new Book();
                book.setID(Integer.parseInt(cursor.getString(0)));
                book.setTitle(cursor.getString(1));
                book.setAuthor(cursor.getString(2));
                // Adding contact to list
                bookList.add(book);
            } while (cursor.moveToNext());
        }

        // return contact list
        return bookList;

    }
}
package com.example.apple.bookshelf;

public class Book {

    int id;
    String title;
    String author;
    String collection;
    String body;

    public Book() {

    }

    public Book(int id, String title, String author, String collection, String body) {
        this.id = id;
        this.title = title;
        this.author = author;
        this.collection = collection;
        this.body = body;
    }

    // getters

    public int getID() {
        return this.id;
    }

    public String getTitle() {
        return this.title;
    }

    public String getAuthor() {
        return this.author;
    }

    public String getCollection() {
        return this.collection;
    }

    public String getBody() {
        return this.body;
    }

    // setters

    public void setID(int id) {
        this.id = id;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public void setCollection(String collection) {
        this.collection = collection;
    }

    public void setBody(String body) {
        this.body = body;
    }

}

getAllBooks
中,您正在创建并返回一个图书列表,而不是创建一个字符串列表。因此,在
MainActivity
中,您实际上是在打印图书对象的字符串表示形式。要解决此问题,您需要实际将字符串放入
getAllBooks
中的列表中。此外,请始终使用类型化列表(在菱形中指定列表元素的类型,例如
列表
列表
),这样编译器就可以发现此类错误。

getAllBooks
中,而不是创建正在创建并返回的字符串列表。因此,在
MainActivity
中,您实际上是在打印图书对象的字符串表示形式。要解决此问题,您需要实际将字符串放入
getAllBooks
中的列表中。此外,请始终使用类型化列表(在菱形中指定列表元素的类型,例如
列表
列表
),这样编译器就会发现此类错误。

简而言之,行
bookList.add(book)将Book对象作为字符串分配给相应的元素,而不是Book的成员/属性,因此@。。。。这是对本书实例的引用

您可以使用
bookList.add(book.addAuthor)。但是,问题在于,使用列表(例如通过单击来更新列出的书籍)会出现问题,因为ListView只知道要显示的文本以及列表中的位置

简言之,使用字符串数组作为适配器的源会使返回数据库中保存的原始数据变得困难/有问题。只有字符串的位置或字符串本身作为引用。该位置不能用于可靠地确定行的rowid,因为rowid可能是访问表中单行的最佳值。位置的起点为0,rowid的起点为1;rowid不保证增量为1,位置将,行可以删除,留下间隙;数据不能根据rowid排序

实际上,您可以将书籍列表传递给适配器。不过有一个小问题,
ArrayAdapter
使用对象的
toString
方法从相应的数组元素检索文本。为对象提供
toString
方法可以控制显示内容。但是,例如,在onClickListener中,位置与图书列表中的图书相关,您可以从中访问其他信息,例如id

因此,如果要将以下内容添加到Book类中,它将能够显示作者和标题:-

public String toString() {
   return this.author + ", " + this.title;
}
您还需要更改
getAllBooks
方法以返回书籍数组:-

public Book[] getAllBooks() {

    SQLiteDatabase db = this.getWriteableDatabse();
    Cursor csr = db.query(TABLE_NAME,null,null,null,null,null,null);
    Book[] books = new Book[csr.getCount()];
    while (csr.moveToNext) {
        books[csr.getPosition] = new Book(
                Integer.parseInt(cursor.getString(0)),
                cursor.getString(1),
                cursor.getString(2),
                "","");
    }
    csr.close;
    return books;
} 
*注意:我建议不要使用硬编码偏移量,而是使用游标的
getColumnIndex
方法,例如,假设第一列(id)的列名是\u id,而不是
Integer.parseInt(Cursor.getString(0))
,您可以使用:-

Integer.parseInt(cursor.getString(csr.getColumnIndex("_id"))
假设ID列是行ID的别名,即它已被定义为
列名称整数主键
列名称整数主键自动递增
(其中列名称仅表示实际使用的列名)然后该值可能超过int所能容纳的值,因此您应该真正使用long。您不需要使用Parse和getString来提取值,Cursor有各种get方法,比如getInt和getlong

因此,理想情况下,您应该使用:-

cursor.getLong(csr.getColumnIndex("column_name"));
将Book类更改为使用
长id

您还需要更改适配器代码:-

    DatabaseHelper db = new DatabaseHelper(this);
    Book[] booklist = getAllBooks();

    ArrayAdapter<Book[]> arrayAdapter =
            new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, bookList);

    authorsListView.setAdapter(arrayAdapter);
其中title_column将是title列或author列的名称

您还可以使用:-

    Cursor csr = db.query(DatabaseHelper.TABLE_NAME,"*,rowid AS _id",null,null,null,null,null);
    SimpleCursorAdpater sca = new SimpleCursorAdapter(this,
        android.R.layout.simple_expandable_list_item_2,
        csr,
        new String[]{"title_column","author_column"},
        new int[]{android.R.id.text1,android.R.id.text2},
        0
    );
    authorsListView.setAdapater(sca);
标题和作者都会出现在列表中。再次使用实际列名,而不是虚构的列名

注:上述内容未经测试,因此可能存在奇怪的错误或打字错误

我个人会添加一个特定的方法来提取DatabaseHelper类中的所有行,例如getAllBooks,它可以是:-

public Cursor getAllBooks() {
    return this.getWriteableDatabase().query(TABLE_NAME,"*,rowid AS _id",null,null,null,null,null);
}

注意
“*,rowid作为_id”
,假设您的id列未命名为\u id。如果您的id列名为\u id,则
query
方法的第二个参数可能为null。游标适配器需要有一个名为\u id的列。然后将其传递给
onItemClickListener
,以及
onItemLongClickListener

简而言之,行
bookList.add(book)将Book对象作为字符串分配给相应的元素,而不是Book的成员/属性,因此@。。。。这是对本书实例的引用

您可以使用
bookList.add(book.addAuthor)。但是,问题在于,使用列表(例如通过单击来更新列出的书籍)会出现问题,因为ListView只知道要显示的文本以及列表中的位置

简言之,使用字符串数组作为适配器的源会使返回数据库中保存的原始数据变得困难/有问题。只有字符串的位置或字符串本身作为引用。该位置不能用于可靠地确定行的rowid,该rowid可以说是访问行的最佳值
public Cursor getAllBooks() {
    return this.getWriteableDatabase().query(TABLE_NAME,"*,rowid AS _id",null,null,null,null,null);
}