Click here to Skip to main content
15,886,664 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
I am trying to store the called number whenever user makes an outgoing call.
First, number is checked with existing numbers in a log table present in local sqlitedb. If the number is present in log, then call information(called number, date-time of call and conversation time of the call) is to be stored in database.

Everything works fine, if the app is running in the background.

When, app is closed, a NullPointerException(for getReadableDatabase()) is thrown while trying to retrieve data from log table of numbers. I tried to figure out what am I possibly be doing wrong and I figured out (not very sure) that context required for the database class (where I am creating an instance to sqlite) is null when the app is closed.

I need to get over this issue and implement the functionality.

What I have tried:

Here is the code:

Class containing database functinalities
Java
public class tool_db_functions extends SQLiteOpenHelper
{
    // Database Info
    private static final String DATABASE_NAME = "kaarigars";
    private static final int DATABASE_VERSION = 2;

    // Table Names    
    public final String TABLE_LOG_CUST_DIALLED_KAARIGAR = "log_cust_dialled_kaarigar";
    public final String TABLE_LOG_CUST_CALLED_KAARIGAR = "log_cust_called_kaarigar";

    // Table Columns   
    public final String[] COL_LOG_CUST_DIALLED_KAARIGAR = {"kid"};
    public final String[] COL_LOG_CUST_CALLED_KAARIGAR = {"kid", "scode", "logdate", "conversationtime"};


    String CREATE_TABLE_LOG_CUST_DIALLED_KAARIGAR = "CREATE TABLE " + TABLE_LOG_CUST_DIALLED_KAARIGAR +
            "(" + COL_LOG_CUST_DIALLED_KAARIGAR[0] + " INTEGER PRIMARY KEY " + ")";

    String CREATE_TABLE_LOG_CUST_CALLED_KAARIGAR = "CREATE TABLE " + TABLE_LOG_CUST_CALLED_KAARIGAR +
            "(" +
            COL_LOG_CUST_CALLED_KAARIGAR[0] + " INTEGER NOT NULL, " +
            COL_LOG_CUST_CALLED_KAARIGAR[1] + " INTEGER DEFAULT NULL, " +
            COL_LOG_CUST_CALLED_KAARIGAR[2] + " DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, " +
            COL_LOG_CUST_CALLED_KAARIGAR[3] + " TEXT NOT NULL " +
            ")";

    private static tool_db_functions sInstance;

   
    private tool_db_functions(Context context)
    {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    public static synchronized tool_db_functions getInstance(Context context)
    {
        try
        {
           
            sInstance = new tool_db_functions(context.getApplicationContext()); //app is running, thus, its context exists
            return sInstance;
        }
        catch (NullPointerException ex) //app is not running, thus, its context doesn't exist
        {
            //instead of app's context, use activities context
            sInstance = new tool_db_functions(context);
            return sInstance;
        }
    }

    // Called when the database connection is being configured.
    // Configure database settings for things like foreign key support, write-ahead logging, etc.
    @Override
    public void onConfigure(SQLiteDatabase db)
    {
        super.onConfigure(db);
    }

    // Called when the database is created for the FIRST time.
    // If a database already exists on disk with the same DATABASE_NAME, this method will NOT be called.
    @Override
    public void onCreate(SQLiteDatabase db)
    {
        
        try
        {
            db.execSQL(CREATE_TABLE_LOG_CUST_DIALLED_KAARIGAR);
            db.execSQL(CREATE_TABLE_LOG_CUST_CALLED_KAARIGAR);
        }
        catch (Exception e)
        {
            throw e;
        }
    }

    // Called when the database needs to be upgraded.
    // This method will only be called if a database already exists on disk with the same DATABASE_NAME,
    // but the DATABASE_VERSION is different than the version of the database that exists on disk.
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
    {
        if (oldVersion != newVersion)
        {
            // Simplest implementation is to drop all old tables and recreate them            
            db.execSQL("DROP TABLE IF EXISTS " + TABLE_LOG_CUST_DIALLED_KAARIGAR);
            db.execSQL("DROP TABLE IF EXISTS " + TABLE_LOG_CUST_CALLED_KAARIGAR);
            onCreate(db);
        }
    }

    

    // Get all categories from the db
    public Cursor getData(String _query)
    {
        // "getReadableDatabase()" and "getWriteableDatabase()" return the same object (except under low
        // disk space scenarios)
        SQLiteDatabase db = sInstance.getReadableDatabase();
        Cursor _cursor = db.rawQuery(_query, null);
        return _cursor;
    }


    

    // Delete a log from table
    public int deleteFromLogCustCalledKaarigar(String[] _logDate)
    {
        int _rowDeleted = -1;
        SQLiteDatabase db = getWritableDatabase();
        db.beginTransaction();
        try
        {
            _rowDeleted = db.delete(TABLE_LOG_CUST_CALLED_KAARIGAR, "where logdate = ?", _logDate);
            db.setTransactionSuccessful();
        }
        catch (Exception e)
        {
            throw e;
        }
        finally
        {
            db.endTransaction();
            return _rowDeleted;
        }
    }
}


Class from where called number is checked for presence in the database
Java
public class tool_store_num_dialled_call_log
{
    //send context of one of the activities in app
    tool_db_functions _db = tool_db_functions.getInstance(new mainActivity());

    //check if the dialled number is already present in the db, if present, return true
    public String checkForDialledNumberInDb(String _dialledNumber)
    {
        Cursor _cursor;
        Log.e("Table name",_db.TABLE_LOG_CUST_DIALLED_KAARIGAR);
        Log.e("DB",_db.toString());
        _cursor = _db.getData("select count(kid) as kcount from " + _db.TABLE_LOG_CUST_DIALLED_KAARIGAR + " where kid = " + _dialledNumber);
        try
        {
            if (_cursor.moveToFirst())
            {
                if (_cursor.getString(_cursor.getColumnIndex("kcount")).equals("0"))
                    return "false";
                else if (_cursor.getString(_cursor.getColumnIndex("kcount")).equals("1"))
                    return "true";
                else
                    return "Query returned unexpected results at checkForDialledNumberInDb at tool_store_num_dialled_call_log.java";
            }
            else
                return "Unable to move cursor to the first position for checkForDialledNumberInDb at tool_store_num_dialled_call_log.java";
        }
        catch (Exception e)
        {
            return "Exception raised at checkForDialledNumberInDb at tool_store_num_dialled_call_log.java with message: " + e.getMessage();
        }
        finally
        {
            if (_cursor != null && !_cursor.isClosed())
                _cursor.close();
        }
    }



Broadcast receiver class for outgoing calls
Java
public class tool_broadcast_receiver_outgoing_call extends BroadcastReceiver
{
    @Override
    public void onReceive(Context _contex, Intent _intent)
    {
        final Bundle _bundle = _intent.getExtras();
        try
        {
            if (_bundle != null)
            {
                String _calledNumber = _bundle.getString(Intent.EXTRA_PHONE_NUMBER);

                if (_calledNumber.length() == 11)
                    _calledNumber = _calledNumber.substring(_calledNumber.length() - 10, 11);
                else if (_calledNumber.length() == 13)
                    _calledNumber = _calledNumber.substring(_calledNumber.length() - 10, 13);

                tool_store_knum_dialled_call_log _logDialledNumbers = new tool_store_knum_dialled_call_log();
                String _flag = _logDialledNumbers.checkForDialledNumberInDb(_calledNumber);
               

                if (_flag.equals("true"))   //check if called number exists in dialled calls log, if exists, save call log to db
                    saveCallLogToLocalDB(_calledNumber);
                else if (_flag.equals("error"))
                    Log.e("Error: ", "From onReceive at tool_broadcast_receiver_outgoing_call.java. Unable to check for dialled log in db at tool_store_dialled_call_log.java");
                else
                    Log.e("Error: ", "From onReceive at tool_broadcast_receiver_outgoing_call.java. " + _flag);
            }
        }
        catch (Exception e)
        {

            Log.e("Exception raised", "at onReceive at tool_broadcast_receiver_outgoing_call.java. Exception Message: " + e.getMessage());
            e.printStackTrace();
        }
    }

    private void saveCallLogToLocalDB(String _calledNumber)
    {
        tool_db_functions _db = tool_db_functions.getInstance(new KaarigarFullInfo());
        CommonGlobal _clsCommon = CommonGlobal.getInstance();

        ContentValues values = new ContentValues();
        values.put(_db.COL_LOG_CUST_CALLED_KAARIGAR[0], _calledNumber);

        if(_clsCommon._selectedSCode != -1)
            values.put(_db.COL_LOG_CUST_CALLED_KAARIGAR[1], 1291);
        values.put(_db.COL_LOG_CUST_CALLED_KAARIGAR[3], "00:3:00");
        _db.insertRow(_db.TABLE_LOG_CUST_CALLED_KAARIGAR, values);
        getDataFromDB(_db);
    }
Posted
Comments
Afzaal Ahmad Zeeshan 6-Mar-16 3:56am    
Exactly, I was also going to say that the context is null when the application is not running.

In such cases, you should pass the context of the background service; not application. Background services are typically running in the background, or when they are alarmed to run, they would have a non-null context.

How to use SQLite from Services in Android?
Member 11040029 6-Mar-16 5:39am    
yeah..but when I passed context of my activity instead of the application, object for the class is initialized. Thus, at
SQLiteDatabase db = sInstance.getReadableDatabase();
NullPointerException must not be thrown.
For confirmation, I also verified if the object is still present in memory for sInstance, and yes it exist when I initialized it with the context of mainActivity.

Thus, a null exception for SQLiteDatabase db = sInstance.getReadableDatabase(); must not be thrown.
Afzaal Ahmad Zeeshan 6-Mar-16 6:33am    
Then try to use that activity itself and not the application. What I think you should do is pass the context of the activity that uses the database, and not others. MyActivity.class would suffice.
Member 11040029 6-Mar-16 5:46am    
At the beginning, does associating the database with Application's context means that the database can be accessed only by using Application's context and not the activity's context?
Afzaal Ahmad Zeeshan 6-Mar-16 6:32am    
No, you are passing a context. You are not telling it to use this resource or another resource, you are not setting a key.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900