53 votes

Android P - «SQLite: aucune erreur de table de ce type» après la copie de la base de données à partir des ressources

J'ai une base de données enregistrée dans le dossier des ressources de mes applications et je copie la base de données à l'aide du code ci-dessous lorsque l'application s'ouvre pour la première fois.

 inputStream = mContext.getAssets().open(Utils.getDatabaseName());

        if(inputStream != null) {

            int mFileLength = inputStream.available();

            String filePath = mContext.getDatabasePath(Utils.getDatabaseName()).getAbsolutePath();

            // Save the downloaded file
            output = new FileOutputStream(filePath);

            byte data[] = new byte[1024];
            long total = 0;
            int count;
            while ((count = inputStream.read(data)) != -1) {
                total += count;
                if(mFileLength != -1) {
                    // Publish the progress
                    publishProgress((int) (total * 100 / mFileLength));
                }
                output.write(data, 0, count);
            }
            return true;
        }
 

Le code ci-dessus s'exécute sans problème, mais lorsque vous essayez d'interroger la base de données, vous obtenez une SQLite: aucune exception de table de ce type.

Ce problème se produit uniquement dans Android P, toutes les versions antérieures d'Android fonctionnent correctement.

Est-ce un problème connu avec Android P ou quelque chose a-t-il changé?

66voto

Avait un problème similaire et a résolu ce problème en l'ajoutant à mon SQLiteOpenHelper

     @Override
    public void onOpen(SQLiteDatabase db) {
        super.onOpen(db);
        db.disableWriteAheadLogging();
    }
 

Apparemment, Android P définit la chose PRAGMA Log différemment. Toujours aucune idée si cela aura des effets secondaires, mais semble fonctionner!

36voto

aaru Points 329

Mes problèmes avec Android P ont été résolus en ajoutant 'this.close ()' après this.getReadableDatabase () dans la méthode createDataBase () comme ci-dessous.

 private void createDataBase() throws IOException {
    this.getReadableDatabase();
    this.close(); 
    try {           
        copyDataBase();            
    } catch (IOException e) {           
        throw new RuntimeException(e);
    }
}
 

29voto

rmtheis Points 2007

Ce problème semble conduire à un accident beaucoup plus souvent sur Android P que sur les versions précédentes, mais ce n'est pas un bug sur Android P lui-même.

Le problème, c'est que votre ligne où vous l'attribuez à votre String filePath ouvre une connexion à la base de données qui reste ouverte lorsque vous copiez le fichier à partir d'actifs.

Pour résoudre le problème, remplacez la ligne

String filePath = mContext.getDatabasePath(Utils.getDatabaseName()).getAbsolutePath();

avec un code pour obtenir le chemin d'accès au fichier de la valeur et puis fermez la base de données:

MySQLiteOpenHelper helper = new MySQLiteOpenHelper();
SQLiteDatabase database = helper.getReadableDatabase();
String filePath = database.getPath();
database.close();

Et aussi ajouter un à l'intérieur de la classe helper:

class MySQLiteOpenHelper extends SQLiteOpenHelper {

    MySQLiteOpenHelper(Context context, String databaseName) {
        super(context, databaseName, null, 2);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
}

9voto

KGBird Points 509

J'ai rencontré un problème similaire. J'ai été la copie d'une base de données, mais pas à partir d'un actif. Ce que j'ai trouvé est que le problème n'avait rien à voir avec mon fichier de base de données de la copie du code. Ni at-il avoir à faire avec les fichiers d'ouverture à gauche, pas fermé, les bouffées de chaleur ou la synchronisation. Mon code généralement remplace un existant unopen base de données. Ce qui semble être nouveau/positions avec Android Tarte et différents des versions précédentes d'Android, c'est que quand Android Tarte crée une base de données SQLite, il définit journal_mode à WAL (write-ahead logging), par défaut. Je n'ai jamais utilisé WAL mode et de l'SQLite docs disent que journal_mode devrait être SUPPRIMER par défaut. Le problème est que si je remplace le fichier existant, nous allons l'appeler mon.db, le write-ahead log, mon.db-wal, existe toujours et efficacement "remplace" ce qui est dans le nouvellement copié mon.le fichier db. Quand j'ai ouvert ma base de données, le sqlite_master table généralement ne contenait qu'une ligne pour android_metadata. Toutes les tables que je m'attendais à manquaient à l'appel. Ma solution est tout simplement de définir journal_mode retour à SUPPRIMER après l'ouverture de la base de données, en particulier lors de la création d'une nouvelle base de données avec Android Tarte.

PRAGMA journal_mode=DELETE;

Peut-être WAL est mieux et il y a probablement une certaine façon à fermer la base de données de sorte que le write-ahead log ne pas obtenir de la manière, mais je n'ai pas vraiment besoin de WAL et n'ont pas besoin d'elle pour toutes les versions précédentes d'Android.

4voto

yvolk Points 172

Malheureusement, la accepté de répondre juste "arrive à travailler" en très des cas concrets, mais il ne donne pas une constante de travail des conseils pour éviter une telle erreur dans Android 9.

Ici, il est:

  1. Avoir une seule instance de SQLiteOpenHelper classe dans votre application pour accéder à votre base de données.
  2. Si vous avez besoin de réécrire / copier la base de données, fermez la base de données (et de fermer toutes les connexions à la base de données) à l'aide de SQLiteOpenHelper.la méthode close() de cette instance ET de ne pas utiliser cette SQLiteOpenHelper exemple plus.

Après l'appel à close(), non seulement toutes les connexions à la base de données sont fermés, mais les fichiers journaux de base sont vidées à la main .fichier sqlite et supprimés. Si vous avez une base de données.fichier sqlite seulement, prêt à être réécrit ou copié.

  1. Après avoir copié / réécriture etc. créer un nouveau singleton de la SQLiteOpenHelper, qui getWritableDatabase() méthode retourne une nouvelle instance de la base de données SQLite! Et de l'utiliser jusqu'à la prochaine fois vous aurez besoin de votre base de données à copier / réécrit...

Cette réponse m'a aidé à comprendre cela: https://stackoverflow.com/a/35648781/297710

J'ai eu ce problème sur Android 9 dans mon AndStatus application https://github.com/andstatus/andstatus qui dispose d'une assez grande suite de tests automatisés qui reproduits "SQLiteException: no such table" dans Android 9 émulateur avant ce commit: https://github.com/andstatus/andstatus/commit/1e3ca0eee8c9fbb8f6326b72dc4c393143a70538 Donc, si vous êtes vraiment curieux, vous pouvez exécuter Tous les tests avant et après cette engageons à voir une différence.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X