我的 android 应用程序有一个大问题。我是第一次开发带有 sqlite 数据库的 android 应用程序,但我有一些我无法解决的问题。
我在 eclipse 项目的 assets 文件夹中有我的 sqlite 数据库,名称为 saldb.sqlite
我有以下类来使用 Singletone 模式管理数据库:
package sal.app.logic;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
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;
public class DataBaseManager extends SQLiteOpenHelper{
private static DataBaseManager dbManagerInstance = null;
private Context salContext;
private SQLiteDatabase salDatabase;
private static String DB_PATH = "/data/data/sal.app/databases/";
private static String DB_NAME = "saldb.sqlite";
private DataBaseManager(Context c)
{
super(c, DB_NAME, null, 1);
//this.salContext = c;
}
public static DataBaseManager getSalDatabase(Context c)
{
if (dbManagerInstance == null)
{
dbManagerInstance = new DataBaseManager(c);
}
return dbManagerInstance;
}
public void createDataBase() throws IOException{
boolean dbExist = checkDataBase();
if(dbExist){
//do nothing - database already exist
}else{
//By calling this method and empty database will be created into the default system path
//of your application so we are gonna be able to overwrite that database with our database.
this.getReadableDatabase();
try {
copyDataBase();
} catch (IOException e) {
throw new Error("Error copying database");
}
}
}
private boolean checkDataBase()
{
SQLiteDatabase checkDB = null;
try{
String myPath = DB_PATH + DB_NAME;
checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
}catch(SQLiteException e){
//database does't exist yet.
}
if(checkDB != null){
checkDB.close();
}
return checkDB != null ? true : false;
}
private void copyDataBase() throws IOException{
//Open your local db as the input stream
InputStream myInput = salContext.getAssets().open(DB_NAME);
// Path to the just created empty db
//String outFileName = DB_PATH + DB_NAME;
String outFileName = "/data/data/sal.app/databases/saldb.sqlite";
//Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(outFileName);
//transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer))>0){
myOutput.write(buffer, 0, length);
}
//Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
}
public void openDataBase() throws SQLException{
//Open the database
String myPath = DB_PATH + DB_NAME;
salDatabase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);
}
@Override
public synchronized void close() {
if(salDatabase != null)
salDatabase.close();
super.close();
}
@Override
public void onCreate(SQLiteDatabase db) {
//db.execSQL("Insert Into Question(_id,level,text,idTopic) Values (1,1,'asa',0)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
// Add your public helper methods to access and get content from the database.
// You could return cursors by doing "return myDataBase.query(....)" so it'd be easy
// to you to create adapters for your views.
public Question getOneQuestion()
{
//list of Versioni, search result with query text
Question quest = new Question();
try
{
//open database to query
openDataBase();
//salDatabase.execSQL("Insert Into Question(_id,level,text,idTopic) Values (1,1,'asa',0)");
//Cursor cursor = salDatabase.rawQuery("SELECT text, idTopic, level from Question WHERE level=2", null);
Cursor cursor = salDatabase.rawQuery("SELECT * from Question", null);
/*Cursor cursor = salDatabase.query("Question",
new String[] { "text","idTopic","level"},
"level=2",
null ,
null,
null,
"RANDOM() LIMIT 1");*/
//Cursor c = db.rawQuery(select, null); */
//mapped all rows to data object
if (cursor.moveToFirst())
{
System.out.println(cursor.getString(2));
do
{
Cursor cursor2 = salDatabase.rawQuery("SELECT * from Topic WHERE _id=0", null);
cursor2.moveToFirst();
Topic t = new Topic(cursor2.getString(1));
quest = new Question(cursor.getString(2),t,(int)cursor.getShort(1));
break;
} while (cursor.moveToNext());
}
//close cursor
cursor.close();
}
catch(Exception ex)
{
System.out.println("DatabaseHelper.search()- : ex " + ex.getClass() +", "+ ex.getMessage());
}
//
return quest;
}
/*public ArrayList<Answer> getAnswersOfQuestion(Questin q)
{
}*/
}
但是在我第一次运行我的应用程序时,我有以下错误:
05-29 23:55:45.684:D/ddm-heap(221):得到功能列表请求 05-29 23:55:46.295:D/dalvikvm(221):GC 在 109 毫秒内释放了 519 个对象/45792 个字节 05-29 23:55:46.544: E/Database(221): sqlite3_open_v2("/data/data/sal.app/databases/saldb.sqlite", &handle, 1, NULL) 失败
05-29 23:55:46.594: D/AndroidRuntime(221): 关闭虚拟机 05-29 23:55:46.604: W/dalvikvm(221): threadid=3: 线程退出但未捕获异常 (group=0x4001b188)
05-29 23:55:46.604:E/AndroidRuntime(221):未捕获的处理程序:线程主因未捕获的异常而退出
在我的主要活动中我这样做:
public class SALActivity extends Activity {
Button back;
Button choiceA;
static int choice = 0;
DataBaseManager db;
//Button choiceB;
//Button choiceC;
//Button choiceD;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.requestWindowFeature(Window.FEATURE_NO_TITLE);
super.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
super.onCreate(savedInstanceState);
setContentView(R.layout.gamemenu);
//db= new DataBaseManager(this);
db=DataBaseManager.getSalDatabase(this);
try {
db.createDataBase();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//db=DataBaseManager.getSalDatabase(this);
Question q = db.getOneQuestion();
//back = (Button) findViewById(R.id.gaveup_button);
choiceA = (Button) findViewById(R.id.choice_a_button);
choiceA.setTextColor(0xffffffff);
//choiceA.setText("A: Académica");
choiceA.setText(q.getQuestionText());
choiceA.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
}
});
//choiceA.setText(10);
//choiceB = (Button) findViewById(R.id.choice_b_button);
//choiceC = (Button) findViewById(R.id.choice_c_button);
//choiceD = (Button) findViewById(R.id.choice_d_button);
//Intent v = new Intent(this, SALActivity.class);
//this.startActivity(v);
}
}
在我第二次运行应用程序时,不会发生错误,数据库在正确的路径中,但只有表 android_metadata
我也可以说,如果我将正确的数据库放在 /data/data/sal.app/databases/ 上,整个程序就可以工作......错误在 copyDatabase 中。