android - Android SQlite 错误 *没有这样的表:帐户*
问题描述
我已经通过数据库浏览器为 sqlite创建了一个数据库表,并将该文件添加到 Assets 文件夹中。当我单击按钮时,我想从表中获取数据并在 TextView 中显示它们,但每次我运行时什么都没有出现,编译器说它们不是名为 Account 的表。我看过很多教程,每次出现相同的错误时,这就是代码。
帐户
public class Account {
private String UserName;
private String Email;
public Account() {
}
public Account(String userName, String email) {
UserName = userName;
Email = email;
}
public String getUserName() {
return UserName;
}
public void setUserName(String userName) {
UserName = userName;
}
public String getEmail() {
return Email;
}
public void setEmail(String email) {
Email = email;
}
}
数据库助手
public class DbHelper extends SQLiteOpenHelper {
private static String DB_PATH="";
private static String DB_NAME="MyDB.db";
private SQLiteDatabase mDataBase;
private Context mContext;
public DbHelper(Context context) {
super(context, DB_NAME, null, 1);
if (Build.VERSION.SDK_INT >= 17){
DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
} else {
DB_PATH = "/data/data/" + context.getPackageName() + "/databases/";
}
mContext = context;
}
@Override
public synchronized void close() {
if (mDataBase != null){
mDataBase.close();
}
super.close();
}
private boolean checkDataBase(){
SQLiteDatabase tempDB = null;
try {
String path = DB_PATH + DB_NAME;
tempDB = SQLiteDatabase.openDatabase(path,null, SQLiteDatabase.OPEN_READWRITE);
}
catch (Exception ex){
if (tempDB != null)
tempDB.close();
}
return tempDB != null ? true:false;
}
public void copyDataBase(){
try {
InputStream myInput = mContext.getAssets().open(DB_NAME);
String outputFileNme = DB_PATH + DB_NAME;
OutputStream myOutput = new FileOutputStream(outputFileNme);
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer))>0){
myOutput.write(buffer,0,length);
}
myOutput.flush();
myOutput.close();
myInput.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void openDataBase(){
String path = DB_PATH + DB_NAME;
mDataBase = SQLiteDatabase.openDatabase(path,null,SQLiteDatabase.OPEN_READWRITE);
}
public void createDataBase(){
boolean isDBExist = checkDataBase();
if (isDBExist){
} else {
this.getReadableDatabase();
try {
copyDataBase();
}catch (Exception ex){
}
}
}
public List<Account> getAllUsers(){
List<Account> temp = new ArrayList<Account>();
SQLiteDatabase db = this.getWritableDatabase();
Cursor c;
try {
c = db.rawQuery("SELECT * FROM Account",null);
if (c == null) return null;
c.moveToFirst();
do {
Account account = new Account(c.getString(c.getColumnIndex("UserName")),c.getString(c.getColumnIndex("Email")));
temp.add(account);
} while (c.moveToNext());
c.close();
} catch (Exception e){
}
db.close();
return temp;
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
主要活动
public class MainActivity extends AppCompatActivity {
List<Account> lstUser = new ArrayList<Account>();
DbHelper dbHelper;
Button btnGetData;
LinearLayout container;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnGetData = findViewById(R.id.btnGetData);
container = findViewById(R.id.container);
dbHelper = new DbHelper(getApplicationContext());
dbHelper.createDataBase();
btnGetData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
lstUser = dbHelper.getAllUsers();
for (Account account:lstUser){
LayoutInflater inflater = (LayoutInflater) getBaseContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View addView = inflater.inflate(R.layout.row,null);
TextView txtUser = addView.findViewById(R.id.txtUser);
TextView txtEmail = addView.findViewById(R.id.txtEmail);
txtUser.setText(account.getUserName());
txtEmail.setText(account.getEmail());
container.addView(addView);
}
}
});
}
}
解决方案
一切都在测试代码之后。所以看起来问题是数据库是空的(也许没有用 DBBrowser for SQlite 正确保存,这看起来很古怪)。
如果使用 DB Browser for SQlite,我建议始终保存数据库(写入更改),关闭数据库,然后打开数据库并检查它是否符合预期。重复直到它是,然后将文件复制到资产文件夹。
但是,这是 CopyDatabase 方法的修改版本,它可能有助于检测复制数据库的任何问题:-
public boolean copyDataBase() {
InputStream myInput;
OutputStream myOutput;
try {
myInput = mContext.getAssets().open(DB_NAME);
} catch (IOException ex) {
Log.d("COPYDB-OPN ASSET","IoException opening Asset file " + DB_NAME);
ex.printStackTrace();
return false;
}
String outputFileNme = DB_PATH + DB_NAME;
try {
myOutput = new FileOutputStream(outputFileNme);
} catch (IOException ex) {
Log.d("COPYDB-OPN OUT","IOException opening Output file " + outputFileNme);
ex.printStackTrace();
return false;
}
long bytes_read = 0;
long bytes_written = 0;
try {
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
bytes_read = bytes_read + length;
myOutput.write(buffer, 0, length);
bytes_written = bytes_written + length;
}
} catch (IOException ex) {
Log.d("COPYDB-CPY DATA",
"IOException Copying Data. " +
" Bytes Read=" + String.valueOf(bytes_read) +
" Bytes Written=" + String.valueOf(bytes_written));
ex.printStackTrace();
return false;
}
try {
myOutput.flush();
myOutput.close();
myInput.close();
} catch (IOException e) {
Log.d("COPYDB-FINALISE","IOException Flushing/Closing Files");
e.printStackTrace();
return false;
}
Log.d("COPYDB-COMPLETED",
"The copy of " + DB_NAME + " has completed. " +
String.valueOf(bytes_written) + " bytes were copied to " + outputFileNme);
return true;
}
- 基本上代替单个 try/catch 子句,引入了多个 try/catch 子句,允许捕获和报告任何问题。
- 该方法还返回一个布尔值,指示它是否已成功完成。
- 如果它确实成功完成,则会相应地向日志输出一条消息。
也可以使用稍微不同的 CreateDatabase 方法:-
public void createDataBase() {
boolean isDBExist = checkDataBase();
if (isDBExist) {
} else {
this.getReadableDatabase();
if (!copyDataBase()) {
throw new RuntimeException("Failed to Copy Database " + DB_NAME + " from the Asset file");
}
}
}
- 这将抛出复制失败的异常。
例如,如果资产文件丢失,则日志中将出现以下内容:-
6-15 04:42:49.633 2252-2252/? E/SQLiteLog: (14) cannot open file at line 35652 of [8201f4e1c5]
(14) os_unix.c:35652: (2) open(/data/user/0/soanswers.soanswers/databases/MyDB.db) -
06-15 04:42:49.641 2252-2252/? E/SQLiteDatabase: Failed to open database '/data/user/0/soanswers.soanswers/databases/MyDB.db'.
android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database
at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:209)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:808)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:793)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:696)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:671)
at soanswers.soanswers.DbHelperSO50867547.checkDataBase(DbHelperSO50867547.java:49)
at soanswers.soanswers.DbHelperSO50867547.createDataBase(DbHelperSO50867547.java:115)
at soanswers.soanswers.MainActivity.SO50867547(MainActivity.java:635)
at soanswers.soanswers.MainActivity.onCreate(MainActivity.java:140)
at android.app.Activity.performCreate(Activity.java:6975)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
06-15 04:42:49.645 2252-2252/? I/swers.soanswers: type=1400 audit(0.0:2324): avc: denied { read } for name="databases" dev="sdb3" ino=81932 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:system_data_file:s0:c512,c768 tclass=dir permissive=1
06-15 04:42:49.657 2252-2252/? I/swers.soanswers: type=1400 audit(0.0:2326): avc: denied { setattr } for name="MyDB.db" dev="sdb3" ino=81933 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:system_data_file:s0:c512,c768 tclass=file permissive=1
06-15 04:42:49.666 2252-2252/? D/COPYDB-OPN ASSET: IoException opening Asset file MyDB.db
06-15 04:42:49.666 2252-2252/? W/System.err: java.io.FileNotFoundException: MyDB.db
at android.content.res.AssetManager.openAsset(Native Method)
at android.content.res.AssetManager.open(AssetManager.java:374)
at android.content.res.AssetManager.open(AssetManager.java:348)
at soanswers.soanswers.DbHelperSO50867547.copyDataBase(DbHelperSO50867547.java:61)
at soanswers.soanswers.DbHelperSO50867547.createDataBase(DbHelperSO50867547.java:119)
at soanswers.soanswers.MainActivity.SO50867547(MainActivity.java:635)
06-15 04:42:49.667 2252-2252/? W/System.err: at soanswers.soanswers.MainActivity.onCreate(MainActivity.java:140)
at android.app.Activity.performCreate(Activity.java:6975)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
06-15 04:42:49.668 2252-2252/? W/System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
注意 无法打开数据库是由于 checkDatabase 方法检查数据库是否存在。
由于无法打开资产文件,真正的错误是:-
06-15 04:42:49.666 2252-2252/? D/COPYDB-OPN ASSET: IoException opening Asset file MyDB.db 06-15 04:42:49.666 2252-2252/? W/System.err: java.io.FileNotFoundException: MyDB.db at android.content.res.AssetManager.openAsset(Native Method) at android.content.res.AssetManager.open(AssetManager.java:374) at android.content.res.AssetManager.open(AssetManager.java:348) at soanswers.soanswers.DbHelperSO50867547.copyDataBase(DbHelperSO50867547.java:61)
如果没有错误,那么日志将包含类似于:-
06-15 04:57:57.337 2384-2384/soanswers.soanswers D/COPYDB-COMPLETED: The copy of MyDB.db has completed. 8192 bytes were copied to /data/user/0/soanswers.soanswers/databases/MyDB.db
- 请注意,由于数据库在此阶段不存在,因此日志还将包含堆栈跟踪,
E/SQLiteLog: (14) cannot open file at line ....
因为数据库不存在。
推荐阅读
- django - 如何过滤模型并加入用户模型
- angular - 我想在其他网站上使用我的 Angular 4 应用程序作为小部件 - 无论网站语言 -
- php - 无论您如何提交信息,都可以获得统一的 $_GET 数组
- oracle - NLS_LANG不同的民族方言
- python - 当我加载我的 json 文件时,我收到此错误:发生异常:json.decoder.JSONDecodeError
- spring-boot - 如何在 Spring Security oauth2 中调试重定向 uri?
- javascript - 如何在javascript中将放置区域的宽度调整为100%
- angularjs - 我们如何更改 Angular js 错误控制台
- c++ - CreateDirectory doesn't create a directory VS2017 c++
- html - 按钮应该相对于css中的右侧折叠栏