简体   繁体   中英

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.

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

I was basically following this tutorial: 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. 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.

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"

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() ).

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. the methods onCreate() and onUpgrade() are here required.

I use a SharedPreferences file to safe a boolean value to check, if the database exists in /data/data/

Hope this will help you!

Have nice coding!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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