1

For the past three days I am unable to understand what issues are being faced. I am getting nulls for some variables and not for others, or sometimes for all. The problem is specifically being faced on Samsung Devices running Lollipop.

What I am essentially doing is storing server returned user data through SQlitehandler class in my LoginActivity and then using that data later from mainactivity. The Sqlitehandler returns nulls randomly, so I can't figure if the db is not being correctly written in LoginActivity or if there's an access issue while reading. I am posting relevant parts of the LoginActivity and SqliteHandler classes. Please need some help.

@Override
        public void onResponse(String response) {
            Log.d(TAG, "Login Response: " + response);
            hideDialog();

            try {
                JSONObject jObj = new JSONObject(response);
                boolean error = jObj.getBoolean("error");

                // Check for error node in json
                if (!error) {
                    // user successfully logged in
                    // Create login session


                    // Now store the user in SQLite
                    String api_key = jObj.getString("api_key");

                    //JSONObject user = jObj.getJSONObject("user");
                    String name = jObj.getString("name");
                    String email = jObj.getString("email");
                    int user_id = jObj.getInt("user_id");

                    JSONObject authorization = jObj.getJSONObject("authorizations");
                    int pro_app = authorization.getInt("pro_app");

                    // Inserting row in users table
                    // SQLite database handler
                    db = new SQLiteHandler(LoginActivity.this);
                    db.addUser(name, email, user_id, api_key);
                    db.addAuthorizations(pro_app);

                    // Set the log level to verbose.

                    String user_id_string = String.valueOf("user_id");
                    String pro_app_string = String.valueOf("pro_app");


                    session.setLogin(true);
                    Toast.makeText(LoginActivity.this, "You have successfully logged in! Please wait while application loads.", Toast.LENGTH_LONG).show();

                    // Launch main activity
                    Intent intent = new Intent(LoginActivity.this,
                            SplashActivity.class);
                    startActivity(intent);
                    finish();
                } else {
                    // Error in login. Get the error message

                    String errorMsg = jObj.getString("message");
                    if (errorMsg.equals("") || errorMsg.isEmpty()) {
                        errorMsg = "An unusual error occurred. Please try again";
                    }
                    Toast.makeText(getApplicationContext(),
                            errorMsg, Toast.LENGTH_LONG).show();
                }
            } catch (Exception e) {
                // JSON error
                hideDialog();
                e.printStackTrace();
                Toast.makeText(getApplicationContext(), "Json error: " + e.getMessage(), Toast.LENGTH_LONG).show();
            }

        }

Following is the SQLiteHandler:

public class SQLiteHandler extends SQLiteOpenHelper {

    private static final String TAG = SQLiteHandler.class.getSimpleName();

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

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

    // Login table name
    private static final String TABLE_USER = "user";
    private static final String TABLE_AUTH = "authorizations";

    // Login Table Columns names
    private static final String KEY_ID = "id";
    private static final String KEY_NAME = "name";
    private static final String KEY_USER_ID = "user_id";
    private static final String KEY_API = "api_key";
    private static final String KEY_PRO = "pro_app";


    public SQLiteHandler(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    // Creating Tables
    @Override
    public void onCreate(SQLiteDatabase db) {
        String CREATE_LOGIN_TABLE = "CREATE TABLE " + TABLE_USER + "("
                + KEY_ID + " INTEGER PRIMARY KEY," + KEY_NAME + " TEXT,"
                + KEY_EMAIL + " TEXT UNIQUE," + KEY_USER_ID + " INTEGER UNIQUE," + KEY_API + " TEXT" + ")";
        db.execSQL(CREATE_LOGIN_TABLE);

        String CREATE_AUTH_TABLE = "CREATE TABLE " + TABLE_AUTH + "("
                + KEY_ID + " INTEGER PRIMARY KEY," + KEY_PRO + " INTEGER"
                + ")";
        db.execSQL(CREATE_AUTH_TABLE);

        Log.d(TAG, "Database tables created");
    }

    // Upgrading database
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

        Log.d(TAG, "onUpgrade() from " + oldVersion + " to " + newVersion);

        // Drop older table if existed
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_USER);
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_AUTH);

        // Create tables again
        onCreate(db);
    }

    /**
     * Storing user details in database
     */
    public void addUser(String name, String email, int user_id, String c_code, String phone, String api_key, int status, String created_at) {
        SQLiteDatabase db = this.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(KEY_NAME, name); // Name
        values.put(KEY_EMAIL, email); // Email
        values.put(KEY_USER_ID, user_id); // Email
        values.put(KEY_API, api_key); // API

        // Inserting Row
        long id = db.insert(TABLE_USER, null, values);
        db.close(); // Closing database connection

        Log.d(TAG, "New user inserted into sqlite: " + id);
    }


    public void addAuthorizations(int pro_app, int no_ads, int pro_original) {
        SQLiteDatabase db = this.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(KEY_PRO, pro_app); // Pro version?

        // Inserting Row
        long id = db.insert(TABLE_AUTH, null, values);
        db.close(); // Closing database connection

        Log.d(TAG, "New auth inserted into sqlite: " + id);
    }

    public void updateAuthorizations(int pro_app, int no_ads, int pro_original) {
        SQLiteDatabase db = this.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(KEY_PRO, pro_app); // Pro version?
        values.put(KEY_ADS, no_ads); // No Ads?
        values.put(KEY_PRO_ORIGINAL, pro_original); //pro origin

        // Inserting Row
        db.update(TABLE_AUTH, values, "id=1", null);
        db.close(); // Closing database connection

        Log.d(TAG, "New auth updated into sqlite ");
    }


    /**
     * Getting user data from database
     */
    public HashMap<String, Object> getUserDetails() {
        HashMap<String, Object> user = new HashMap<String, Object>();
        String selectQuery = "SELECT  * FROM " + TABLE_USER;

        SQLiteDatabase db = this.getReadableDatabase();
        Cursor cursor = db.rawQuery(selectQuery, null);
        // Move to first row
        cursor.moveToFirst();
        if (cursor.getCount() > 0) {
            user.put("name", cursor.getString(1));
            user.put("email", cursor.getString(2));
            user.put("user_id", cursor.getInt(3));
            user.put("api_key", cursor.getString(4));

        }
        cursor.close();
        db.close();
        // return user
        Log.d(TAG, "Fetching user from Sqlite: " + user.toString());

        return user;
    }

    public HashMap<String, Integer> getUserAuthorizations() throws Exception{
        HashMap<String, Integer> auth = new HashMap<String, Integer>();
        String selectQuery = "SELECT  * FROM " + TABLE_AUTH;

        SQLiteDatabase db = this.getReadableDatabase();
        Cursor cursor = db.rawQuery(selectQuery, null);
        // Move to first row
        cursor.moveToFirst();
        if (cursor.getCount() > 0) {
            auth.put("pro_app", cursor.getInt(1));
        }
        cursor.close();
        db.close();
        // return user
        try {
            int authINT = auth.get("pro_app");
        } catch (Exception e){
            Crashlytics.log("this is what is throwing the error");
            Crashlytics.logException(e);
        }
        int authINTNEXT = auth.get("pro_app");


        return auth;
    }

    /**
     * Re crate database Delete all tables and create them again
     */
    public void deleteUsers() {
        SQLiteDatabase db = this.getWritableDatabase();
        // Delete All Rows
        db.delete(TABLE_USER, null, null);
        db.delete(TABLE_AUTH, null, null);
        db.close();

        Log.d(TAG, "Deleted all user info from sqlite");
    }


}

Error I am getting in Crashlytics:

Non-fatal Exception: java.lang.NullPointerException
Attempt to invoke virtual method 'int java.lang.Integer.intValue()' on a null object reference
 raw
com.blueinklabs.investifystocks.helper.SQLiteHandler.getUserAuthorizations (SourceFile:198)
com.blueinklabs.investifystocks.StorageMethod.loadDatabaseData (SourceFile:65)
com.blueinklabs.investifystocks.MainActivity.onCreate (SourceFile:183)
android.app.Activity.performCreate (Activity.java:5993)
android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1111)
android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2418)
android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:2530)
android.app.ActivityThread.access$900 (ActivityThread.java:163)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:1358)
android.os.Handler.dispatchMessage (Handler.java:102)
android.os.Looper.loop (Looper.java:135)
android.app.ActivityThread.main (ActivityThread.java:5536)
java.lang.reflect.Method.invoke (Method.java)
java.lang.reflect.Method.invoke (Method.java:372)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:1397)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1192)
Floern
  • 33,559
  • 24
  • 104
  • 119
dejavu89
  • 754
  • 1
  • 7
  • 17
  • getUserDetails() & getUserAuthorizations() are randomly giving null pointer exceptions. I even saw a case where authorizations returned an integer correctly but returned null in the email field. mind boggling. Can't even recreate myself as this is being faced on very few galaxy lollipop devices (I don't have access to one). – dejavu89 Mar 04 '16 at 07:06
  • Where is the logcat ?? – M D Mar 04 '16 at 07:07
  • added. Basically it is showing nothing as far as I understand. the SqliteHandler should return either 0 or 1 for authorization so that I can check for pro, however, it returns nothing from the database. So either it is not being written to the db correctly or it is not being retrieved correctly. Can it have to do something with the db being stored on sdcard by samsung or permissions or something? – dejavu89 Mar 04 '16 at 07:12
  • I got one issue. `user.put("user_id", cursor.getInt(3));` you start getting data as `getString(1` but Cursor will return data from position `0`. also change `auth.put("pro_app", cursor.getInt(0));` – M D Mar 04 '16 at 07:14
  • Hey! Did you solve this ? – Hardik Joshi Jul 22 '17 at 16:45

1 Answers1

2

Actually the issue is that Cursor is return data from 0 position, So that means you got record 0,1,2.. manner. Check mu code below

 /**
 * Getting user data from database
 */
public HashMap<String, Object> getUserDetails() {
    HashMap<String, Object> user = new HashMap<String, Object>();
    String selectQuery = "SELECT  * FROM " + TABLE_USER;

    SQLiteDatabase db = this.getReadableDatabase();
    Cursor cursor = db.rawQuery(selectQuery, null);
    // Move to first row
    cursor.moveToFirst();
    if (cursor.getCount() > 0) {
        user.put("name", cursor.getString(0));
        user.put("email", cursor.getString(1));
        user.put("user_id", cursor.getInt(2));
        user.put("api_key", cursor.getString(3));

    }
    cursor.close();
    db.close();
    // return user
    Log.d(TAG, "Fetching user from Sqlite: " + user.toString());

    return user;
}

public HashMap<String, Integer> getUserAuthorizations() throws Exception{
    HashMap<String, Integer> auth = new HashMap<String, Integer>();
    String selectQuery = "SELECT  * FROM " + TABLE_AUTH;

    SQLiteDatabase db = this.getReadableDatabase();
    Cursor cursor = db.rawQuery(selectQuery, null);
    // Move to first row
    cursor.moveToFirst();
    if (cursor.getCount() > 0) {
        auth.put("pro_app", cursor.getInt(0));
    }
    cursor.close();
    db.close();
    // return user
    try {
        int authINT = auth.get("pro_app");
    } catch (Exception e){
        Crashlytics.log("this is what is throwing the error");
        Crashlytics.logException(e);
    }
    int authINTNEXT = auth.get("pro_app");


    return auth;
}

Or i have another way to get Record based on Column Name as per below code

public static String getString(Cursor cursor, String fieldName, String nullValue) {
    int column = cursor.getColumnIndex(fieldName);

    if (cursor.isNull(column))
        return nullValue;
    else
        return cursor.getString(column);
}

public static int getInt(Cursor cursor, String fieldName, int nullValue) {
    int column = cursor.getColumnIndex(fieldName);

    if (cursor.isNull(column))
        return nullValue;
    else
        return cursor.getInt(column);
}

and implement like

public HashMap<String, Object> getUserDetails() {
    HashMap<String, Object> user = new HashMap<String, Object>();
    String selectQuery = "SELECT  * FROM " + TABLE_USER;

    SQLiteDatabase db = this.getReadableDatabase();
    Cursor cursor = db.rawQuery(selectQuery, null);
    // Move to first row
    cursor.moveToFirst();
    if (cursor.getCount() > 0) {
        user.put("name", getString(cursor , NAME_COLUMN, ""));
        user.put("email", getString(cursor , EMAIL_COLUMN, ""));
        user.put("user_id", getInt(cursor ,USER_ID_COLUMN,0));
        user.put("api_key",getString(cursor , API_KEY_COLUMN, ""));

    }
    cursor.close();
    db.close();
    // return user
    Log.d(TAG, "Fetching user from Sqlite: " + user.toString());

    return user;
}

and do for other method

M D
  • 47,665
  • 9
  • 93
  • 114
  • Actually 0 is for the Primary ID key which I don't use as such. However, I just realised that I have not initiated the table to autoincrement the primary key and I am not putting any primary key value at the time of adding the user or the authorization. Can you comment if this might be the case. thanks for the lead. – dejavu89 Mar 04 '16 at 07:22
  • 1
    @dejavu89 Ok then you should change `String selectQuery = "SELECT COLUMN Name that you wants FROM " + TABLE_AUTH;`. never use `*` every time becoz it will get all the record and takes some times too – M D Mar 04 '16 at 07:24
  • 1
    Thanks, I'll keep that in mind. But do you think not initiating a primary key is the essential problem here? (I did not add autoincrement neither am i adding the primary key on row creation) – dejavu89 Mar 04 '16 at 07:28
  • 1
    @dejavu89 No Primary Key is not an issue. id will automatically increased by 1 when records added in Table – M D Mar 04 '16 at 07:28
  • 1
    I'll implement what you mentioned (and will mark as answer if it works) but for the sake of learning / understanding, what is causing the null pointer? even if I am calling through * it should not be a problem (its only happening on samsung lollipop devices). Further, I only add one row to both the tables at the time of the login so there aren't multiple rows. Your perspective would really help man :) – dejavu89 Mar 04 '16 at 07:38
  • @dejavu89 As per my aspect this will fine with Lollipop. I don't thing any issue but yes you can manage the Open and Close DB at properly. Android > 5.0 will more secure. You should take care about all the situation – M D Mar 04 '16 at 07:44
  • Hi, but I am getting errors from multiple Samsung devices – dejavu89 Mar 04 '16 at 08:08