9 Stimmen

Sqlite-Probleme mit dem HTC Desire HD

In letzter Zeit habe ich eine Menge Beschwerden über die HTC Desire-Serie erhalten, die beim Aufrufen von SQL-Anweisungen fehlschlägt. Ich habe Berichte von Anwendern mit Protokollschnappschüssen erhalten, die das Folgende enthalten.

I/Database( 2348): sqlite returned: error code = 8, msg = statement aborts at 1: [pragma journal_mode = WAL;] 
E/Database( 2348): sqlite3_exec to set journal_mode of /data/data/my.app.package/files/localized_db_en_uk-1.sqlite to WAL failed

gefolgt von meiner App, die im Grunde genommen in Flammen aufgeht, weil der Aufruf zum Öffnen der Datenbank zu einem schwerwiegenden Laufzeitfehler führt, der sich darin äußert, dass der Cursor offen gelassen wird. Es sollte nicht ein Cursor an dieser Stelle sein, wie wir versuchen, es zu öffnen.

Dieses Problem tritt nur beim HTC Desire HD und Z auf. Mein Code funktioniert im Wesentlichen wie folgt (ein wenig geändert, um den Problembereich zu isolieren).

SQLiteDatabase db;
String dbName;

public SQLiteDatabase loadDb(Context context) throws IOException{
   //Close any old db handle
   if (db != null && db.isOpen()) {
      db.close();
   } 
  // The name of the database to use from the bundled assets.
  String dbAsset = "/asset_dir/"+dbName+".sqlite";
  InputStream myInput = context.getAssets().open(dbAsset, Context.MODE_PRIVATE);

  // Create a file in the app's file directory since sqlite requires a path
  // Not ideal but we will copy the file out of our bundled assets and open it
  // it in another location.
  FileOutputStream myOutput = context.openFileOutput(dbName, Context.MODE_PRIVATE);

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

  // Close the streams
  myOutput.flush();
  // Guarantee Write!
  myOutput.getFD().sync();
  myOutput.close();
  myInput.close();
  // Not grab the newly written file
  File fileObj = context.getFileStreamPath(dbName);
  // and open the database
  return db = SQLiteDatabase.openDatabase(fileObj.getAbsolutePath(), null, SQLiteDatabase.OPEN_READONLY | SQLiteDatabase.NO_LOCALIZED_COLLATORS);
}

Leider ist dieses Telefon nur im Vereinigten Königreich erhältlich und ich habe keins in meinem Bestand. Ich erhalte nur Berichte dieses Typs von der HTC Desire-Serie. Ich weiß nicht, was sich geändert hat, da dieser Code bisher ohne Probleme funktioniert hat. Gibt es etwas, das ich übersehe?

20voto

CommonsWare Punkte 950864

Kurze Antwort: Versuchen Sie, die SQLiteDatabase.OPEN_READONLY .

Längere Antwort:

Das "WAL" ist das "write-ahead log", eine relativ neue Funktion in SQLite, wie ich es verstehe. In der SQLite-Dokumentation zu WAL heißt es: "Es ist nicht möglich, schreibgeschützte WAL-Datenbanken zu öffnen." Nun, das scheint sich eher auf schreibgeschützte Medien zu beziehen, aber es könnte auch für OPEN_READONLY .

Es würde mich überraschen, wenn dies hilft, da es dies voraussetzt:

  • WAL wird im Standard-Android nicht verwendet
  • HTC aktiviert WAL in diesen beiden Geräten
  • Irgendetwas Besonderes in Ihrer Umgebung (z. B. die Binärdatenbank, die Sie aus den Assets herausschleppen) verursacht dieses Problem, während eine gewöhnliche Nur-Lese-Datenbank noch einwandfrei funktioniert, da ich mir nicht vorstellen kann, dass diese Geräte Kompatibilitätstests mit nicht funktionierender Nur-Lese-Datenbankunterstützung bestanden hätten

Aber ich denke, es ist zumindest einen Versuch wert.

Sie könnten auch in Erwägung ziehen, von der Paketierung der binären Datenbank auf die Paketierung der SQL-Anweisungen zur Erstellung/Befüllung der Datenbank und deren Ausführung umzusteigen. Dies ist zwar langsamer (viel langsamer, wenn Sie keine Transaktionen verwenden), aber weniger anfällig für datenbankdateispezifische Probleme.

-1voto

ctate Punkte 1381

Das grundlegende Problem hier ist, dass Sie davon ausgehen, dass sqlite3-Datenbankdateien zwischen Android-Geräten portabel sind. Das ist nicht der Fall. Das Dateiformat - ja, die Verwendung von SQLite als Datenbank-Engine überhaupt - ist no Teil der API. HTC könnte ein Android-Telefon herstellen, das Postgres anstelle von Sqlite3 verwendet, und es könnte immer noch offiziell kompatibel sein.

Ja, es ist ein üblicher Trick, den Datenbankinhalt vorzubefüllen, indem man eine sqlite3 .db-Datei in den Assets der Anwendung bündelt und sie dann nach der Installation unverändert verwendet. Es ist jedoch nicht garantiert, dass dies funktioniert, nicht einmal zwischen Geräten, auf denen die gleiche Version der Android-Plattform läuft. Das Einzige, worauf Sie sich verlassen können, ist, dass eine .db-Datei, die auf einem bestimmten Gerät mit einer bestimmten Android-Version erstellt wurde, auch auf demselben Gerät weiter verwendet werden kann. physisch Gerät mit demselben oder einem neueren Android-Build desselben Systemherstellers.

(Nicht einmal Geräte desselben Modells vom selben Hersteller? Nein: Es gibt keine Garantie dafür, dass zwei Geräte mit demselben Branding tatsächlich denselben Systemaufbau unter der Haube haben oder zu verschiedenen Zeitpunkten während ihrer Produktlebensdauer identische Hardware verwenden).

Die einzige Möglichkeit, dies portabel zu machen, besteht darin, nicht die rohe Datenbankdatei selbst einzubetten, sondern eine generische, analysierbare Darstellung, die in die öffentliche API eingespielt werden kann, um die geräteangepasste Datenbankdatei zu erstellen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X