Android Fragment中SQLite查询与SimpleCursorAdapter使用问题
嘿,我来帮你搞定这两个问题,顺便给你揪出代码里几个容易踩坑的小细节:
解决你的Android SQLite与Fragment展示问题
问题1:Fragment中实例化BookDAO的Context错误
先看你Books Fragment的代码,有两个明显的问题:
- 代码执行顺序错了:你在
return v;之后才写实例化BookDAO的代码,这行代码永远不会被执行到!必须把业务逻辑代码放在return之前。 - Context传递错误:BookDAO的构造函数需要的是
Context对象,Fragment本身不是Context,不能直接传this。在Fragment里获取安全的Context可以用requireContext()(推荐,避免空指针),或者getActivity()(要确保Activity已绑定)。
修正后的Books Fragment onCreateView代码:
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate布局 View v = inflater.inflate(R.layout.fragment_books, container, false); // 正确实例化BookDAO并操作数据库 BookDAO livreBdd = new BookDAO(requireContext()); livreBdd.open(); // 别忘了打开数据库连接! List<Book> bookList = livreBdd.getAllBooks(); livreBdd.close(); // 用完记得关闭连接,避免资源泄漏 // 后续数据展示的代码放在这里 return v; }
问题2:用SimpleCursorAdapter展示数据
首先要明确:SimpleCursorAdapter是用来绑定Cursor类型数据到UI的,但你的getAllBooks()返回的是List<Book>,这里给你两种可行方案:
方案一:修改DAO返回Cursor(适配SimpleCursorAdapter)
把BookDAO的getAllBooks()改成返回Cursor(注意不要在DAO里关闭Cursor,交给Adapter管理):
public Cursor getAllBooksCursor() { // 注意:SimpleCursorAdapter要求Cursor必须包含名为_id的列,所以把id别名成_id String selectQuery = "SELECT id AS _id, isbn, title, resume FROM " + TABLE_NAME; return mdb.rawQuery(selectQuery, null); }
然后需要调整你的布局:当前的fragment_books是三个TextView,只能展示单条数据,要展示所有条目得用ListView或RecyclerView。
先修改fragment_books.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context="com.nabtech.android.nabilaffoauthor.MainActivity" tools:showIn="@layout/app_bar_main"> <ListView android:id="@+id/book_list" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
再创建列表项布局item_book.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="8dp"> <TextView android:id="@+id/item_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="18sp" android:textStyle="bold"/> <TextView android:id="@+id/item_isbn" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="14sp" android:textColor="@android:color/darker_gray"/> <TextView android:id="@+id/item_resume" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="14sp" android:layout_marginTop="4dp"/> </LinearLayout>
最后在Fragment中初始化SimpleCursorAdapter:
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_books, container, false); ListView listView = v.findViewById(R.id.book_list); BookDAO livreBdd = new BookDAO(requireContext()); livreBdd.open(); Cursor cursor = livreBdd.getAllBooksCursor(); // 定义Cursor列名和布局View的对应关系 String[] fromColumns = {BookDAO.TITLE, BookDAO.ISBN, BookDAO.RESUME}; int[] toViews = {R.id.item_title, R.id.item_isbn, R.id.item_resume}; // 初始化Adapter SimpleCursorAdapter adapter = new SimpleCursorAdapter( requireContext(), R.layout.item_book, cursor, fromColumns, toViews, 0 ); listView.setAdapter(adapter); livreBdd.close(); return v; }
方案二:用ArrayAdapter展示List(更简单)
如果你不想改DAO的返回类型,直接用ArrayAdapter绑定List数据更省心。先创建自定义Adapter:
public class BookAdapter extends ArrayAdapter<Book> { public BookAdapter(Context context, List<Book> books) { super(context, 0, books); } @NonNull @Override public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { // 复用布局 if (convertView == null) { convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_book, parent, false); } Book book = getItem(position); if (book != null) { TextView titleTv = convertView.findViewById(R.id.item_title); TextView isbnTv = convertView.findViewById(R.id.item_isbn); TextView resumeTv = convertView.findViewById(R.id.item_resume); titleTv.setText(book.getTitle()); isbnTv.setText(String.valueOf(book.getIsbn())); resumeTv.setText(book.getResume()); } return convertView; } }
然后在Fragment中使用:
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_books, container, false); ListView listView = v.findViewById(R.id.book_list); BookDAO livreBdd = new BookDAO(requireContext()); livreBdd.open(); List<Book> bookList = livreBdd.getAllBooks(); livreBdd.close(); BookAdapter adapter = new BookAdapter(requireContext(), bookList); listView.setAdapter(adapter); return v; }
额外的代码错误修正
我还发现你代码里几个小错误,不改会导致数据库操作失败:
- BookDAO中的
TABLE_DROP拼写错误:" DROP TABLE IF RXISTS"应该是"DROP TABLE IF EXISTS "(注意空格和正确拼写) - BookDAO中的
TABLE_CREATE里,RESUME后面少了空格:"+ RESUME + "TEXT );"应该是"+ RESUME + " TEXT );" - DatabaseHandler中的
BOOK_TABLE_DROP少了空格:"DROP TABLE IF EXISTS" + BOOK_TABLE_NAME + ";"应该是"DROP TABLE IF EXISTS " + BOOK_TABLE_NAME + ";"
这些小错误会导致SQL语句语法错误,创建/删除表失败,记得修正!
内容的提问来源于stack exchange,提问作者nabilnoble01
相关产品推荐
相关产品推荐

