首页 > 解决方案 > 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);

            }
        }
    });
}

}

标签: androiddatabasesqliteandroid-sqlite

解决方案


一切都在测试代码之后。所以看起来问题是数据库是空的(也许没有用 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 ....因为数据库不存在。

推荐阅读