android - 在 fragment 中复制数据库然后在 Android Studio 中使用它

标签 android sqlite

来 self 的数据库助手类的代码。

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)

最佳答案

您的代码有一些问题。

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

其次,每次应用程序运行时都会尝试复制数据库,因为没有检查数据库是否实际存在。

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

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

数据库助手.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 方法,如果 **databases* 文件夹不存在,它会创建它,这是您遇到的问题的修复。

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

  • 请注意,如果需要,仅实例化 DatabaseHelper 将执行 Assets 文件夹中数据库文件的复制,因此您在 fragment 中的代码可以是

:-

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;
    }
}

关于android - 在 fragment 中复制数据库然后在 Android Studio 中使用它,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55213046/

相关文章:

android - 为完整的 android 应用程序添加自定义字体

java - 从 VBA 代码启动 jar 文件

android - 如何从 Android App Bundle 中排除 ABI?

android - 写入文件后PhoneGap Email Attach

android - 当应用程序被杀死时,互联网广播接收器不工作

android - 如果应用程序已打开,则深层链接不会正确重定向

java - 访问服务器计算机上的数据库的 Android 应用程序

sql - 获取包含字母过滤的单词列表

java - 如果我在 java 中的 sql 命令中写 "INTEGER"或 "int"有关系吗?[sqlite]