2015-11-02 65 views
-1

我希望我的问题不是太宽泛。我真正想知道的是如何准确地确定我的代码在墙上的位置。Android Studio应用程序崩溃从Sqlite数据库

我没有从调试器收到错误,应用程序在模拟器启动使用sqlite数据库的活动(第3个活动)时崩溃。我很积极,它是我的代码中添加了sqlite,导致崩溃,因为它在我添加之前运行。

此代码只需访问并从我创建并粘贴到资产文件夹的外部数据库中读取。我回顾了firefox的SQLite管理器中的sqlite数据库;该信息似乎被正确格式化。

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

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

LetterImage:

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项目。任何和所有的见解,非常感谢。

+0

如果您有答案,请填写答案。 –

回答

0

我想通了,解决这个问题的一种方法:

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()没有返回false到createDatabase(),所以代码试图打开一个不存在的数据库。