如何在资产文件夹中用数据库填充 ListView?
How to populate ListView with db in asset folder?
所以我想制作一个应用程序,列出我存储在我创建的现有 SQLite 数据库中的食物。我的 foodDB.db 文件在 /assets/databases 文件夹中。
我知道我必须使用 DatabaseHelper class。我已经做了相当多的研究,我看过很多 Whosebug 帖子和 youtube 教程,但 none 满足我从资产文件夹中的现有数据库填充 ListView 的标准。我觉得他们很混乱,不清楚。
有人可以清楚地向我解释我将如何处理吗?我真的很挣扎,希望得到一些指导。
我的数据库名为 foodDatabase.db
。
我的数据库包含 1 个 table,名为 dataset
。
table dataset
包含列:id, name, description, protein, fat, carbohydrates, energy, starch, sugar, cholesterol
。
首先要注意几点
1 - 你说文件是 FoodDB.db 但后来又说数据库叫做 foodDatabase.db。数据库名称是文件名。因此,以下示例使用 FoodDB.db 作为资产中的文件(您可以在从资产复制时重命名文件,但我在此答案中没有这样做.)
2 - 您不需要数据库助手,示例中也没有使用。
有两部分:-
1) 访问数据库以提取 ListView 的数据。在以下示例中,这是从资产复制到标准数据库位置 (/data/data/the_package/databases/the_database_name)。
- 假设一旦从资产中复制,数据库随后将被使用(即在应用程序的生命周期内复制一次)。
2) 在 ListView 中显示提取的数据(作为 Cursor 获取)。
要执行 2,您需要布局包含一个 ListView,因此使用了以下布局。 activity_main.xml :-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="fooddb.so49328656populatelistview.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
/>
<ListView
android:id="@+id/foodlist"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
- 注意
tools:context="fooddb.so49328656populatelistview.MainActivity"
必须反映 您的包裹
数据库助手 - 未按警告使用
调用activityMainActivity.java(见注释):-
public class MainActivity extends AppCompatActivity {
static final String DBNAME = "FoodDB.db";
static final String DBASSETPATH = "databases/" + DBNAME;
static final String FOODTABLE = "dataset";
static final String FOODCOLUMN = "Food";
static final String IDCOLUMN = "ID";
ListView mFoodList;
SQLiteDatabase mDB;
SimpleCursorAdapter mSCA;
Cursor mCsr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mFoodList = (ListView) this.findViewById(R.id.foodlist);
mDB = openFoodDB();
if (mDB != null) {
mCsr = mDB.query(FOODTABLE,
new String[]{IDCOLUMN + " AS _id",
FOODCOLUMN
},
null,null,null,null,null);
mSCA = new SimpleCursorAdapter(this,android.R.layout.simple_list_item_1,mCsr,
new String[]{FOODCOLUMN},
new int[]{android.R.id.text1},0);
mFoodList.setAdapter(mSCA);
} else {
Toast.makeText(this,"Unable to open Database.",Toast.LENGTH_LONG);
}
}
private SQLiteDatabase openFoodDB() {
String dbpath = this.getDatabasePath(DBNAME).getPath();
if (this.getDatabasePath(DBNAME).exists()) {
Log.d("OPENFOODDB","Opening already existing Database");
return SQLiteDatabase.openDatabase(dbpath,null,SQLiteDatabase.OPEN_READWRITE);
}
InputStream is;
byte[] buffer;
FileOutputStream db;
try {
is = this.getAssets().open(DBASSETPATH);
buffer = new byte[is.available()];
is.read(buffer);
is.close();
} catch (Exception e) {
e.printStackTrace();
Log.d("OPENFOODDB","Unable to locate or buffer input from assets " + DBASSETPATH);
return null;
}
// Just in case the databases directory doesn't exist create it.
File dbmkdir = (this.getDatabasePath(DBNAME)).getParentFile();
dbmkdir.mkdirs();
try {
db = new FileOutputStream(this.getDatabasePath(DBNAME).getPath());
} catch (Exception e) {
e.printStackTrace();
Log.d("OPENFOODDB","Unable to create outputstream for DB at path " + dbpath);
try {
is.close();
} catch (Exception e2) {
}
return null;
}
try {
db.write(buffer);
db.flush();
db.close();
is.close();
} catch (Exception e) {
Log.d("OPENFOODDB","Failed to copy asset to DB");
e.printStackTrace();
return null;
}
return SQLiteDatabase.openDatabase(dbpath,null,SQLiteDatabase.OPEN_READWRITE);
}
}
备注
openFoodDB
方法return如果数据库不存在,则从资产文件复制后的SQLiteDatabase。如果有问题,该方法将 return 无效。
- 如果数据库存在,那么日志将包含类似
D/OPENFOODDB: Opening already existing Database
的消息
- 如果数据库是从资产文件中复制并成功打开的,则不会有日志消息。只有在出现问题时才会记录消息。
- 例如,如果资产文件丢失,那么您会在日志中收到一条消息,例如
D/OPENFOODDB: Unable to locate or buffer input from assets databases/FoodDB.db
这将在堆栈跟踪之前显示
例如:-
03-16 22:17:04.008 1529-1529/? W/System.err: java.io.FileNotFoundException: databases/FoodDB.db
03-16 22:17:04.008 1529-1529/? W/System.err: at android.content.res.AssetManager.openAsset(Native Method)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.content.res.AssetManager.open(AssetManager.java:315)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.content.res.AssetManager.open(AssetManager.java:289)
03-16 22:17:04.008 1529-1529/? W/System.err: at fooddb.so49328656populatelistview.MainActivity.openFoodDB(MainActivity.java:63)
03-16 22:17:04.008 1529-1529/? W/System.err: at fooddb.so49328656populatelistview.MainActivity.onCreate(MainActivity.java:37)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.app.Activity.performCreate(Activity.java:5008)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.app.ActivityThread.access0(ActivityThread.java:130)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.os.Handler.dispatchMessage(Handler.java:99)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.os.Looper.loop(Looper.java:137)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.app.ActivityThread.main(ActivityThread.java:4745)
03-16 22:17:04.008 1529-1529/? W/System.err: at java.lang.reflect.Method.invokeNative(Native Method)
03-16 22:17:04.008 1529-1529/? W/System.err: at java.lang.reflect.Method.invoke(Method.java:511)
03-16 22:17:04.008 1529-1529/? W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
03-16 22:17:04.008 1529-1529/? W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
03-16 22:17:04.008 1529-1529/? W/System.err: at dalvik.system.NativeStart.main(Native Method)
- CursorAdapter 需要一个专门命名为 _id 的列,因此使用
IDCOLUMN + " AS _id"
.
结果:-
所以我想制作一个应用程序,列出我存储在我创建的现有 SQLite 数据库中的食物。我的 foodDB.db 文件在 /assets/databases 文件夹中。
我知道我必须使用 DatabaseHelper class。我已经做了相当多的研究,我看过很多 Whosebug 帖子和 youtube 教程,但 none 满足我从资产文件夹中的现有数据库填充 ListView 的标准。我觉得他们很混乱,不清楚。
有人可以清楚地向我解释我将如何处理吗?我真的很挣扎,希望得到一些指导。
我的数据库名为 foodDatabase.db
。
我的数据库包含 1 个 table,名为 dataset
。
table dataset
包含列:id, name, description, protein, fat, carbohydrates, energy, starch, sugar, cholesterol
。
首先要注意几点
1 - 你说文件是 FoodDB.db 但后来又说数据库叫做 foodDatabase.db。数据库名称是文件名。因此,以下示例使用 FoodDB.db 作为资产中的文件(您可以在从资产复制时重命名文件,但我在此答案中没有这样做.)
2 - 您不需要数据库助手,示例中也没有使用。
有两部分:-
1) 访问数据库以提取 ListView 的数据。在以下示例中,这是从资产复制到标准数据库位置 (/data/data/the_package/databases/the_database_name)。
- 假设一旦从资产中复制,数据库随后将被使用(即在应用程序的生命周期内复制一次)。
2) 在 ListView 中显示提取的数据(作为 Cursor 获取)。
要执行 2,您需要布局包含一个 ListView,因此使用了以下布局。 activity_main.xml :-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="fooddb.so49328656populatelistview.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
/>
<ListView
android:id="@+id/foodlist"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
- 注意
tools:context="fooddb.so49328656populatelistview.MainActivity"
必须反映 您的包裹
数据库助手 - 未按警告使用
调用activityMainActivity.java(见注释):-
public class MainActivity extends AppCompatActivity {
static final String DBNAME = "FoodDB.db";
static final String DBASSETPATH = "databases/" + DBNAME;
static final String FOODTABLE = "dataset";
static final String FOODCOLUMN = "Food";
static final String IDCOLUMN = "ID";
ListView mFoodList;
SQLiteDatabase mDB;
SimpleCursorAdapter mSCA;
Cursor mCsr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mFoodList = (ListView) this.findViewById(R.id.foodlist);
mDB = openFoodDB();
if (mDB != null) {
mCsr = mDB.query(FOODTABLE,
new String[]{IDCOLUMN + " AS _id",
FOODCOLUMN
},
null,null,null,null,null);
mSCA = new SimpleCursorAdapter(this,android.R.layout.simple_list_item_1,mCsr,
new String[]{FOODCOLUMN},
new int[]{android.R.id.text1},0);
mFoodList.setAdapter(mSCA);
} else {
Toast.makeText(this,"Unable to open Database.",Toast.LENGTH_LONG);
}
}
private SQLiteDatabase openFoodDB() {
String dbpath = this.getDatabasePath(DBNAME).getPath();
if (this.getDatabasePath(DBNAME).exists()) {
Log.d("OPENFOODDB","Opening already existing Database");
return SQLiteDatabase.openDatabase(dbpath,null,SQLiteDatabase.OPEN_READWRITE);
}
InputStream is;
byte[] buffer;
FileOutputStream db;
try {
is = this.getAssets().open(DBASSETPATH);
buffer = new byte[is.available()];
is.read(buffer);
is.close();
} catch (Exception e) {
e.printStackTrace();
Log.d("OPENFOODDB","Unable to locate or buffer input from assets " + DBASSETPATH);
return null;
}
// Just in case the databases directory doesn't exist create it.
File dbmkdir = (this.getDatabasePath(DBNAME)).getParentFile();
dbmkdir.mkdirs();
try {
db = new FileOutputStream(this.getDatabasePath(DBNAME).getPath());
} catch (Exception e) {
e.printStackTrace();
Log.d("OPENFOODDB","Unable to create outputstream for DB at path " + dbpath);
try {
is.close();
} catch (Exception e2) {
}
return null;
}
try {
db.write(buffer);
db.flush();
db.close();
is.close();
} catch (Exception e) {
Log.d("OPENFOODDB","Failed to copy asset to DB");
e.printStackTrace();
return null;
}
return SQLiteDatabase.openDatabase(dbpath,null,SQLiteDatabase.OPEN_READWRITE);
}
}
备注
openFoodDB
方法return如果数据库不存在,则从资产文件复制后的SQLiteDatabase。如果有问题,该方法将 return 无效。- 如果数据库存在,那么日志将包含类似
D/OPENFOODDB: Opening already existing Database
的消息
- 如果数据库是从资产文件中复制并成功打开的,则不会有日志消息。只有在出现问题时才会记录消息。
- 例如,如果资产文件丢失,那么您会在日志中收到一条消息,例如
D/OPENFOODDB: Unable to locate or buffer input from assets databases/FoodDB.db
这将在堆栈跟踪之前显示
- 如果数据库存在,那么日志将包含类似
例如:-
03-16 22:17:04.008 1529-1529/? W/System.err: java.io.FileNotFoundException: databases/FoodDB.db
03-16 22:17:04.008 1529-1529/? W/System.err: at android.content.res.AssetManager.openAsset(Native Method)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.content.res.AssetManager.open(AssetManager.java:315)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.content.res.AssetManager.open(AssetManager.java:289)
03-16 22:17:04.008 1529-1529/? W/System.err: at fooddb.so49328656populatelistview.MainActivity.openFoodDB(MainActivity.java:63)
03-16 22:17:04.008 1529-1529/? W/System.err: at fooddb.so49328656populatelistview.MainActivity.onCreate(MainActivity.java:37)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.app.Activity.performCreate(Activity.java:5008)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.app.ActivityThread.access0(ActivityThread.java:130)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.os.Handler.dispatchMessage(Handler.java:99)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.os.Looper.loop(Looper.java:137)
03-16 22:17:04.008 1529-1529/? W/System.err: at android.app.ActivityThread.main(ActivityThread.java:4745)
03-16 22:17:04.008 1529-1529/? W/System.err: at java.lang.reflect.Method.invokeNative(Native Method)
03-16 22:17:04.008 1529-1529/? W/System.err: at java.lang.reflect.Method.invoke(Method.java:511)
03-16 22:17:04.008 1529-1529/? W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
03-16 22:17:04.008 1529-1529/? W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
03-16 22:17:04.008 1529-1529/? W/System.err: at dalvik.system.NativeStart.main(Native Method)
- CursorAdapter 需要一个专门命名为 _id 的列,因此使用
IDCOLUMN + " AS _id"
.