1

当从两个不同的活动中引用时,我试图获取一些有关数据库工作的方法,这导致我在同一类中使用不同的上下文重新初始化整个数据库。它适用于一个活动,但是当数据库关闭、初始化并在另一个活动中打开时,它会导致 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 类缺少一些东西,但找不到罪魁祸首。如果您需要更多信息或代码来解决这个难题,请随时告诉我。感谢您非常感谢您的帮助!

4

2 回答 2

3

我可以看看menu.getData(lView, view)方法吗?

Cursor无论如何,我建议不要从 Database Helper 类返回对象。为什么?因为,可能有多个调用,可能是对数据库的并行调用。每次您需要数据库中的某些内容时,您都需要打开它,然后关闭它。如果您的应用程序的一部分将关闭数据库,而另一部分尚未完成其工作 - 并且将尝试从数据库中访问数据或尝试从Cursor对象中获取数据 - 它肯定会崩溃。

我的解决方案是制作一些应用程序模型 <=> 数据库模型对象,该对象将双向映射数据。

例如:

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;
}
于 2013-05-09T21:49:05.640 回答
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();
于 2016-07-12T14:45:51.313 回答