2017-08-30 224 views
0

我正試圖將數據庫與APK捆綁在一起。我在我的設備上使用Android Studio 2.2.3和API 24(物理和模擬器)。無法在android studio中打開SQLite數據庫

基本上我想要做的是,使用我已經創建的數據庫(使用python創建)並從該數據庫爲應用程序生成動態HTML。我讀過,我們不能直接使用這個數據庫,我們必須將其複製到app/APK。

我得到的調試日誌以下錯誤:

E/SQLiteLog: (14) cannot open file at line 32456 of [bda77dda96] 
E/SQLiteLog: (14) os_unix.c:32456: (2) open(/data/data/com.sunnah.sunnahapp/databases/test.sqlite) - 
E/SQLiteDatabase: Failed to open database '/data/data/com.sunnah.sunnahapp/databases/test.sqlite'. 
        android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database 
         at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method) 
         at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:209) 
         at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193) 
         at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463) 
         at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185) 
         at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177) 
         at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:808) 
         at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:793) 
         at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:696) 
         at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:671) 
         at com.sunnah.sunnahapp.DatabaseHelper1.openDataBase(DatabaseHelper1.java:133) 
         at com.sunnah.sunnahapp.DatabaseHelper1.<init>(DatabaseHelper1.java:38) 
         at com.sunnah.sunnahapp.MainActivity.onCreate(MainActivity.java:56) 
         at android.app.Activity.performCreate(Activity.java:6736) 
         at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119) 
         at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2636) 
         at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2744) 
         at android.app.ActivityThread.-wrap12(ActivityThread.java) 
         at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1493) 
         at android.os.Handler.dispatchMessage(Handler.java:102) 
         at android.os.Looper.loop(Looper.java:154) 
         at android.app.ActivityThread.main(ActivityThread.java:6195) 
         at java.lang.reflect.Method.invoke(Native Method) 
         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:874) 
         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:764) 
D/AndroidRuntime: Shutting down VM 
E/AndroidRuntime: FATAL EXCEPTION: main 
        Process: com.sunnah.sunnahapp, PID: 14478 
        java.lang.RuntimeException: Unable to start activity ComponentInfo{com.sunnah.sunnahapp/com.sunnah.sunnahapp.MainActivity}: android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database 
         at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2683) 
         at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2744) 
         at android.app.ActivityThread.-wrap12(ActivityThread.java) 
         at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1493) 
         at android.os.Handler.dispatchMessage(Handler.java:102) 
         at android.os.Looper.loop(Looper.java:154) 
         at android.app.ActivityThread.main(ActivityThread.java:6195) 
         at java.lang.reflect.Method.invoke(Native Method) 
         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:874) 
         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:764) 
        Caused by: android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database 
         at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method) 
         at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:209) 
         at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193) 
         at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463) 
         at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185) 
         at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177) 
         at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:808) 
         at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:793) 
         at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:696) 
         at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:671) 
         at com.sunnah.sunnahapp.DatabaseHelper1.openDataBase(DatabaseHelper1.java:133) 
         at com.sunnah.sunnahapp.DatabaseHelper1.<init>(DatabaseHelper1.java:38) 
         at com.sunnah.sunnahapp.MainActivity.onCreate(MainActivity.java:56) 
         at android.app.Activity.performCreate(Activity.java:6736) 
         at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119) 
         at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2636) 
         at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2744)  
         at android.app.ActivityThread.-wrap12(ActivityThread.java)  
         at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1493)  
         at android.os.Handler.dispatchMessage(Handler.java:102)  
         at android.os.Looper.loop(Looper.java:154)  
         at android.app.ActivityThread.main(ActivityThread.java:6195)  
         at java.lang.reflect.Method.invoke(Native Method)  
         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:874)  
         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:764)  
E/MQSEventManagerDelegate: failed to get MQSService. 
I/Process: Sending signal. PID: 14478 SIG: 9 
Disconnected from the target VM, address: 'localhost:8602', transport: 'socket' 

我試圖尋找對SO一些解決方案,但他們並沒有爲我工作。有人說數據庫大小可能是問題。我的數據庫是15MB,然後我創建了一個test.sqlite數據庫只有一個表和行。其他人表示,這是因爲SD卡上的權限。我不使用SD卡。它仍然沒有工作。錯誤保持不變。

我嘗試將我的test.sqlite數據庫放在資產和資產/數據庫文件夾中,但它仍然給出相同的錯誤。

下面是我的我的代碼:

DatabaseHelper1.java

package com.sunnah.sunnahapp; 

import android.content.Context; 
import android.content.ContextWrapper; 
import android.database.sqlite.SQLiteException; 
import android.database.SQLException; 
import android.database.sqlite.SQLiteDatabase; 
import android.database.sqlite.SQLiteOpenHelper; 

import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import android.util.Log; 

public class DatabaseHelper1 extends SQLiteOpenHelper { 

    //The Android's default system path of your application database. 
    private static String DB_PATH; //"/data/data/YOUR_PACKAGE/databases/"; 
    private static String DB_NAME = "test.sqlite"; 

    private SQLiteDatabase myDataBase; 
    private final Context myContext; 

    /** 
    * Constructor 
    * Takes and keeps a reference of the passed context in order to access to the application assets and resources. 
    * @param context 
    */ 
    public DatabaseHelper1(Context context) { 

     super(context, DB_NAME, null, 1); 
     this.myContext = context; 

     //Write a full path to the databases of your application 
     String packageName = context.getPackageName(); 
     DB_PATH = String.format("/data/data/%s/databases/", packageName); 
     openDataBase(); 

    } 

    /** 
    * Creates a empty database on the system and rewrites it with your own database. 
    * */ 
    public void createDataBase() throws IOException { 
     Log.d("Create DB Func", "My Message"); 

     boolean dbExist = checkDataBase(); 
     Log.d("Past DB Create", "My Message 1"); 

     if(dbExist){ 
      Log.e(this.getClass().toString(), "Copying error"); 
     }else{ 

      //By calling this method and empty database will be created into the default system path 
      //of your application so we are gonna be able to overwrite that database with our database. 
      this.getReadableDatabase(); 
      Log.d("getDatabase Func", "My Messag2e"); 

      try { 
       Log.d("b4 Copy DB Func", "My Messag2e"); 
       copyDataBase(); 
       Log.d("after copy dB Func", "My Messag2e"); 
      } catch (IOException e) { 

       throw new Error("Error copying database"); 
      } 
     } 

    } 

    /** 
    * Check if the database already exist to avoid re-copying the file each time you open the application. 
    * @return true if it exists, false if it doesn't 
    */ 
    private boolean checkDataBase(){ 

     SQLiteDatabase checkDB = null; 

     try{ 
      String myPath = DB_PATH + DB_NAME; 
      checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY); 

     } catch(SQLiteException e){ 
      Log.e(this.getClass().toString(), "Error while checking db"); 
      //database does't exist yet. 

     } 

     if(checkDB != null){ 

      checkDB.close(); 

     } 

     return checkDB != null ? true : false; 
    } 

    /** 
    * Copies your database from your local assets-folder to the just created empty database in the 
    * system folder, from where it can be accessed and handled. 
    * This is done by transfering bytestream. 
    * */ 
    private void copyDataBase() throws IOException{ 

     //Open your local db as the input stream 
     InputStream myInput = myContext.getAssets().open(DB_NAME); 

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

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

     //transfer bytes from the inputfile to the outputfile 
     byte[] buffer = new byte[1024]; 
     int length; 
     while ((length = myInput.read(buffer))>0){ 
      myOutput.write(buffer, 0, length); 
     } 

     //Close the streams 
     myOutput.flush(); 
     myOutput.close(); 
     myInput.close(); 

    } 

    public void openDataBase() throws SQLException { 

     //Open the database 
     String myPath = DB_PATH + DB_NAME; 
     myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY); 

    } 

    @Override 
    public synchronized void close() { 

     if(myDataBase != null) 
      myDataBase.close(); 

     super.close(); 

    } 

    @Override 
    public void onCreate(SQLiteDatabase db) { 

    } 

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

    } 

    // Add your public helper methods to access and get content from the database. 
    // You could return cursors by doing "return myDataBase.query(....)" so it'd be easy 
    // to you to create adapters for your views. 

} 

MainActivity.java

package com.sunnah.sunnahapp; 

import android.graphics.Bitmap; 
import android.support.v7.app.AppCompatActivity; 
import android.os.Bundle; 
import android.webkit.WebView; 
import android.webkit.WebViewClient; 


//DB PART 
import com.sunnah.sunnahapp.R; 
import com.sunnah.sunnahapp.R.layout; 
import com.sunnah.sunnahapp.DatabaseHelper1; 

import android.app.Activity; 
import android.app.ListActivity; 
import android.database.Cursor; 
import android.database.sqlite.SQLiteDatabase; 
import android.os.Bundle; 
import android.view.View; 
import android.widget.AdapterView; 
import android.widget.AdapterView.OnItemClickListener; 
import android.widget.ArrayAdapter; 
import android.widget.ListView; 
import android.widget.TextView; 
import android.widget.Toast; 

import java.io.IOException; 

//DB PART END 





public class MainActivity extends AppCompatActivity { 

    private WebView webView; 
    private SQLiteDatabase database; 
    //private static final String DB_NAME = "bukhari.sqlite"; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 


     setContentView(R.layout.activity_main); 
     webView = (WebView) findViewById(R.id.webView); 
     webView.setWebViewClient(new MainActivity.myWebClient()); 


     // Database Part START 
     //Our key helper 

     DatabaseHelper1 dbOpenHelper; //= new DatabaseHelper1(); 
     dbOpenHelper = new DatabaseHelper1(this); 

     try { 
      dbOpenHelper.createDataBase(); 
     } catch (IOException ioe) { 
      throw new Error("Unable to create database"); 

     } 

     //database = dbOpenHelper.openDataBase(); 
     //That’s it, the database is open! 

     //Database Part END 

     webView.getSettings().setJavaScriptEnabled(true); 
     webView.loadUrl("file:///android_asset/www/index.html"); 
    } 


    public class myWebClient extends WebViewClient 
    { 
     @Override 
     public void onPageStarted(WebView view, String url, Bitmap favicon) { 
      super.onPageStarted(view, url, favicon); 
     } 

     @Override 
     public boolean shouldOverrideUrlLoading(WebView view, String url) { 

      view.loadUrl(url); 
      return true; 
     } 
    } 

    @Override 
    // This method is used to detect back button 
    public void onBackPressed() { 
     if(webView.canGoBack()) { 
      webView.goBack(); 
     } else { 
      // Let the system handle the back button 
      super.onBackPressed(); 
     } 
    } 
} 

能否請您指導我在這裏。我嘗試改變實際存在的路徑(即目錄結構)。 我錯過了什麼? 如何在給定路徑中不存在的情況下創建一個空的數據庫。我認爲它會在這種情況下創建,如DatabaseHelper1類的註釋所述。

+0

添加'<使用權限android:name =「android.permission.WRITE_EXTERNAL_STORAGE」/>' –

+0

'/ data/data/sunnahapp/databases /'。然後卸載舊的應用程序並再次運行 –

+0

@IntelliJAmiya,錯誤。 謝謝你的迴應。 –

回答

0

好的。看起來checkDatabase()在數據庫不存在時引發異常(第一個應用程序啓動/安裝)。它不應該拋出異常,因爲它會調用copyDatabase()。

所以我註釋掉throw new Error("database does't exist yet.");

我也做了一些其他的變化,所以我現在DatabaseHelper1.java洛斯這個樣子,如果它可以幫助別人:

package com.sunnah.sunnahapp; 

import android.content.Context; 
import android.content.ContextWrapper; 
import android.database.sqlite.SQLiteException; 
import android.database.SQLException; 
import android.database.sqlite.SQLiteDatabase; 
import android.database.sqlite.SQLiteOpenHelper; 

import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.io.File; 
import android.util.Log; 

public class DatabaseHelper1 extends SQLiteOpenHelper { 

    //The Android's default system path of your application database. 
    private static String DB_PATH = "data/data/com.sunnah.sunnahapp/databases/"; //"/data/data/YOUR_PACKAGE/databases/"; 
    private static String DB_NAME = "test.sqlite"; 

    private SQLiteDatabase myDataBase; 
    private final Context myContext; 

    /** 
    * Constructor 
    * Takes and keeps a reference of the passed context in order to access to the application assets and resources. 
    * @param context 
    */ 
    public DatabaseHelper1(Context context) { 

     super(context, DB_NAME, null, 1); 
     this.myContext = context; 

     //Write a full path to the databases of your application 
     //String packageName = context.getPackageName(); 
     //DB_PATH = String.format("/data/data/%s/databases/", packageName); 
     //openDataBase(); 

    } 

    /** 
    * Creates a empty database on the system and rewrites it with your own database. 
    * */ 
    public void createDataBase() throws IOException { 

     boolean dbExist; 
     try { 

      dbExist = checkDataBase(); 


     } catch (SQLiteException e) { 

      e.printStackTrace(); 
      throw new Error("database dose not exist"); 

     } 


     if(dbExist){ 
      //do nothing - database already exist 
     }else{ 
      try { 

       copyDataBase(); 


      } catch (IOException e) { 

       e.printStackTrace(); 
       throw new Error("Error copying database"); 

      } 
      //By calling this method and empty database will be created into the default system path 
      //of your application so we are gonna be able to overwrite that database with our database. 
      this.getReadableDatabase(); 
     } 

    } 

    /** 
    * Check if the database already exist to avoid re-copying the file each time you open the application. 
    * @return true if it exists, false if it doesn't 
    */ 
    private boolean checkDataBase(){ 

     SQLiteDatabase checkDB = null; 

     try{ 
      String myPath = DB_PATH + DB_NAME; 
      checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY); 

     } catch(SQLiteException e){ 
      //Log.e(this.getClass().toString(), "Error while checking db"); 
      //database does't exist yet. 
      //throw new Error("database does't exist yet."); 

     } 

     if(checkDB != null){ 

      checkDB.close(); 

     } 

     return checkDB != null ? true : false; 
    } 

    /** 
    * Copies your database from your local assets-folder to the just created empty database in the 
    * system folder, from where it can be accessed and handled. 
    * This is done by transfering bytestream. 
    * */ 
    private void copyDataBase() throws IOException{ 

     //Open your local db as the input stream 
     InputStream myInput = myContext.getAssets().open(DB_NAME); 

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

     File databaseFile = new File(DB_PATH); 
     // check if databases folder exists, if not create one and its subfolders 
     if (!databaseFile.exists()){ 
      databaseFile.mkdir(); 
     } 
     //Open the empty db as the output stream 
     OutputStream myOutput = new FileOutputStream(outFileName); 

     //transfer bytes from the inputfile to the outputfile 
     byte[] buffer = new byte[1024]; 
     int length; 
     while ((length = myInput.read(buffer))>0){ 
      myOutput.write(buffer, 0, length); 
     } 

     //Close the streams 
     myOutput.flush(); 
     myOutput.close(); 
     myInput.close(); 

    } 

    public void openDataBase() throws SQLException { 

     //Open the database 
     String myPath = DB_PATH + DB_NAME; 
     myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY); 

    } 

    @Override 
    public synchronized void close() { 

     if(myDataBase != null) 
      myDataBase.close(); 

     super.close(); 

    } 

    @Override 
    public void onCreate(SQLiteDatabase db) { 

    } 

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

    } 

    // Add your public helper methods to access and get content from the database. 
    // You could return cursors by doing "return myDataBase.query(....)" so it'd be easy 
    // to you to create adapters for your views. 

} 

非常感謝你。