第二次打开时,Android数据库NullPointerException

时间:2014-01-12 00:18:16

标签: android sqlite

我一直在刷新片段的联系人列表时遇到问题,每次我尝试调用刷新列表的方法时,都会收到此错误:

01-11 17:55:48.215: W/System.err(25594): java.lang.NullPointerException
01-11 17:55:48.235: W/System.err(25594):at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:224)
01-11 17:55:48.235: W/System.err(25594): at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)
01-11 17:55:48.235: W/System.err(25594): at com.Spit.pocketbook.DatabaseManager.<init>(DatabaseManager.java:48)
01-11 17:55:48.235: W/System.err(25594): at com.Spit.pocketbook.ContactsFragment.getContacts(ContactsFragment.java:105)
01-11 17:55:48.235: W/System.err(25594): at com.Spit.pocketbook.ContactsFragment.fillContactList(ContactsFragment.java:70)
01-11 17:55:48.235: W/System.err(25594): at com.Spit.pocketbook.SwipeActivity.onFinishCreateContactDailog(SwipeActivity.java:96)
01-11 17:55:48.235: W/System.err(25594): at com.Spit.pocketbook.ContactCreateDialog$PositiveButtonListener.onClick(ContactCreateDialog.java:129)
01-11 17:55:48.235: W/System.err(25594): at com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java:167)
01-11 17:55:48.235: W/System.err(25594): at android.os.Handler.dispatchMessage(Handler.java:99)
01-11 17:55:48.235: W/System.err(25594): at android.os.Looper.loop(Looper.java:137)
01-11 17:55:48.235: W/System.err(25594): at android.app.ActivityThread.main(ActivityThread.java:4950)
01-11 17:55:48.235: W/System.err(25594): at java.lang.reflect.Method.invokeNative(Native Method)
01-11 17:55:48.235: W/System.err(25594): at java.lang.reflect.Method.invoke(Method.java:511)
01-11 17:55:48.245: W/System.err(25594): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1004)
01-11 17:55:48.245: W/System.err(25594): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:771)
01-11 17:55:48.245: W/System.err(25594): at dalvik.system.NativeStart.main(Native Method)

每次我在ContactsFragment

中使用此方法时都会发生这种情况
private ArrayList<Contact> getContacts(){
    DatabaseManager manager = new DatabaseManager(getActivity());
    ArrayList<Contact> contacts = manager.getAllContacts();
    manager.close();
    return contacts;
}

实例化一个新的DatabaseManager(我创建它是为了在数据库中执行繁琐的工作并为我的应用程序的其余部分很好地包装它):

public DatabaseManager(Context context){
    mDatabase = new DatabaseHelper(context).getWritableDatabase();    //Line 48 (where the error occurs)
    mContext = context;
}

这里是getAllContacts()方法供参考:

public ArrayList<Contact> getAllContacts(){
    ArrayList<Contact> contacts = new ArrayList<Contact>();

    //query the database for all the contacts
    String[] projections = {ContactsTable._ID, 
            ContactsTable.COLUMN_CONTACT_NAME, 
            ContactsTable.COLUMN_LOOKUP_KEY,
            ContactsTable.COLUMN_SCOPE};
    Cursor C = mDatabase.query(ContactsTable.CONTACTS_TABLE_NAME, projections, 
            null, null, null, null, ContactsTable.COLUMN_CONTACT_NAME + " ASC");

    //iterates through the results and adds them all to the ArrayList
    while(C.moveToNext()){
        Contact contact = new Contact(C.getLong(0),
                C.getString(1),
                C.getString(2),
                C.getString(3));
        contacts.add(contact);
        }

    C.close();  //save from memory leakage

    return contacts;
}

注意:“m”变量代表全局变量

所有这一切中有趣的部分是,在创建ContactFragment时调用同样的方法(.getContacts()),它也以相同的方式调用DatabaseManager构造函数。除了所有这些之外,当我的应用程序加载时,它会打开一个ViewPager(实际读取日志的人的SwipeActivity),它会加载两个片段。 ContactsFragment和另一个SummaryFragment,它使用与.getContact()非常相似的方法来获取数据库中的其他信息。但我的应用程序加载时效果很好。获取所有信息并显示得很好。只有当我尝试在片段生命周期中第二次更新它时,我才会得到错误。我发现的唯一修复是旋转屏幕,基本上转储并重新创建活动中的所有内容。

因为它在我旋转屏幕时起作用,这让我觉得这是一个问题,即使我关闭数据库,它仍然保持打开状态,这就是为什么我不能再次调用它来刷新清单。如果这是问题,我不知道如何解决它,并会感谢任何和所有帮助,但再次,这可能与它无关。

这是我对manager.close()的调用,它关闭了DatabaseManager在创建时打开的数据库:

public void close(){
    mDatabase.close();
}

我几天来一直在努力解决这个问题。我做了一些研究(显然没有用),并研究了可以产生错误的不同方法,但我提出的每个修复都没有效果。

提前感谢所有建议/帮助,

大卫(吐)

2 个答案:

答案 0 :(得分:2)

您收到NullPointerException因为您关闭了数据库,然后由于某种原因后续尝试重新打开它。

最好的办法是不要关闭数据库。正如Google FW工程师Dianne Hackborn所说,您不需要手动关闭数据库,因为一旦您的进程被终止,它将自动关闭。有关她对此发表评论的多篇帖子,请参阅link #1link #2

此外,如果你沿着这条路走,你应该让你的DatabaseHelper成为一个单身,这样你在任何时候都只有一个数据库实例(否则,这也会成为问题)。为您的ContentProvider和嵌套DatabaseHelper类实现类似的内容:

public class CustomDbProvider extends ContentProvider {
    private static final String DATABASE_NAME = "myapp.db";
    private static final int DATABASE_VERSION = 4;

    static class DatabaseHelper extends SQLiteOpenHelper {
        private static final String TAG = "DBHelper";
        private static DatabaseHelper sInstance = null;

        private DatabaseHelper(Context context) {

            // calls the super constructor, requesting the default cursor factory.
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        public static DatabaseHelper getInstance(Context c) {
            if (sInstance == null) sInstance = new DatabaseHelper(c);
            return sInstance;
        }

然后您的Fragment您可以执行以下操作(另请参阅dev page here)(此外,此代码假设您使用某种类型的ListAdapter但如果没有,一旦你在Cursor获得onLoadFinished(),你可以随心所欲地做任何事情):

public class ContactsFragment extends Fragment implements
        LoaderManager.LoaderCallbacks<Cursor> {

    ...

    @Override
    public void onCreate(Bundle savedInstance) {
        ...
        // initialize the loader with the loader callbacks
        getLoaderManager().initLoader(SOME_UNIQUE_ID, getArguments(), this);
    }

    @Override
    public Loader<Cursor> onCreateLoader(int arg0, Bundle fragargs) {
        Uri uri = /* FIXME some URL defined in your Provider */;
        String selection = null;
        String[] selectionArgs = null;
        return new CursorLoader(mContext, uri, projection, selection, selectionArgs, ContactsTable.COLUMN_CONTACT_NAME + " ASC");
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
        mAdapter.swapCursor(c);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        mAdapter.swapCursor(null);
    }

答案 1 :(得分:0)

stacktrace表示您传递给SQLiteOpenHelper的上下文为null

由于它是作为上下文传递的片段getActivity(),因此在创建数据库管理器时片段未附加到活动。