Sqlite数据库在Samsung Android Oreo 8.0设备中无法正常运行

时间:2018-08-16 06:16:33

标签: android sqlite samsung-mobile android-8.0-oreo

我已经创建了一个仅执行一些数据库读取操作的应用程序(从db中获取记录并执行一些公式并显示结果)

该应用程序在通过 Lenovo(5.1.1),Moto(5.1、6.0、7.1.1),OnePlus(8.1),Mi A1(8.0.0),Micromax(5.0)测试的所有设备上均能正常运行),三星(7.1)

但三星设备包含(8.0),但无法正常工作 设备是三星银河J8(SM-J810G),三星银河S7(SM-G930W8),三星银河S9(SM-G960U)。

下面是我使用的代码。

DBQuery.java

package com.test.dbhelper;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;

import com.test.common.DBConstants;

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

public class DBAdapter extends SQLiteOpenHelper implements DBConstants {
private static String DB_PATH = "";

private SQLiteDatabase mDB;

private static int DB_VERSION = 1;
private Context appContext;

public DBAdapter(Context context) {
    super(context.getApplicationContext(), DB_NAME, null, DB_VERSION);
    DB_PATH = "/data/data/" + context.getPackageName() + "/databases/";
    appContext = context;
    createDataBase();
}

@Override
public void onCreate(SQLiteDatabase db) {
    System.out.println("DB Helper On Create....");
    this.mDB = db;
    createDataBase();
}

public void createDataBase() {
    SQLiteDatabase db_Read = null;
    try {
        boolean dbExist = checkDataBase();
        if (dbExist) {
        } else {
            db_Read = this.getReadableDatabase();
            db_Read.close();
            try {
                copyDataBase();
            } catch (IOException e) {
                throw new Error("Error copying database");
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private boolean checkDataBase() {

    try {
        String myPath = DB_PATH + DB_NAME;
        mDB = SQLiteDatabase.openDatabase(myPath, null,
                SQLiteDatabase.OPEN_READONLY);
    } catch (SQLiteException e) {
    }
    if (mDB != null) {
        mDB.close();
    }
    return mDB != null ? true : false;
}

private void copyDataBase() throws IOException {

    InputStream myInput = appContext.getAssets().open(DB_NAME);
    String outFileName = DB_PATH + DB_NAME;
    OutputStream myOutput = new FileOutputStream(outFileName);
    byte[] buffer = new byte[1024];
    int length;

    while ((length = myInput.read(buffer)) > 0) {
        myOutput.write(buffer, 0, length);
    }

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

public void openDataBase() {
    try {
        String myPath = DB_PATH + DB_NAME;
        mDB = SQLiteDatabase.openDatabase(myPath, null,
                SQLiteDatabase.OPEN_READONLY);
    } catch (Exception e) {
        System.out.println("Open Database failed...");
        e.printStackTrace();
    }
}

public DBAdapter open() throws SQLException {
    mDB = getWritableDatabase();
    return this;
}

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

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

}

public int insertData(String table_name, ContentValues initialValues) {
    int record = (int) mDB.insert(table_name, null, initialValues);
    return record;
}

public int deleteData(String table_name, String whereClause) {
    return (int) mDB.delete(table_name, whereClause, null);
}

public int updateData(String table_name, ContentValues initialValues,
                      String whereClause) {
    return mDB.update(table_name, initialValues, whereClause, null);
}

public Cursor executeRawQuery(String query) {
    Cursor c = null;
    c = mDB.rawQuery(query, null);

    return c;
}

}

DBConstants.java

package com.test.common

interface DBConstants {
  companion object {
    const val DB_NAME = "test.db3"
    const val TAB_WELL_RITE = "well_rite"
    const val TAB_WELL_RITE_TANK_VOLUME_IN_GALLON = "tank_volume_in_gallon"
    const val TAB_WELL_RITE_MODEL_WELL_RITE = "model_well_rite"
    const val TAB_WELL_RITE_MODEL_CHALLANGER = "model_challanger"
    const val TAB_WELL_RITE_MODEL_FLEX_LITE = "model_flex_lite"
    const val TAB_WELL_RITE_TANK_VOLUME_IN_LITRE = "tank_volume_in_litre"
  }
}

DBQuery.java

package com.test.dbhelper;

import android.database.Cursor;

import com.test.activity.TestApp;
import com.test.common.Constants;
import com.test.common.DBConstants;
import com.test.common.LogUtils;

import java.util.HashMap;

public class DBQuery implements DBConstants, Constants {

public static String TAG = "DBQuery";

public static HashMap<String, String> getWellRiteModels(String tableName, String field, double value) {

    HashMap<String, String> dataMap = new HashMap<>();

    String query = "SELECT * " + " FROM " + tableName
            + " WHERE " + field + " >= '" + value + "' order by " + field + " LIMIT 1";

    Cursor cursor = TestApp.dbAdapter.executeRawQuery(query);

    if (cursor.getCount() > 0) {
        if (cursor.moveToFirst()) {
            dataMap.put(WELL_RITE, cursor.getString(1));
            dataMap.put(CHALLANGER, cursor.getString(2));
            dataMap.put(FLEX_LITE, cursor.getString(3));
        }
    }
    return dataMap;
  }
}

TestApp.kt

package com.test.activity

import android.app.Application
import com.crashlytics.android.Crashlytics
import com.test.dbhelper.DBAdapter
import io.fabric.sdk.android.Fabric

class TestApp : Application() {

  companion object {
    lateinit var dbAdapter: DBAdapter
  }

  override fun onCreate() {
    super.onCreate()
    Fabric.with(this, Crashlytics())
    dbAdapter = DBAdapter(applicationContext)
    dbAdapter.openDataBase()
  }
}

从MainActivity.java中,我正在调用下面的函数以使用DBQuery方法获取数据。

var dataMap: HashMap<kotlin.String, kotlin.String> = HashMap()
dataMap = DBQuery.getWellRiteModels(TAB_WELL_RITE, DBConstants.TAB_WELL_RITE_TANK_VOLUME_IN_GALLON, 32.50)

我的test.db3数据库的资产文件夹中有记录。 它将从资产复制到/ data / data / ...,如您在DBAdapter.java类中看到的代码。

Android 8.0的三星设备是否存在任何特定问题?

下面是错误日志

Fatal Exception: java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/user/0/com.test/databases/test.db3
   at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:55)
   at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1742)
   at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1685)
   at com.test.dbhelper.DBAdapter.executeRawQuery(DBAdapter.java:147)
   at com.test.dbhelper.DBQuery.getWellRiteModels(DBQuery.java:26)     

2 个答案:

答案 0 :(得分:1)

尝试在需要时关闭和打开数据库,到目前为止,只需在checkDataBase()的下面的代码中注释一下,它将像魅力一样工作...

mDB.close();

答案 1 :(得分:0)

所以我解决了Oreo中的类似问题,该问题来自特定版本中Sqlite的优化​​,该版本在其他设备上运行良好,但不适用于Oreo。如果您有复杂的查询,请尝试使用交叉联接为优化器强制某些表的顺序,并在实际查询之前执行“编译优化”。

使用EXPLAIN QUERY PLAN可以发现,在Oreo中,优化器在某个时刻扫描的表与其他设备不同。该表很大,因此查询花费了很多时间。我无法真正解释为什么这样做,但是根据SQLite documentation的说法,可能会有关于复杂子查询的回归。

我不知道它是否对您有帮助,但对我有用。