【问题标题】:Android Studio App Crash from Sqlite databaseSqlite 数据库中的 Android Studio 应用程序崩溃
【发布时间】:2015-11-02 03:17:51
【问题描述】:

我希望我的问题不会太宽泛。我真正想知道的是如何准确判断我的代码在哪里碰壁。

我的调试器没有出错,当模拟器启动一个使用 sqlite 数据库的活动(第三个活动)时,应用程序就会崩溃。我很肯定是在我的代码中添加了 sqlite 导致崩溃,因为它在我添加它之前运行。

此代码只需要访问和读取我创建并粘贴到资产文件夹中的外部数据库。我在 Firefox 的 SQLite Manager 中查看了 sqlite 数据库;信息的格式似乎正确。

我在 app/src/Main 中创建了一个 assets 文件夹,以方便添加外部数据库“ex3.db”。然后我将数据库文件复制并粘贴到那里。

所以这里是代码。 LetterImage 是一个保存从 sqlite 数据库中检索到的字符串的类。 MyDBHandler 创建一个空数据库,将旧数据库复制到其中,并使用从基于字符串的查询返回的值填充 LetterImage。 LoadSubjectActivity 调用它们来搜索数据库并返回一个字符串。

字母图片:

public class LetterImage {
private Integer _ID;
private String _letter;
private String _bigfilename;
private String _littlefilename;

//Constructor(s)
public LetterImage(){

}

public LetterImage(Integer ID, String letter, String bigfilename, String littlefilename){
    this._ID = ID;
    this._letter = letter;
    this._bigfilename = bigfilename;
    this._littlefilename = littlefilename;
}

public LetterImage(String letter){
    this._letter = letter;
}

//End Constructors

//Begin setters and getters

//ID is primary key
public void setID(Integer ID){
    this._ID = ID;
}

public Integer getID(){
    return this._ID;
}

//letter is main identifier used to search database
// passed to LoadSubjectActivity
// from ChooseSubjectABCActivity as extra from intent
public void setLetter(String letter){
    this._letter = letter;
}

public String getLetter(){
    return this._letter;
}

//Capital letter image file name
public void setBigFileName(String bigfilename){
    this._bigfilename = bigfilename;
}
public String getBigFileName(){
    return this._bigfilename;
}

//Lowercase Letter image file name
public void setLittleFileName(String littlefilename){
    this._littlefilename = littlefilename;
}
public String getLittleFileName(){
    return this._littlefilename;
}
}

现在,这里是 MyDBHandler:

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

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

public class MyDBHandler extends SQLiteOpenHelper{

private final Context myContext;
private static Context context;

private static final int DATABASE_VERSION = 1;
private static String DB_PATH = "data/data" + context.getPackageName() + "/databases/";
private static final String DATABASE_NAME = "ex3.db";
public static final String TABLE_IMAGES = "tbl1";

private SQLiteDatabase myDataBase;

//Fields in Database
public static final String COLUMN_ID = "_id";
public static final String COLUMN_BIGIMAGEFILE = "bigImage";
public static final String COLUMN_LITTLEIMAGEFILE = "littleImage";
public static final String COLUMN_LETTER = "letter";

//Constructor
public MyDBHandler(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
    this.myContext = context;
}

//if there is no existing database, create an empty one
public void createDatabase() throws IOException{
    boolean dbExist = checkDataBase();

    if(dbExist) {
        //do nothing
    }else {
        //call this method and create an empty database
        this.getReadableDatabase();

        try {
            copyDataBase();

        } catch(IOException e){
            throw new Error("Error copying database");

        }

    }
}

//check to see if there is an existing database
private boolean checkDataBase(){
    SQLiteDatabase checkDB = null;

    try{
        String myPath = DB_PATH + DATABASE_NAME;
        checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);

    } catch (SQLiteException e){
        throw new Error("Unable to open database");
    }

    if(checkDB != null){

        checkDB.close();
    }

    return checkDB != null ? true : false;
}

//fills new empty database with existing database ex3
private void copyDataBase() throws IOException{

    InputStream myInput = myContext.getAssets().open(DATABASE_NAME);

    String outFileName = DB_PATH + DATABASE_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();
}

//opens the new database
public void openDatabase() throws SQLException {

    String myPath = DB_PATH + DATABASE_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){

}


//creates an instance of letter LetterImage
//queries the new database by searching for the row with where the value of COLUMN_LETTER = letter
//fills LetterImage with the values from that row
public LetterImage findLetter(String letter) {
    String query = "Select * FROM " + TABLE_IMAGES + " WHERE " + COLUMN_LETTER + " =  \"" + letter + "\"";

    SQLiteDatabase db = this.getWritableDatabase();

    Cursor cursor = db.rawQuery(query, null);

    LetterImage LetterImage = new LetterImage();

    if (cursor.moveToFirst()) {
        cursor.moveToFirst();
        LetterImage.setID(Integer.parseInt(cursor.getString(0)));
        LetterImage.setBigFileName(cursor.getString(1));
        LetterImage.setLittleFileName(cursor.getString(2));
        LetterImage.setLetter(cursor.getString(3));
        cursor.close();
    } else {
        LetterImage = null;
    }
    db.close();
    return LetterImage;
}
}

最后,这里是 LoadSubjectActivity 类的相关部分:

public class LoadSubjectActivity extends MainActivity{

private DrawingView drawView;
private ImageButton currPaint;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.content_load_subject);

    //receives string letter, from last activity
    //letter will be used to search array and return files names of the images to be used

    Intent intent = getIntent();
    String letter = intent.getExtras().getString("letter");

    //displayFN calls testDB(letter) to test the database
    //It should simply display the string returned by testDB()

    TextView displayFN = (TextView)findViewById(R.id.display_filenames);
    displayFN.setText(testDB(letter.toLowerCase()));


    //Eventually, button images will be filled dynamically

    ImageButton bigLetter = (ImageButton)findViewById(R.id.big_letter);
    ImageButton littleLetter = (ImageButton)findViewById(R.id.little_letter);
    bigLetter.setImageResource(R.drawable.biga);
    littleLetter.setImageResource(R.drawable.littlea);

    drawView = (DrawingView)findViewById(R.id.drawing);
    LinearLayout paintLayout = (LinearLayout)findViewById(R.id.paint_colors);
    currPaint = (ImageButton)paintLayout.getChildAt(0);
    currPaint.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.paint_pressed));
}

//Function to test the database takes a string as an argument to search the database
public String testDB(String letter){

    //create a new instance of dbHandler
    MyDBHandler dbHandler = new MyDBHandler(this);

    //try to either create an empty database or open the existing one
    try{
        dbHandler.createDatabase();
    } catch (IOException ioe){
        throw new Error("Unable to create database");
    }
    try{
        dbHandler.openDatabase();
    } catch(SQLException sqle){
        sqle.printStackTrace();
        throw new Error ("unable to open database");
    }


    LetterImage letterImage = dbHandler.findLetter(letter);
    String blFileName = letterImage.getBigFileName();

    //return the big letter image file name;
    return blFileName;

}

无论如何,对于任何明显的问题,我提前道歉。我已经尽我所能追踪逻辑......我正在自学java和sql......这是我的第一个android项目。非常感谢任何和所有的见解。

【问题讨论】:

  • 如果你有答案,写一个答案。

标签: java database sqlite debugging android-studio


【解决方案1】:

我想出了一种解决方法:

1.) 重写 checkDatabase()。我参考了这个教程:How to use an existing database with an Android application,发现了这个:

private boolean checkDataBase(){

    File dbFile = new File(DB_PATH + DATABASE_NAME);
    //Log.v("dbFile", dbFile + "   "+ dbFile.exists());
    return dbFile.exists();
}

2.) 硬编码 DB_PATH 名称,因为 context.getFilesDir 和 getDatabasePath() 没有返回我需要的路径。

***通过 logcat 并将错误追溯到问题开始的确切位置是我如何找到我需要更改的地方。在这种情况下,checkDatabase() 没有向 createDatabase() 返回 false,因此代码试图打开一个不存在的数据库。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-22
    相关资源
    最近更新 更多