2017-08-30 229 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. 

} 

非常感谢你。