简体   繁体   English

Android设备上的SQLite异常:没有这样的表,但是模拟器可以正常工作吗?

[英]SQLite exception on Android Device : No such table, but emulator works fine?

I've looked through this question as well : problem about sqlite database, no such table: but have had no success in fixing the problem. 我也仔细研究了这个问题: 关于sqlite数据库的问题,没有这样的表:但是在解决问题上没有成功。

As the title mentions, the exact same code was able to run on the emulator fine(displays the table) but runs into the exception with "no such table" found on the device. 如标题所述,完全相同的代码可以在模拟器上很好地运行(显示表),但是遇到异常,但在设备上找不到“没有这样的表”。 Using an HTC Desire Z Android version 2.2.1 使用HTC Desire Z Android 2.2.1版

I was basically following this tutorial: http://www.reigndesign.com/blog/using-your-own-sqlite-database-in-android-applications/ 我基本上是在遵循本教程: http : //www.reigndesign.com/blog/using-your-own-sqlite-database-in-android-applications/

The idea being to copy a preloaded database to the directory which the android app will use to make changes to, then copy out to the sd card upon a save being called. 想法是将预加载的数据库复制到android应用将用于进行更改的目录,然后在调用保存时将其复制到sd卡。 However, although the copy from the assets folder to the app database directory works fine, and the copy to the SD card works fine (tested by opening the db file copied out to the sd card using an sqlite browser), trying to display the database on the device gives me a problem whereas i've run into no problems at all with the emulator. 但是,尽管从资产文件夹到应用程序数据库目录的复制工作正常,并且到SD卡的复制工作正常(通过使用sqlite浏览器打开复制到sd卡的db文件进行了测试),但尝试显示数据库在设备上给我带来了一个问题,而我在模拟器上完全没有遇到任何问题。

here is the code for the database helper: 这是数据库助手的代码:

 public class DatabaseHelper extends SQLiteOpenHelper{

private static String DB_PATH = "/data/data/com.mko.preloaddb/databases/";
private static String DB_NAME = "preloaddb";
private SQLiteDatabase myDB;
private final Context myContext;


public DatabaseHelper(Context context) {
    super(context, DB_NAME, null, 1);
    this.myContext = context;
}

@Override
public void onCreate(SQLiteDatabase db) {
    // TODO Auto-generated method stub

}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    // TODO Auto-generated method stub

}

/**
 * Creates DB by copying over DB from assets if it doesn't exist yet
 * @throws IOException
 */
public void createDatabase() throws IOException{
    boolean dbExist = checkDatabase();

    if(dbExist){
        Log.e("DatabaseHelper","database exists");
    }else{
        this.getReadableDatabase().close();

        try{
            //copy preloaded db from assets if it doesn't exist yet
            copyDatabase();
        }catch(IOException e){
            throw new Error("Error copying database");
        }
    }
}

public void openDatabase() throws SQLException{
    //open the database
    String myPath = DB_PATH + DB_NAME;
    myDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);
}

/***
 * Copies preloaded db from assets
 * @throws IOException
 */
private void copyDatabase() throws IOException{
    //Open local db as input steam
    InputStream myInput = myContext.getAssets().open(DB_NAME);

    //Path to just created empty db
    String outFileName = DB_PATH + DB_NAME;

    //open the empty db as the output stream
    OutputStream myOutput = new FileOutputStream(outFileName);

    byte[] buffer = new byte[1024];
    int length;
    while((length = myInput.read(buffer))>0){
        myOutput.write(buffer,0,length);
    }

    myOutput.flush();
    myOutput.close();
    myInput.close();


}

private boolean checkDatabase(){
    SQLiteDatabase checkDB = null;

    try{
        String myPath = DB_PATH + DB_NAME;
        checkDB = SQLiteDatabase.openDatabase(myPath, null,   SQLiteDatabase.OPEN_READONLY);
    }catch(SQLiteException e){
        //database doesn't exist yet, so checkDB will be null
    }
    if(checkDB !=null){
        checkDB.close();            
    }
    return checkDB !=null ? true : false;
    }

}

And here is the code for the activity that calls it: 这是调用它的活动的代码:

public class PreloadDBTestActivity extends Activity {
/** Called when the activity is first created. */
Application myApp;
DatabaseHelper myDbHelper;
SQLiteDatabase myDb;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    myApp = this.getApplication();
    myDbHelper = new DatabaseHelper(this);               
    setContentView(R.layout.main);

}

public void refreshViewTable(View v){

    TableLayout tl = (TableLayout)findViewById(R.id.tbl_dbview);
    if(myDb==null || !myDb.isOpen()){
        openDB(null);
    }
    String[] result_columns = new String[]{"_id","baseclassname","basehealth"};
    Cursor allRows = myDb.query(true, "baseclasses", result_columns, null, null, null, null, null, null);

    if(allRows.moveToFirst()){
        do{
            String classname = allRows.getString(1);
            TableRow curr = new TableRow(this);
            TextView text = new TextView(this);
            text.setText(classname);
            curr.addView(text);
            tl.addView(curr);
        }while(allRows.moveToNext());
    }


}

public void openDB(View v){
    TextView tv = (TextView)findViewById(R.id.lbl_debug);
    try{
        myDbHelper.createDatabase();
    }catch (IOException ioe){
        throw new Error("Unable to create database");
    }
    try{
        myDb = myDbHelper.getWritableDatabase();
    }catch(SQLiteException e){

        tv.setText("Unable to open writable database");
    }
    Toast.makeText(this, "Successful open, copy should work", Toast.LENGTH_LONG).show();

}

public boolean copyDbToSd(View v){
    File dbfile = new File(Environment.getDataDirectory()+"/data/com.mko.preloaddb/databases/preloaddb");
    File exportDir = new File(Environment.getExternalStorageDirectory(),"/exampledata/example");

    TextView tv = (TextView)findViewById(R.id.lbl_debug);
    if(myDb.isOpen()){
        myDb.close();

    }

    if(!exportDir.exists()){
        boolean success = exportDir.mkdirs();

        tv.setText("Making dir");
        if(success){
            Toast.makeText(this, "Success expor dir !"+exportDir.getAbsolutePath(), Toast.LENGTH_LONG).show();

        }else{
            Toast.makeText(this, "No success expor dir =("+exportDir.getAbsolutePath(), Toast.LENGTH_LONG).show();
        }

    }
    if(!dbfile.exists()){           
        tv.setText("Database file does not exist or wrong directory "+dbfile.getAbsolutePath());
    }else{          
        tv.setText("Database file found! " +dbfile.getAbsolutePath());
    }
    File file = new File(exportDir,dbfile.getName());
    try{
        file.createNewFile();
        if(!file.exists()){
            Toast.makeText(this, "DestinationFile does not exist!", Toast.LENGTH_LONG).show();
        }
        this.copyfile(dbfile, file);
        return true;            
    }catch (IOException e){
        Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
        Log.e("Preload", e.getMessage(), e);
        return false;
    }
}

private void copyfile(File src, File dst) throws IOException{
    FileChannel inChannel = new FileInputStream(src).getChannel();
    FileChannel outChannel = new FileOutputStream(dst).getChannel();
    try{
        inChannel.transferTo(0, inChannel.size(), outChannel);
    }finally{
        if(inChannel!=null){
            inChannel.close();
        }           
        if(outChannel!=null){
            outChannel.close();
        }
    }
}

private boolean isExternalStorageAvail(){
    return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);     
}

Just in case it's confusing, i've bound the methods "openDB","copyDbToSd" and "refreshViewTable" to buttons on the gui, and I hit the buttons in the order of "openDB", "refreshViewTable" and "copyDBToSd" 以防万一,我将方法“ openDB”,“ copyDbToSd”和“ refreshViewTable”绑定到gui上的按钮,然后按“ openDB”,“ refreshViewTable”和“ copyDBToSd”的顺序单击按钮

I've already had the same problem with the method 我已经在方法上遇到了同样的问题

SQLiteDatabase.openDatabase

the method getWritebleDatabase() calls the onCreate() method of the DBHandler (if DB file doesn't exists, then onOpen() ). 方法getWritebleDatabase()调用DBHandler的onCreate()方法(如果数据库文件不存在,则调用onOpen())。

So, maybe you can take a look at the code below: 因此,也许您可​​以看一下下面的代码:

public class SqlDBAdapter {

 private static final String DB_NAME = "projHours.sqlite"; private static final int DB_VERSION = 1; private static Context c; private SQLiteDatabase db; private SQLiteOpenHelper sqlDBHelp; /** * Constructor for the SQL DB Adapter, copy DB from assets if not exists in /data/data/<package-name>/databases * * @param c */ public SqlDBAdapter(Context c) { super(); SqlDBAdapter.c = c; sqlDBHelp = new SqlDBHelper(); } /** * Open the SQL DB as Writable */ public void openDB() { try { db = sqlDBHelp.getWritableDatabase(); } catch (SQLiteException ex) { Toast.makeText(c, "DB with filename " + DB_NAME + "coudn't be opend!", Toast.LENGTH_SHORT); } } /** * Close the SQL DB */ public void closeDB() { db.close(); } /** * Helper class for the SQL DB Adapter */ static class SqlDBHelper extends SQLiteOpenHelper { private static final String DB_PATH = "/data/data/" + c.getPackageName() + "/databases/" + DB_NAME; public SqlDBHelper() { super(c, DB_NAME, null, DB_VERSION); createDB(); } private void createDB() { SharedPreferences prefs = c.getSharedPreferences("sharedPrefs", 0); boolean dbExists = prefs.getBoolean("dbExists", false); Log.d("PM.ADA.SDA", "DB Exists : " + dbExists); if (!dbExists) { this.getReadableDatabase(); copyDB(); prefs.edit().putBoolean("dbExists", true).commit(); } } @Override public void onCreate(SQLiteDatabase db) {} @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {} public void copyDB() { try { InputStream is = c.getAssets().open(DB_NAME); BufferedInputStream bis = new BufferedInputStream(is); OutputStream os = new FileOutputStream(DB_PATH); BufferedOutputStream bos = new BufferedOutputStream(os); byte[] buffer = new byte[64]; int length; while ((length = bis.read(buffer)) > 0) { bos.write(buffer, 0, length); } bos.flush(); bos.close(); bis.close(); } catch (IOException e) { e.printStackTrace(); } } } 

}

I use an inner class for my DB Helper that extends the SQLiteOpenHelper. 我为数据库助手使用了一个内部类,该类扩展了SQLiteOpenHelper。 the methods onCreate() and onUpgrade() are here required. 这里需要方法onCreate()和onUpgrade()。

I use a SharedPreferences file to safe a boolean value to check, if the database exists in /data/data/ 我使用SharedPreferences文件来保护布尔值以检查数据库是否存在于/ data / data /

Hope this will help you! 希望这个能对您有所帮助!

Have nice coding! 编码不错!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM