无法在android studio中打开SQLite DB

时间:2017-08-30 04:51:26

标签: java android database sqlite

我正在尝试将数据库与APK捆绑在一起。我在我的设备上使用Android Studio 2.2.3和API 24(物理和模拟器)。

基本上我想要做的是,使用我已创建的数据库(使用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上寻找一些解决方案,但他们并没有为我工作。有人说DB大小可能会有问题。我的数据库是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类注释所述。

1 个答案:

答案 0 :(得分: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.

}

非常感谢。