Android Sqlite - 无法在 onCreate 之外调用数据库处理程序

Posted

技术标签:

【中文标题】Android Sqlite - 无法在 onCreate 之外调用数据库处理程序【英文标题】:Android Sqlite - unable to call database handler outside of onCreate 【发布时间】:2017-06-27 14:56:49 【问题描述】:

代码如下:

主要活动:

    package com.dummies.myapplication;

import android.database.sqlite.SQLiteDatabase;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import java.sql.SQLClientInfoException;
import java.util.List;
import com.dummies.myapplication.User;

public class MainActivity extends AppCompatActivity 

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //new LoginHelper().Process();

        DatabaseHandlerV2 db = new DatabaseHandlerV2(this);

        // db.deleteTable();

//       /db.makeTable(DatabaseHandlerV2);

        //Log.d("Insert: ", "Inserting ..");
        db.addUser(new User(1, "name", "email","password","van","username"));


        // Reading all contacts
        Log.d("Reading: ", "Reading all contacts..");
        List<User> users = db.getAllUsers();

        for (User us : users) 
            String log = "Id: "+us.getID()+" ,Name: " + us.getName() + " ,email: " + us.getEmail() + " ,password: " + us.getPassword() + ",username:" + us.getUsername() + ",van:" + us.getVan();
            // Writing Contacts to log
            Log.d("Name: ", log);
        

        Button login = (Button) findViewById(R.id.loginSubmit);
        final EditText clientUsername = (EditText)findViewById(R.id.username);
        final EditText clientPassword = (EditText)findViewById(R.id.password);

        login.setOnClickListener(new View.OnClickListener()
            public void onClick(View v) 
                //Log.d("User deets username", clientUsername.getText().toString());
                //Log.d("User deets password", clientPassword.getText().toString());
                String username  = clientUsername.getText().toString();
                String password = clientPassword.getText().toString();
                LoginHelper LoginHelper = new LoginHelper();
                LoginHelper.checkLogin(username, password);

            
        );

        //db.deleteTable();


    
    public void loginSuccess(String id, String username, String email, String password, String vanId, String name)
    
        //Log.d("logged in user", id + "," + username + "," + email + "," + password + "," + vanId);
        // db.addUser(new User(id, username, email,password,vanId));
        int intId = Integer.parseInt(id);
        //int intVanId = Integer.parseInt(vanId);
        DatabaseHandlerV2 db = new DatabaseHandlerV2(this);
        db.deleteTableData();
       // db.addUser(new User(intId, name, email,password,vanId,username));
        db.addUser(new User(1, "name", "email","password","van","username"));
        Log.d("Jon Error", "Logged in user is" + intId);

        // db.deleteTable();
    



数据库助手 V2:

package com.dummies.myapplication;

/**
 * Created by Jon on 05/02/2017.
 */

import java.util.ArrayList;
import java.util.List;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabaseLockedException;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class DatabaseHandlerV2 extends SQLiteOpenHelper 

    // All Static variables
    // Database Version
    private static final int DATABASE_VERSION = 1;

    // Database Name
    private static final String DATABASE_NAME = "userManager";

    // Contacts table name
    private static final String TABLE_USERS= "users";

    // Contacts Table Columns names
    private static final String KEY_ID = "id";
    private static final String KEY_NAME = "name";
    private static final String KEY_EMAIL = "email";
    private static final String KEY_PASSWORD = "password";
    private static final String KEY_VAN = "van_id";
    private static final String KEY_USERNAME = "username";


    public DatabaseHandlerV2(Context context) 
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    

    // Creating Tables
    @Override
    public void onCreate(SQLiteDatabase db) 
        String CREATE_USERS_TABLE = "CREATE TABLE " + TABLE_USERS + "("
                + KEY_ID + " INTEGER PRIMARY KEY," + KEY_NAME + " TEXT,"
                + KEY_EMAIL + " TEXT" + "," + KEY_PASSWORD + " TEXT," + KEY_VAN + " INTEGER," + KEY_USERNAME + " TEXT" + ")";

        db.execSQL(CREATE_USERS_TABLE);
        Log.d("Jon error", "creating table");
    





    // Upgrading database
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) 
        // Drop older table if existed
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_USERS);

        // Create tables again
        onCreate(db);
    

    /**
     * All CRUD(Create, Read, Update, Delete) Operations
     */

    // Adding new contact
    void addUser(User user) 
        SQLiteDatabase db = this.getWritableDatabase();

        //onCreate(db);

        ContentValues values = new ContentValues();
        values.put(KEY_NAME, user.getName()); // Contact Name
        values.put(KEY_EMAIL, user.getEmail()); // Contact Email
        values.put(KEY_PASSWORD, user.getPassword());
        values.put(KEY_VAN, user.getVan());
        values.put(KEY_USERNAME, user.getUsername());

        // Inserting Row
        db.insert(TABLE_USERS, null, values);
        db.close(); // Closing database connection

    

    // Getting single contact
    Contact getUser(int id) 
        SQLiteDatabase db = this.getReadableDatabase();

        Cursor cursor = db.query(TABLE_USERS, new String[]  KEY_ID,
                        KEY_NAME, KEY_EMAIL, KEY_PASSWORD, KEY_VAN, KEY_USERNAME , KEY_ID + "=?",
                new String[]  String.valueOf(id) , null, null, null, null);
        if (cursor != null)
            cursor.moveToFirst();

        Contact contact = new Contact(Integer.parseInt(cursor.getString(0)),
                cursor.getString(1), cursor.getString(2));
        // return contact
        return contact;
    

    // Getting All Contacts
    public List<User> getAllUsers() 
        Log.d("Jon Error", "debug");
        List<User> userList = new ArrayList<User>();
        // Select All Query
        String selectQuery = "SELECT  * FROM " + TABLE_USERS;

        SQLiteDatabase db = this.getWritableDatabase();
        Cursor cursor = db.rawQuery(selectQuery, null);

        // looping through all rows and adding to list
        if (cursor.moveToFirst()) 
            do 
                Log.d("Jon Error:", "test");
                User user = new User();
                user.setID(Integer.parseInt(cursor.getString(0)));
                //Log.d(cursor.getString(0));
                user.setName(cursor.getString(1));
                user.setEmail(cursor.getString(2));
                user.setPassword(cursor.getString(3));
                user.setVan(cursor.getString(4));
                user.setUsername(cursor.getString(5));
                // Adding contact to list
                userList.add(user);
             while (cursor.moveToNext());
        

        // return contact list
        return userList;
    

    // Updating single contact
    public int updateUser(User user) 
        SQLiteDatabase db = this.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(KEY_NAME, user.getName());
        values.put(KEY_EMAIL, user.getEmail());
        values.put(KEY_PASSWORD, user.getPassword());
        values.put(KEY_VAN, user.getVan());
        values.put(KEY_VAN, user.getUsername());

        // updating row
        return db.update(TABLE_USERS, values, KEY_ID + " = ?",
                new String[]  String.valueOf(user.getID()) );
    

    // Deleting single contact
    public void deleteUser(Contact contact) 
        SQLiteDatabase db = this.getWritableDatabase();
        db.delete(TABLE_USERS, KEY_ID + " = ?",
                new String[]  String.valueOf(contact.getID()) );
        db.close();
    

    public void deleteTable()
    
        SQLiteDatabase db = this.getReadableDatabase();
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_USERS);
        Log.d("Jon error", "deleteing");
    

    public void deleteTableData()
    
        SQLiteDatabase db = this.getReadableDatabase();
        db.execSQL("DELETE FROM " + TABLE_USERS);
    


    // Getting contacts Count
    public int getUsersCount() 
        String countQuery = "SELECT  * FROM " + TABLE_USERS;
        SQLiteDatabase db = this.getReadableDatabase();
        Cursor cursor = db.rawQuery(countQuery, null);
        cursor.close();

        // return count
        return cursor.getCount();
    


现在我确定问题是因为我正在调用 db.addUser(new User(1, "name", "email","password","van","username"));来自 loginSuccess 方法。

我怎样才能让这个简单的插入工作?我确信这个问题与上下文有关。我试过这个没有运气Static way to get 'Context' on Android?

谢谢!

【问题讨论】:

您似乎是从任务中调用loginSuccess()。您的上下文为空。打开数据库时尝试使用全局应用程序上下文。 【参考方案1】:

尝试使用单例设计模式来访问数据。 看看这个post 看看如何。

据我所知,loginSuccess() 在从网络服务器接收数据后被调用。

您的应用可能正在尝试同时将数据写入数据库。

编辑: 当使用多个 DatabaseHandlerV2 实例时,请考虑关闭连接。

例子:

助手:

public class SampleHelper extends SQLiteOpenHelper 

    private static SampleHelper instance;
    private static Context mContext;

    public static synchronized SampleHelper getHelper(Context context) 
        if (instance == null)
             instance = new SampleHelper(context);
        return instance;
    

    private SampleHelper(Context context) 
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        mContext = context;
    

写作:

SampleHelper helper = SampleHelper.getHelper(mContext);
SQLiteDatabase writableDb = helper.getWritableDatabase();
String statement = "INSERT OR REPLACE INTO table_name(colA,colB) VALUES (valA,valB)";
writableDb.execSQL(statement);

阅读:

Cursor cursor = null;
try     
    cursor = SampleHelper.getHelper(mContext).getReadableDatabase().rawQuery("SELECT colA FROM table_name");
    if (cursor.moveToFirst()) 
        do 
            /**read the data here**/
         while (cursor.moveToNext());
    

finally 
    if(null != cursor)
        cursor.close();

如您所见,与数据库的连接并未关闭。 当使用单例模式时,我们只使用SampleHelper 的一个实例,因此我们可以保持连接打开。

直到现在我才检查您的更新日志。它说:

A SQLiteConnection object for database '/data/data/com.dummies.myapplication/databases/userManager' was leaked! Please fix your application to end transactions in progress properly and to close the database when it is no longer needed.

这意味着您没有关闭连接(db.close();),因此在deleteTableData() 方法上执行this.getReadableDatabase(); 时出现空指针异常。

我仍然建议使用提供的示例代码来避免数据库被锁定异常。

对于openOrCreateDatabase 异常,请检查此post。请注意,数据库名称以.db 结尾。还要检查你的上下文是否为空。

【讨论】:

你能提供一个具体的例子吗? 当然。我就是这样做的。 谢谢。我仍然有一个错误使用你的代码。 - 查看更新的问题。 我已经更新了我的答案以解决新的异常。 我仍然遇到同样的错误,我相信这是因为在调用 DatabaseHaldler.getHelper 时,我将它作为不是有效上下文的 permiter 传递。有任何想法吗? - 编辑 - 我尝试从 MainActivity 中的 onCreate 方法运行代码并且它很好 - 在 loginSuccess 上它失败了。【参考方案2】:

每次你想改变它的结构时,你都必须打开一个可写的数据库(不可读)。所以,在你的 DatabaseHandlerV2 类中需要插入、删除或更新数据到数据库中的每个方法中,把这行:SQLiteDatabase db = this.getWritableDatabase(); 代替:SQLiteDatabase db = this.getReadableDatabase();

在这种特定情况下,要解决此错误,您必须以这种方式更改deleteTableData() 方法:

public void deleteTableData()

    SQLiteDatabase db = this.getWritableDatabase();
    db.execSQL("DELETE FROM " + TABLE_USERS);

【讨论】:

我仍然收到错误:E/AndroidRuntime: FATAL EXCEPTION: main Process: com.dummies.myapplication, PID: 3861 java.lang.NullPointerException: Attempt to invoke virtual method 'android.database.sqlite .SQLiteDatabase android.content.Context.openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase$CursorFactory, android.database.DatabaseErrorHandler)' 在空对象引用上 这并不能解决问题,在大多数情况下,调用getWriteableDatabase() 与调用getReadableDatabase() 相同。 似乎“this”在“deleteTableData”方法中为空。那么您可以发布代码以显示您在哪里调用 loginSuccess 吗?【参考方案3】:
DatabaseHandlerV2 maindb=null;

@Override

protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    maindb= new DatabaseHandlerV2(this);

public void loginSuccess(String id, String username, String email, String password, String vanId, String name)

maindb.deleteTableData();

【讨论】:

以上是关于Android Sqlite - 无法在 onCreate 之外调用数据库处理程序的主要内容,如果未能解决你的问题,请参考以下文章

无法在 android 中使用 sqlite 添加唯一行

Android SQLite 更新无法在 AsyncTask 的后台运行

无法存储android设备的位置并将其存储在sqlite中

Android Sqlite - 无法在 onCreate 之外调用数据库处理程序

无法写入导入的 SQLite 数据库 Android

无法从 SQLite 检索数据说 android (Eclipse) 中不存在该列