如何在片段类的列表视图中显示 SQLite 数据库?
Posted
技术标签:
【中文标题】如何在片段类的列表视图中显示 SQLite 数据库?【英文标题】:How to display a SQLite database in a listview of a fragment class? 【发布时间】:2018-11-21 02:58:58 【问题描述】:我是 android Studio 的新手。我有一个包含三列的 SQLite 数据库,我会将所有数据显示到列表视图中。该数据库位于资产文件夹中。我尝试在片段类中使用 SimpleCursorAdapter 但没有成功。当我在我的设备上启动它时应用程序崩溃。谁能告诉我为什么?
这是我的片段类:
public class rightFragment extends Fragment
View view;
Cursor c;
SimpleCursorAdapter adapter;
ListView listView;
Button buttondisplay;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
view = inflater.inflate (R.layout.fragment_right, container, false);
DatabaseHelper myDbHelper = new DatabaseHelper (getActivity ());
try
myDbHelper.createDataBase ();
catch (IOException ioe)
try
myDbHelper.openDataBase ();
catch (SQLException sqle)
throw sqle;
c = myDbHelper.query ("fradeu", null, null, null, null, null, null);
Cursor c = myDbHelper.readData ();
String[] from = new String []DatabaseHelper.COL1,DatabaseHelper.COL2;
int[] to = new int[] R.id.fra, R.id.deu;
adapter = new SimpleCursorAdapter (getActivity (), R.layout.list_view_adapter, c, from, to)
;
buttondisplay.setOnClickListener (new View.OnClickListener ()
@Override
public void onClick(View v)
adapter.notifyDataSetChanged();
listView.setAdapter(adapter);
);
return view
数据库助手:
public class DatabaseHelper extends SQLiteOpenHelper
String DB_PATH = null;
private static String DB_NAME = "mydatabase3.db";
private SQLiteDatabase database;
private final Context myContext;
public static final String TABLE_NAME = "fradeu";
public static final String COL1 = "fra";
public static final String COL2 = "deu";
public DatabaseHelper(Context context)
super (context, DB_NAME, null, 10);
this.myContext = context;
this.DB_PATH = "/data/data/" + context.getPackageName () + "/" + "databases/";
Log.e ("Path 1", DB_PATH);
public void createDataBase() throws IOException
boolean dbExist = checkDataBase ();
if (dbExist)
else
this.getReadableDatabase ();
try
copyDataBase ();
catch (IOException e)
throw new Error ("Error copying database");
private boolean checkDataBase()
SQLiteDatabase checkDB = null;
try
String myPath = DB_PATH + DB_NAME;
checkDB = SQLiteDatabase.openDatabase (myPath, null, SQLiteDatabase.OPEN_READONLY);
catch (SQLiteException e)
if (checkDB != null)
checkDB.close ();
return checkDB != null ? true : false;
private void copyDataBase() throws IOException
InputStream myInput = myContext.getAssets ().open (DB_NAME);
String outFileName = DB_PATH + DB_NAME;
OutputStream myOutput = new FileOutputStream (outFileName);
byte[] buffer = new byte[10];
int length;
while ((length = myInput.read (buffer)) > 0)
myOutput.write (buffer, 0, length);
myOutput.flush ();
myOutput.close ();
myInput.close ();
public void openDataBase() throws SQLException
String myPath = DB_PATH + DB_NAME;
database = SQLiteDatabase.openDatabase (myPath, null, SQLiteDatabase.OPEN_READONLY);
public Cursor readData()
String[] allColumns = new String[] DatabaseHelper.COL1,DatabaseHelper.COL2;
Cursor c =database.query (DatabaseHelper.TABLE_NAME,allColumns,null,null,null,null,null);
if(c != null)
c.moveToFirst ();
return c;
@Override
public synchronized void close()
if (database != null)
database.close ();
super.close ();
@Override
public void onCreate(SQLiteDatabase db)
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
if (newVersion > oldVersion)
try
copyDataBase ();
catch (IOException e)
e.printStackTrace ();
public Cursor query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy)
return database.query ("fradeu", null, null, null, null, null,null);
用于 SimpleCursorAdapter 的 xml 文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:orientation="horizontal" >
<TextView
android:id="@+id/fra"
android:layout_
android:layout_
android:text="fra"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/deu"
android:layout_
android:layout_
android:layout_marginLeft="10dp"
android:text="deu"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
【问题讨论】:
【参考方案1】:有很多潜在的问题,这里有一个检查清单:-
-
文件 mydatabase2.db 是否存在于 ????/App/Main/assets 文件夹中?
它是否是有效的 SQLite 数据库(在 SQlite 工具中打开并检查)。
表 fradeu 应该有一个名为 _id 的列,它应该是 rowid 的别名(例如,它被定义为
_id INTEGER PRIMARY KEY
或 _id INTEGER PRIMARY AUTOINCREMENT
,由于不必要的开销,不推荐后者)
注意请参阅设置 allColumns 的代码(以及如何避免没有 _id 列)。
修复
为了克服问题,对代码进行了相当广泛的更改,包括捕获潜在问题的代码,因此它有点臃肿,而不是传播需要在较高级别的 try/catch 子句的异常,它们在较低级别进行测试和捕获(为了我的方便)。
以下来自工作代码(如下),它使用以下内容作为 mydatabase3.db :-
已复制到资产文件夹。
生成的应用最初看起来像:-
然后:-
代码
请参阅 cmets 以获取修复建议和更改原因DatabaseHelper.java :-
public class DatabaseHelper extends SQLiteOpenHelper
private String DB_PATH = null;
private static String DB_NAME = "mydatabase3.db";
private SQLiteDatabase database;
private final Context myContext;
public static final String TABLE_NAME = "fradeu";
public static final String COL1 = "fra";
public static final String COL2 = "deu";
public DatabaseHelper(Context context)
super (context, DB_NAME, null, 10);
this.myContext = context;
this.DB_PATH = "/data/data/" + context.getPackageName () + "/" + "databases/";
String altdbpath = (context.getDatabasePath("anything")).getParent() + "/"; //<<<< gets path without hardcoding recommended
//<<<< Added for info re paths
Log.d("DBPATHINFO","Hardcoded DB path is >>>>" + DB_PATH + "<<<<");
Log.d("DBPATHINFO","Derived DB path is >>>>" + altdbpath + "<<<<");
Log.e ("Path 1", DB_PATH);
public void createDataBase()
boolean dbExist = checkDataBase ();
if (!dbExist)
this.getReadableDatabase ();
copyDataBase();
// Note can check file which won't issue stacktrace which may be confusing
private boolean checkDataBase()
SQLiteDatabase checkDB = null;
try
String myPath = DB_PATH + DB_NAME;
checkDB = SQLiteDatabase.openDatabase (myPath, null, SQLiteDatabase.OPEN_READONLY);
catch (SQLiteException e)
if (checkDB != null)
checkDB.close ();
return checkDB != null;
private void copyDataBase()
InputStream myInput;
OutputStream myOutput;
final String TAG = "COPYDATABASE";
Log.d(TAG,"Attempt to copy database initiated.");
Log.d(TAG,"Attempting to open Asset " + DB_NAME);
try
myInput = myContext.getAssets().open(DB_NAME);
catch (IOException e)
Log.d(TAG,"Error attempting to open Asset " +DB_NAME);
throw new RuntimeException(e);
//InputStream myInput = myContext.getAssets ().open (DB_NAME);
String outFileName = DB_PATH + DB_NAME;
Log.d(TAG,"Attempting to open the Database file :- " + outFileName);
try
myOutput = new FileOutputStream(outFileName);
catch (IOException e)
Log.d(TAG,"Error attempting to open the Database file :-" + outFileName);
throw new RuntimeException(e);
byte[] buffer = new byte[4096];
long bytescopied = 0;
int length;
Log.d(TAG,"Attempting to copy from the asset file to the Database file");
try
while ((length = myInput.read(buffer)) > 0)
myOutput.write(buffer, 0, length);
bytescopied = bytescopied + length;
catch (IOException e)
Log.d(TAG,"Error while copying from the asset file to the Database file - " +
String.valueOf(bytescopied) +
" bytes copied, so far.");
Log.d(TAG,"File has been copied from the assets file to the Database file." +
String.valueOf(bytescopied) +
" bytes were copied."
);
Log.d(TAG, "Attempting to flush and close files.");
try
myOutput.flush();
myOutput.close();
myInput.close();
catch (IOException e)
Log.d(TAG,"Error flusing or closing files.");
public void openDataBase()
String myPath = DB_PATH + DB_NAME;
database = SQLiteDatabase.openDatabase (myPath, null, SQLiteDatabase.OPEN_READONLY);
public Cursor readData()
// String[] allColumns = new String[] DatabaseHelper.COL1,DatabaseHelper.COL2;
//<<<<< for a CursorAdapater _id column MUST be included
// Assuming you have an _id column then allColumns replaced with null (all columns)
// Alternaelty if the table doesn have _id column then you could use :-
//String[] allColumns = new String[] DatabaseHelper.COL1,DatabaseHelper.COL2,"rowid AS _id";
Cursor c =database.query (DatabaseHelper.TABLE_NAME,null,null,null,null,null,null);
//<<<< useless code cursor WILL NOT be null
// (very rarely would a cursor be null and
// probably only if trapped by try/catch
// which will tend to obfuscate matters/issues
// )
/*
if(c != null)
c.moveToFirst ();
*/
return c;
@Override
public synchronized void close()
if (database != null)
database.close ();
super.close ();
@Override
public void onCreate(SQLiteDatabase db)
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
if (newVersion > oldVersion)
copyDataBase();
public Cursor query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy)
return database.query ("fradeu", null, null, null, null, null,null);
片段的onCreateView方法:-
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
//<<<< Obviously change to use your layout (this is stock layout)
View rootView = inflater.inflate(R.layout.fragment_so50804849, container, false);
listView = (ListView) rootView.findViewById(R.id.list); //<<<< ADDED NOTE use your id
buttondisplay = (Button) rootView.findViewById(R.id.showlist); //<<<< ADDED NOTE use your id
DatabaseHelper myDbHelper = new DatabaseHelper (getActivity ());
myDbHelper.createDataBase();
myDbHelper.openDataBase();
/*
c = myDbHelper.query(DatabaseHelper.TABLE_NAME,null,null,null,null,null,null);
Cursor c = myDbHelper.readData(); //???? two cursors called c c will now refer to this one
*/
c = myDbHelper.readData(); //<<<< Just the one cursor
String[] from = new String []DatabaseHelper.COL1,DatabaseHelper.COL2;
int[] to = new int[] R.id.fra, R.id.deu;
adapter = new SimpleCursorAdapter(getActivity(),R.layout.list_view_adapter,c,from,to,0);
//listView.setAdapter(adapter);
//<<<< No need for a button see commented out line above where setAdapter is used this works
buttondisplay.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
if (buttondisplay.getText().toString().contains("SHOW"))
listView.setAdapter(adapter);
buttondisplay.setText("HIDE LIST");
else
listView.setAdapter(null);
buttondisplay.setText("SHOW LIST");
);
return rootView;
【讨论】:
以上是关于如何在片段类的列表视图中显示 SQLite 数据库?的主要内容,如果未能解决你的问题,请参考以下文章
如何在片段内的 recylerview 列表中显示 SQLite 数据库数据?
当我从用户获取数据并将其保存到 SQLite 数据库中时,我应该怎么做才能使列表视图在片段中工作