1

Copying sqlite database is working in samsung mobiles but it is not working in Redmi or Oppo or Vivo phones for example OS with Redmi MIUI Global 10.3.12 stable version it is crashing.

I am expecting to work on all platforms.

I have tried installing in all models in emulators. working fine in all devices but the problem is with Vivo, Redmi, Oppo mobile UIs.

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    lvProduct = (ListView) findViewById(R.id.listview_product);
    mDBHelper = new DatabaseHelper(this);
    File database = getApplicationContext().getDatabasePath(DatabaseHelper.DBNAME);
    if (false == database.exists()) {
        mDBHelper.getReadableDatabase();
        //Copy db
        if (copyDatabase(this)) {
            Toast.makeText(this, "Copy database succes", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "Copy data error", Toast.LENGTH_SHORT).show();
            return;
        }
    }
}

My database is not copying in Redmi, Vivo,Oppo UIs, But working fine in Samsung mobiles.

enter image description here

Stefan Becker
  • 5,695
  • 9
  • 20
  • 30

1 Answers1

1

Your issue is very likely with mDBHelper.getReadableDatabase();

That is with Android 9+ the default logging has been changed from Journal to WAL (write=ahead logging).

What getReadableDatabase (or getWritableDatabase) does is open a brand new empty database and populates it with a table android_metadata. The actual data is not written to the database file but to the -wal file (i.e. database file name suffixed with -wal).

When the database is copied, the database created by the getReadableDatabase is overwritten but the -wal (and also -shm) files remain. So when the database is opened SQLite detects that the -wal file is not the correct -wal file and fails to open it. The SDK handles this by creating a new empty usable database and hence the table name not found.

There are a number of fixes.

  • You can override the onConfigure method of the database helper and call disableWriteAheadLogging

    • This is not recommended as you lose the advantages of WAL
  • You could use the method getReadableDatabase for a database with another name.

    • I've never come across this, but in theory it would work. Again this is not recommended as it's still relatively resource hungry.
  • You can delete the -wal and -shm files if they exist before or immediately after the copy.

    • This is not recommended as it's wasteful of resources (opening a database is relatively expense resource wise).
  • You can replace the getReadableDatabase with a File's mkdirs. That is the getReadableDatabase has been coded, historicaly, as a hack to get around the NO ENT error due to the databases folder not existing when an app is installed.

  • I recommend not actually doing this after the check for the database existing but as part of the check using something based upon :-

    private boolean checkDataBase(Context context, String databaseName) { /** * Does not open the database instead checks to see if the file exists * also creates the databases directory if it does not exists * (the real reason why the database is opened, which appears to result in issues) */

    File db = new File(context.getDatabasePath(databaseName).getPath()); //Get the file name of the database
    Log.d("DBPATH","DB Path is " + db.getPath()); //TODO remove for Live App
    if (db.exists()) return true; // If it exists then return doing nothing
    
    // Get the parent (directory in which the database file would be)
    File dbdir = db.getParentFile();
    // If the directory does not exits then make the directory (and higher level directories)
    if (!dbdir.exists()) {
        db.getParentFile().mkdirs();
        dbdir.mkdirs();
    }
    return false;
    

    }

  • The code above was taken from A pre-populated database does not work at API 28 throws “no such table” exception , which is a little more comprehensive.

Fix

Applied to your code then it could be :-

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    lvProduct = (ListView) findViewById(R.id.listview_product);
    mDBHelper = new DatabaseHelper(this);
    File database = getApplicationContext().getDatabasePath(DatabaseHelper.DBNAME);
    if (false == database.exists()) {
        File dbdir = database.getParentFile();
        if (!dbdir.exists()) {
            database.getParentFile().mkdirs();
            dbdir.mkdirs();
        }
        //Copy db
        if (copyDatabase(this)) {
            Toast.makeText(this, "Copy database succes", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "Copy data error", Toast.LENGTH_SHORT).show();
            return;
        }
    }
}
MikeT
  • 51,415
  • 16
  • 49
  • 68