Android无法将数据库复制到资源文件夹

时间:2016-06-23 20:45:08

标签: android sqlite

我有一个手动创建的数据库(.sqlite3)。我已尝试根据此 question/answer

将其合并到我的应用中

我不确定原因,但它一直让我误解“ErrorCopyingdatabase”错误。我正在使用模拟器进行测试。

这是我将数据库合并到应用程序中的代码。我做了2节课。

<li id="li">fdsf</li>

和...

public class DataBaseHelper extends SQLiteOpenHelper {
    private static String TAG = "DataBaseHelper"; // Tag just for the LogCat window
    //destination path (location) of our database on device
    private static String DB_PATH = "";
    private static String DB_NAME ="Characters";// Database name
    private SQLiteDatabase mDataBase;
    private final Context mContext;

    public DataBaseHelper(Context context)
    {
        super(context, DB_NAME, null, 1); // 1? Its database Version
        if(android.os.Build.VERSION.SDK_INT >= 17) {
            DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
        }
        else {
            DB_PATH = "/data/data/" + context.getPackageName() + "/databases/";
        }
        this.mContext = context;
    }

    public void createDataBase() throws IOException {
        //If the database does not exist, copy it from the assets.

        boolean mDataBaseExist = checkDataBase();
        if(!mDataBaseExist)  {
            this.getReadableDatabase();
            this.close();
            try {
                //Copy the database from assests
                copyDataBase();
                Log.e(TAG, "createDatabase database created");
            }
            catch (IOException mIOException) {
                throw new Error("ErrorCopyingDataBase");
            }
        }
    }

    //Check that the database exists here: /data/data/your package/databases/Da Name
    private boolean checkDataBase() {
        File dbFile = new File(DB_PATH + DB_NAME);
        //Log.v("dbFile", dbFile + "   "+ dbFile.exists());
        return dbFile.exists();
    }

    //Copy the database from assets
    private void copyDataBase() throws IOException {
        InputStream mInput = mContext.getAssets().open(DB_NAME);
        String outFileName = DB_PATH + DB_NAME;
        OutputStream mOutput = new FileOutputStream(outFileName);
        byte[] mBuffer = new byte[1024];
        int mLength;
        while ((mLength = mInput.read(mBuffer))>0) {
            mOutput.write(mBuffer, 0, mLength);
        }
        mOutput.flush();
        mOutput.close();
        mInput.close();
    }

    //Open the database, so we can query it
    public boolean openDataBase() throws SQLException {
        String mPath = DB_PATH + DB_NAME;
        //Log.v("mPath", mPath);
        mDataBase = SQLiteDatabase.openDatabase(mPath, null, SQLiteDatabase.CREATE_IF_NECESSARY);
        //mDataBase = SQLiteDatabase.openDatabase(mPath, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS);
        return mDataBase != null;
    }

    @Override
    public synchronized void close() {
        if(mDataBase != null)
            mDataBase.close();
        super.close();
    }
}

我尝试修改代码以满足我的需求...... 正如我所说,它似乎无法复制数据库,并不断向我发送ErrorCopyingDatabase错误(第一个代码片段)。

因此,在后续尝试中,首先没有数据库可以进行查询。

顺便说一句,我从片段上的按钮激活所有内容。

public class TestAdapter {
    protected static final String TAG = "DataAdapter";

    private final Context mContext;
    private SQLiteDatabase mDb;
    private DataBaseHelper mDbHelper;

    public TestAdapter(Context context){
        this.mContext = context;
        mDbHelper = new DataBaseHelper(mContext);
    }

    public TestAdapter createDatabase() throws SQLException{
        try {
            mDbHelper.createDataBase();
        }
        catch (IOException mIOException)
        {
            Log.e(TAG, mIOException.toString() + "  UnableToCreateDatabase");
            throw new Error("UnableToCreateDatabase");
        }
        return this;
    }

    public TestAdapter open() throws SQLException{
        try{
            mDbHelper.openDataBase();
            mDbHelper.close();
            mDb = mDbHelper.getReadableDatabase();
        }
        catch (SQLException mSQLException){
            Log.e(TAG, "open >>"+ mSQLException.toString());
            throw mSQLException;
        }
        return this;
    }

    public void close(){
        mDbHelper.close();
    }

    public ArrayList getTestData(int numberId){
        try {
            ArrayList<String> details = new ArrayList<>();
            String name = "";
            String summary = "";
            String trivia = "";
            String abilities = "";
            Cursor mcur = mDb.rawQuery("SELECT Name FROM CharactersInfo WHERE _id=?", new String[]{numberId + ""});

            if (mcur.getCount() > 0) {

                mcur.moveToFirst();
                name = mcur.getString(mcur.getColumnIndex("Name"));
                summary = mcur.getString(mcur.getColumnIndex("Summary"));
                trivia = mcur.getString(mcur.getColumnIndex("Trivia"));
                abilities = mcur.getString(mcur.getColumnIndex("Abilities"));


                details.add(name);
                details.add(summary);
                details.add(trivia);
                details.add(abilities);

            }
            return details;
        } catch (SQLException mSQLException) {
            Log.e(TAG, "getTestData >>"+ mSQLException.toString());
            throw mSQLException;
        }
    }
}

我已经对它进行了一些调查,我非常感谢你的帮助。

修改: 这是logcat(只有致命的例外部分),对于迟到的条目感到抱歉:

TestAdapter mDbHelper = new TestAdapter(getActivity());
mDbHelper.createDatabase();
mDbHelper.open();
ArrayList cursor = mDbHelper.getTestData(indentifier);
TextView textView = (TextView) view.findViewById(R.id.character_trivia);
String string = "" + cursor;
textView.setText(string);

mDbHelper.close();

2 个答案:

答案 0 :(得分:1)

要将数据库与预定义数据一起使用,最好使用AndroidSqliteAssetHelper

以下是其中一部分内容:

  

用于管理数据库创建和版本的Android帮助程序类   管理使用应用程序的原始资产文件。

     

此类为开发人员提供了一种发布Android的简单方法   具有现有SQLite数据库的应用程序(可以预先填充   数据)并管理其初始创建和所需的任何升级   随后的版本发布。

     

它是作为SQLiteOpenHelper的扩展实现的,提供了一个   ContentProvider实现推迟开放的有效方法   升级数据库直到第一次使用。

     

而不是实现onCreate()和onUpgrade()方法   执行一堆SQL语句,开发人员只需包含   在项目的资产目录中适当命名的文件资产。   这些将包括用于创建的初始SQLite数据库文件   可选地任何SQL升级脚本。

答案 1 :(得分:0)

我建议稍微更改copyDataBase()。另外,我删除了throws clasure。这样,logcat将打印出更好的信息:

private void copyDataBase() {
    Log.v(TAG, "copyDataBase() - start");
    try {
        InputStream myInput = mContext.getAssets().open(DATABASE_NAME);

        // I think this line should solve your problem... Maybe, you are not setting the output file properly... Try like below:
        OutputStream myOutput = new FileOutputStream(mContext.getDatabasePath(DATABASE_NAME));

        byte[] buffer = new byte[1024];
        int length;
        while ((length = myInput.read(buffer))>0){
            myOutput.write(buffer, 0, length);
        }

        myOutput.flush();
        myOutput.close();
        myInput.close();

    } catch (Exception e) {
        Log.e(TAG, "copyDataBase(): " + e);

        StackTraceElement trace[] = e.getStackTrace();
        for(StackTraceElement element : trace) {
            Log.e(TAG, element.toString());

        }
    }
    Log.v(TAG, "copyDataBase() - end");
}

然后,您可以删除此内容:

if(android.os.Build.VERSION.SDK_INT >= 17) {
    DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
}
else {
    DB_PATH = "/data/data/" + context.getPackageName() + "/databases/";
}

并改变这一点:

if(!mDataBaseExist)  {
    this.getReadableDatabase();
    this.close();
    try {
        //Copy the database from assests
        copyDataBase();
        Log.e(TAG, "createDatabase database created");
    }
    catch (IOException mIOException) {
        throw new Error("ErrorCopyingDataBase");
    }
}

对此:

if(!mDataBaseExist)  {
    this.getReadableDatabase();
    this.close();
    copyDataBase();
    Log.e(TAG, "createDatabase database created");
}