2015-11-02 68 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(),所以代碼試圖打開一個不存在的數據庫。