2017-10-28 132 views
2

我想从SQLite数据库中填充ListView,但Log显示:[email protected]。 Gradle构建时没有任何错误或警告。ListView从SQLite显示出奇怪

任何想法有什么不对?我的数据库设置有id,title,author,collectionbody的字段。

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()); 

    } 

} 

DatabaseHelper.java

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; 

    } 
} 

Book.java

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; 
    } 

} 
+0

您需要自定义适配器来使用具有多个参数的对象填充listview。你的'ArrayAdapter'适用于像String这样的单个对象。所有你需要做的就是创建一个适配器项目(一个项目的布局资源),并在扩展ArrayAdapter的类中使用它。 [Here's](http://www.ezzylearning.com/tutorial/customizing-android-listview-items-with-custom-arrayadapter)一个例子,你应该怎么做。 – grabarz121

回答

0

getAllBooks中,不是创建一个String列表,而是创建并返回一个Book列表。因此,在MainActivity中,实际上是打印Book对象的字符串表示形式。为了解决这个问题,你需要将字符串放入getAllBooks的列表中。此外,请始终使用键入的列表(指定钻石中列表元素的类型,例如List<Book>List<String>),以便编译器捕获此类错误。

+0

谢谢你的回复。在getAllBooks中创建String列表而不是Book列表需要更改哪些内容? – Sebastian

+0

@Sebastian不需要将书籍添加到列表中,您需要将字符串添加到列表中。但从你的代码判断,你确实需要在这个列表中的书,对吧?如果是这样的话,那么一切都是正确的 - 你有书。它只是在调用toString时想要一些有意义的东西,你需要在Book.java中创建一个名为toString的方法,并在那里返回一个字符串 – Aenadon

+0

@Sebastian然而,我仍然建议你为所有List实例提供钻石类型你的代码,无论是Book还是String或者你放在那里的任何东西。 – Aenadon

0

简而言之,bookList.add(book);行将Book对象作为字符串分配给各个元素,而不是Book的成员/属性,因此@ ....这是对Book实例的引用。您可以使用bookList.add(book.addAuthor);。然而,问题在于使用列表,比方说通过点击来更新列出的书籍会变得有问题,因为所有ListViews知道的是正在显示的文本和列表中的位置。

简而言之,使用字符串数组作为适配器的来源使得返回数据库中保存的原始数据变得困难/有问题。您只有字符串或字符串本身的位置作为参考。该位置不能用于可靠地确定行的rowid,这可以说是访问单个表的最佳值。位置从0开始,rowid在1; rowid不能保证增加1,位置会减少,行可以被删除而留下空隙;数据可能不按照rowid排序。

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

所以,如果你是以下内容添加到您的图书类,它能够显示作者和书名: -

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,然后而非Integer.parseInt(cursor.getString(0)),你可以使用: -

Integer.parseInt(cursor.getString(csr.getColumnIndex("_id")) 

假设ID列的别名的rowid即它已被定义为column_name INTEGER PRIMARY KEYcolumn_name INTEGER PRIMARY KEY AUTOINCREMENT(其中column_name仅表示使用的实际列名称),那么该值可能会超过int可容纳的值,因此您应该真正使用long。您不需要使用Parse和getString来提取值,Cursor具有各种get方法,如getInt和getlong。

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

cursor.getLong(csr.getColumnIndex("column_name")); 

与改变Book类使用long 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); 

另一种方法是使用的CursorAdapter

你可以这样做: -

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_1, 
     csr, 
     new String[]{"title_column"}, 
     new int[]{android.R.id.text1}, 
     0 
    ); 
    authorsListView.setAdapater(sca); 

凡title_column将标题栏或authour列的名称。

您还可以使用: -

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 AS _id",假设您的id列未命名为_id。如果您的ID列名为_id那么query方法的第二个参数可能为空。CursorAdapter要求有一个名为_id的列。然后传递给onItemClickListener以及onItemLongClickListener