我的Android应用程序中存在很大问题。我是第一次使用sqlite数据库开发一个android应用程序,但我遇到了无法解决的问题。
我的sqlite数据库位于eclipse项目的assets文件夹中,名称为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在109ms内释放了519个对象/ 45792个字节 05-29 23:55:46.544:E / Database(221):sqlite3_open_v2(“/ data / data / sal.app / databases / saldb.sqlite”,&amp; handle,1,NULL)失败
05-29 23:55:46.594:D / AndroidRuntime(221):关闭VM 05-29 23:55:46.604:W / dalvikvm(221):threadid = 3:线程退出未捕获异常(组= 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);
}
}
在我第二次运行app时,错误不会发生,数据库在正确的路径中但只有表android_metadata
我也可以说,如果我在/data/data/sal.app/databases/上放置正确的数据库,整个程序就可以正常工作...... 错误发生在copyDatabase中。
答案 0 :(得分:1)
这是我复制数据库的工作代码。
private static String DB_PATH = "/data/data/com.demo.databaseDemo/databases/";
private static String DB_NAME = "myDatabase.db";
private void copyDataBase() throws IOException{
//Open your local db as the input stream
InputStream myInput = _myContext.getAssets().open(DB_NAME);
// Path to the just created empty db
String outFileName = DB_PATH + DB_NAME;
//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();
}//end of copyDataBase() method
答案 1 :(得分:0)
您需要为您的数据库创建文件夹,并在第一次运行应用程序时将其复制到该文件夹中。这是我的工作:
// Check to see if database exists, otherwise copy from assets
boolean dbExist = db.databaseExist();
if (!dbExist) {
try {
// See if there is a data directory, otherwise create it
String destPath = "/data/data/" + getActivity().getPackageName() +
"/databases/";
File f = new File(destPath);
if (!f.exists()) {
f.mkdirs();
f.createNewFile();
// Copy from assets to data directory
CopyDB(getActivity().getBaseContext().getAssets().open("myData.sqlite"),
new FileOutputStream(destPath + "/myData.sqlite"));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}