我试图从两个不同的活动中引用一些有关数据库工作的方法,这使得我在同一个类中使用不同的上下文重新初始化整个数据库。它适用于一个活动,但是当数据库关闭,初始化并在另一个活动中打开时,它会导致IllegalArgumentException。这对我没有任何意义,因为我没有更改任何直接连接到数据库的方法,并且当代码在两个类中分离时它正在完美地工作。
堆栈跟踪:
05-09 20:44:42.661: E/AndroidRuntime(953): FATAL EXCEPTION: main
05-09 20:44:42.661: E/AndroidRuntime(953): java.lang.RuntimeException: Unable to resume activity {maturaarbeit.nicola_pfister.marks/maturaarbeit.nicola_pfister.marks.Marks}: java.lang.IllegalArgumentException: the bind value at index 1 is null
05-09 20:44:42.661: E/AndroidRuntime(953): at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2575)
05-09 20:44:42.661: E/AndroidRuntime(953): at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2603)
05-09 20:44:42.661: E/AndroidRuntime(953): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2089)
05-09 20:44:42.661: E/AndroidRuntime(953): at android.app.ActivityThread.access$600(ActivityThread.java:130)
05-09 20:44:42.661: E/AndroidRuntime(953): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
05-09 20:44:42.661: E/AndroidRuntime(953): at android.os.Handler.dispatchMessage(Handler.java:99)
05-09 20:44:42.661: E/AndroidRuntime(953): at android.os.Looper.loop(Looper.java:137)
05-09 20:44:42.661: E/AndroidRuntime(953): at android.app.ActivityThread.main(ActivityThread.java:4745)
05-09 20:44:42.661: E/AndroidRuntime(953): at java.lang.reflect.Method.invokeNative(Native Method)
05-09 20:44:42.661: E/AndroidRuntime(953): at java.lang.reflect.Method.invoke(Method.java:511)
05-09 20:44:42.661: E/AndroidRuntime(953): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
05-09 20:44:42.661: E/AndroidRuntime(953): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
05-09 20:44:42.661: E/AndroidRuntime(953): at dalvik.system.NativeStart.main(Native Method)
05-09 20:44:42.661: E/AndroidRuntime(953): Caused by: java.lang.IllegalArgumentException: the bind value at index 1 is null
05-09 20:44:42.661: E/AndroidRuntime(953): at android.database.sqlite.SQLiteProgram.bindString(SQLiteProgram.java:164)
05-09 20:44:42.661: E/AndroidRuntime(953): at android.database.sqlite.SQLiteProgram.bindAllArgsAsStrings(SQLiteProgram.java:200)
05-09 20:44:42.661: E/AndroidRuntime(953): at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:47)
05-09 20:44:42.661: E/AndroidRuntime(953): at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1314)
05-09 20:44:42.661: E/AndroidRuntime(953): at android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1161)
05-09 20:44:42.661: E/AndroidRuntime(953): at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1032)
05-09 20:44:42.661: E/AndroidRuntime(953): at maturaarbeit.nicola_pfister.marks.database.DBAdapter.getAverage(DBAdapter.java:200)
05-09 20:44:42.661: E/AndroidRuntime(953): at maturaarbeit.nicola_pfister.marks.MyMenu.getData(MyMenu.java:71)
05-09 20:44:42.661: E/AndroidRuntime(953): at maturaarbeit.nicola_pfister.marks.Marks.onResume(Marks.java:52)
05-09 20:44:42.661: E/AndroidRuntime(953): at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1184)
05-09 20:44:42.661: E/AndroidRuntime(953): at android.app.Activity.performResume(Activity.java:5082)
05-09 20:44:42.661: E/AndroidRuntime(953): at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2565)
05-09 20:44:42.661: E/AndroidRuntime(953): ... 12 more
Marks中的异常抛出方法(menu.onResume):
private final Context context;
private DatabaseHelper DBHelper;
private SQLiteDatabase db;
MyMenu menu = new MyMenu(this);
ListView lView;
View view;
private String TAG = "Marks";
@Override
protected void onResume() {
super.onResume();
menu.closedb();
menu.opendb(TAG);
menu.getData(lView, view);
}
MyMenu中的涉及方法(db.open()上的例外):
DBAdapter db;
public void opendb(String caller) {
db = new DBAdapter(context);
this.caller = caller; //Is used to distinguish which activity called the class; not involved in this problem
db.open();
}
public void closedb() {
db.clean();
db.close();
}
@SuppressWarnings("deprecation")
public String getData(final ListView lView, final View view) {
SimpleCursorAdapter adapter = null;
if (caller == "Main") {
adapter = new SimpleCursorAdapter(context,
android.R.layout.simple_list_item_activated_1,
db.getAllSubjects(),
new String[] { "subject" },
new int[] { android.R.id.text1 });
} else if (caller == "Marks") {
adapter = new SimpleCursorAdapter(context,
android.R.layout.simple_list_item_activated_1,
db.getMarks(subject),
new String[] {"value"},
new int[] { android.R.id.text1 });
Cursor cursor = db.getAverage(selection);
average = cursor.getDouble(cursor.getColumnIndexOrThrow(DBAdapter.KEY_VALUE));
if (average != 0.0) {
TextView text = new TextView(context);
text = (TextView)view.findViewById(R.id.marks_average);
text.setText(context.getString(R.string.average) + " " + average);
text.setBackgroundColor(context.getResources().getColor(R.color.lightgrey));
} else {
TextView text = new TextView(context);
text = (TextView)view.findViewById(R.id.marks_average);
text.setText("");
text.setBackgroundColor(context.getResources().getColor(android.R.color.transparent));
}
}
DBAdapter中的涉及方法(适用于一个活动,在getAverage()上抛出异常):
public DBAdapter open() throws SQLException {
db = DBHelper.getWritableDatabase();
return this;
}
public void close() {
DBHelper.close();
}
public boolean clean () {
db.delete(DATABASE_TABLE_SUBJECTS, KEY_SUBJECT +"=?", new String[] {""});
db.delete(DATABASE_TABLE_MARKS, KEY_VALUE + "=?", new String[] {""});
return true;
}
public Cursor getAverage(String subject) throws SQLException {
Cursor mCursor =
db.query(true, DATABASE_TABLE_AVERAGE, new String[] {
KEY_ROWID,
KEY_SUBJECT,
KEY_VALUE
},
KEY_SUBJECT + "=?",
new String[] {subject}, null, null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
我最初认为错误在于open()方法,但是在查看堆栈跟踪时,我发现getAverage()抛出异常会让我感到困惑,因为此时甚至都没有调用它。我假设在Marks活动中正确初始化DBAdapter类时缺少某些东西,但无法找到罪魁祸首。 如果您需要更多信息或代码来解决难题,请随时告诉我。 非常感谢您的帮助!
答案 0 :(得分:3)
我可以看到menu.getData(lView, view)
方法吗?
无论如何,我建议不要从Database Helper类返回Cursor
个对象。
为什么?
因为,可能有多个调用,可能是对数据库的并行调用。每当你需要数据库中的东西时,你需要打开它,然后关闭。如果您的应用程序的一部分将关闭数据库,而其他部分尚未完成其工作 - 并且将尝试从数据库中的数据访问某些内容或尝试从Cursor
对象获取数据 - 它肯定会崩溃。 / p>
我的解决方案是制作一些应用程序模型< =>将从双向映射数据的数据库模型对象。
例如:
public LinkedList<Person> getPersonList(){
Cursor result = db.query(...);
LinkedList<Person> people = null;
if(result.moveToFirst()){
people = new LinkedList<Person>();
Person person = null;
do{
person = new Person();
person.setBirthDate(result.getInt(0));
/*some more attributes mapping*/
people.add(person);
}while(result.hasNext());
}
return people;
}
答案 1 :(得分:0)
问题在于我认为您正在为每个上下文创建不同的SQLiteOpenHelper类实例。我对更好的设计模式的建议是为这个类使用一个线程安全的单例实例:
public class MyDbHelper extends SQLiteOpenHelper {
static volatile OnePageDbHelper sDefaultInstance;
private static final int DATABASE_VERSION = 1;
protected static final String DATABASE_NAME = "XXX.db";
/**
* Synchronized singleton instance access to application's {@link SQLiteOpenHelper} object.
*/
public static MyDbHelper getDefault(Context pContext) {
if (sDefaultInstance == null) {
synchronized (MyDbHelper.class) {
if (sDefaultInstance == null) {
sDefaultInstance = new MyDbHelper(pContext.getApplicationContext());
}
}
}
return sDefaultInstance;
}
/**
* Private constructor means object can only be instantiated within this class.
*
* @see {@link #getDefault(Context)}.
*/
private OnePageDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
// TODO - Execute SQL statements to create all tables.
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO - Remove all tables if exist.
}
}
然后您可以访问:
MyDbHelper.getInstance().performMyDbOperations();