复制片段中的数据库,然后在Android Studio中使用它

时间:2019-03-17 23:42:32

标签: android sqlite

我的databasehelper类中的代码。

package com.app.testapp;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class DatabaseHelper extends SQLiteOpenHelper {

    private String DB_PATH;
    private static String DB_NAME = "test";
    private final Context context;

    public DatabaseHelper(Context context) {
        super(context, DB_NAME, null, 1);
        this.context = context;
        this.DB_PATH = "/data/data/" + context.getPackageName() + "/" + "databases/";
        Log.e("Database Path:", DB_PATH);
    }

    public void copyDatabase() throws IOException {
        InputStream myInput = context.getAssets().open(DB_NAME);
        String outString = DB_PATH + DB_NAME;
        OutputStream myOutput = new FileOutputStream(outString);
        byte[] buffer = new byte[10];
        int length;
        while ((length = myInput.read(buffer)) > 0) {
            myOutput.write(buffer, 0, length);
        }
        myOutput.flush();
        myOutput.close();
        myInput.close();
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
    }

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

我的viewFragment类中的代码

package com.app.testapp;

import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import java.io.IOException;

public class ViewFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment, container, false);
        DatabaseHelper db = new DatabaseHelper(getActivity());
        initDatabase(db);
        return view;
    }

    private void initDatabase(DatabaseHelper db) {
        try {
            db.copyDatabase();
        } catch (IOException ioe) {
            throw new Error("Error creating database");
        }
    }

}

MainActivity类中的代码。

package com.app.testapp;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getSupportFragmentManager().beginTransaction().replace(R.id.frag_container, new ViewFragment()).commit();
    }
}

我试图复制一个已经预制的数据库,然后创建一个新的本地数据库,我可以在程序中访问和使用它。我以前见过类似于此工作的代码,也有类似于此工作与按钮的代码,但是我无法使它工作。

我的错误如下

2019-03-17 23:32:46.645 13197-13197/com.app.testapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.app.testapp, PID: 13197
java.lang.Error: Error creating database
    at com.app.testapp.ViewFragment.initDatabase(ViewFragment.java:28)
    at com.app.testapp.ViewFragment.onCreateView(ViewFragment.java:20)
    at android.support.v4.app.Fragment.performCreateView(Fragment.java:2439)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1460)
    at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
    at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:802)
    at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2625)
    at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2411)
    at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366)
    at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2273)
    at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3273)
    at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:3229)
    at android.support.v4.app.FragmentController.dispatchActivityCreated(FragmentController.java:201)
    at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:620)
    at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:178)
    at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1248)
    at android.app.Activity.performStart(Activity.java:6679)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2609)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
    at android.app.ActivityThread.-wrap12(ActivityThread.java)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6077)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)

其他日志:-

    E/Database Path:: /data/data/com.app.testapp/databases/
W/System.err: java.io.FileNotFoundException: /data/data/com.app.testapp/databases/test (No such file or directory)
W/System.err:     at java.io.FileOutputStream.open(Native Method)
        at java.io.FileOutputStream.<init>(FileOutputStream.java:221)
        at java.io.FileOutputStream.<init>(FileOutputStream.java:108)
        at com.app.testapp.DatabaseHelper.copyDatabase(DatabaseHelper.java:29)
        at com.app.testapp.ViewFragment.initDatabase(ViewFragment.java:26)
        at com.app.testapp.ViewFragment.onCreateView(ViewFragment.java:20)
        at android.support.v4.app.Fragment.performCreateView(Fragment.java:2439)
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1460)
        at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
        at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:802)
        at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2625)
        at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2411)
        at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366)
        at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2273)
        at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3273)
        at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:3229)
        at android.support.v4.app.FragmentController.dispatchActivityCreated(FragmentController.java:201)
W/System.err:     at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:620)
        at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:178)
        at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1248)
        at android.app.Activity.performStart(Activity.java:6679)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2609)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
        at android.app.ActivityThread.-wrap12(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6077)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)

1 个答案:

答案 0 :(得分:1)

您的代码有一些问题。

首先,我认为当数据库文件所在的 databases 目录不存在,因此复制将失败时,它不适合将App作为新App安装。输出文件无法打开。

第二次,每次运行该应用程序时都会尝试复制数据库,因为不会检查数据库是否确实存在。

虽然不是真正的问题,但是如果使用Context的 getDatabasePath 方法,则无需对路径进行硬编码,这可能是不正确的。它还应该对代码进行过时的验证。

我相信以下DatabaseHelper可以解决您的问题(除非问题是文件 test 已复制到 assets 文件夹中(并且是有效的数据库) ):-

DatabaseHelper.java

public class DatabaseHelper extends SQLiteOpenHelper {

    private String DB_PATH;
    private static String DB_NAME = "test";
    private final Context context;

    public DatabaseHelper(Context context) {
        super(context, DB_NAME, null, 1);
        this.context = context;
        this.DB_PATH = context.getDatabasePath(DB_NAME).getPath(); //<<<<<<<<<< REPLACES following line
        //this.DB_PATH = "/data/data/" + context.getPackageName() + "/" + "databases/";
        Log.e("Database Path:", DB_PATH);
        if (!checkDatabase()) {
            try {
                copyDatabase();
            } catch (IOException ioe) {
                ioe.printStackTrace();
                throw  new RuntimeException("Error creating Database - see stack-trace above.");
            }
        }
    }

    private boolean checkDatabase() {
        File dbpath = new File(DB_PATH);
        if (dbpath.exists()) {
            return true;
        } else {
            if (!dbpath.getParentFile().exists()) { 
                dbpath.getParentFile().mkdirs();
            }
        }
        return false;
    }

    private void copyDatabase() throws IOException { // MADE PRIVATE AS USED INTERNALLY
        InputStream myInput = context.getAssets().open(DB_NAME);
        String outString = DB_PATH;
        OutputStream myOutput = new FileOutputStream(outString);
        byte[] buffer = new byte[10];
        int length;
        while ((length = myInput.read(buffer)) > 0) {
            myOutput.write(buffer, 0, length);
        }
        myOutput.flush();
        myOutput.close();
        myInput.close();
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
}
  • 基本上,添加了 checkDatabase 方法(如果不存在)将创建** database *文件夹,这是您遇到的问题的解决方法。

在进行复制之前调用 checkDatabase ,并且仅在数据库不存在时才进行复制,可以解决在解决第一个问题之后遇到的第二个问题。

  • 请注意,只需实例化DatabaseHelper即可从资产文件夹执行数据库文件的复制,因此,您在片段中的代码可能是

:-

public class ViewFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment, container, false);
        DatabaseHelper db = new DatabaseHelper(getActivity());
        return view;
    }
}