-3

I'm running into an issue whereby clicking the concreteIn button causes the app to crash.

The code below is from the MaterialsIn class.

package com.example.android.gatekeeper;

import android.content.Intent;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

import com.example.android.gatekeeper.gateData.DbAccess;

import static com.example.android.gatekeeper.MaterialsOut.REQUEST_IMAGE_CAPTURE;


public class MaterialsIn extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_materials_in);

        // Find the (@Concrete) button.
        Button concreteIn = (Button) findViewById(R.id.concrete_in);

        // Set a click listener on that View
        concreteIn.setOnClickListener(new View.OnClickListener() {
            // The code in this method will be executed when the Concrete In button is clicked on.
            @Override
            public void onClick(View view) {
                DbAccess db = new DbAccess();
                db.insertConcreteIn();
                Intent takePicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                if (takePicture.resolveActivity(getPackageManager()) != null) {
                    startActivityForResult(takePicture, REQUEST_IMAGE_CAPTURE);
                }
            }
        });
    }
}

When the insertConcreteIn() method is called, the app crashes at getWritableDatabase().

package com.example.android.gatekeeper.gateData;

import android.content.ContentValues;
import android.database.sqlite.SQLiteDatabase;
import android.support.v7.app.AppCompatActivity;

import com.example.android.gatekeeper.gateData.Contract.GateEntry;


public class DbAccess extends AppCompatActivity {

    // To access our database, we instantiate our subclass of SQLiteOpenHelper
    // and pass the context, which is the current activity.
    DbHelper mDbHelper = new DbHelper(this);

    // Insert data corresponding to the concrete in to the database.
    public void insertConcreteIn() {

        // Gets the data repository in write mode.
        SQLiteDatabase SQLiteDb = mDbHelper.getWritableDatabase();

        // Create a new map of values, where column names are the keys.
        ContentValues values = new ContentValues();
        values.put(GateEntry.COLUMN_DIRECTION, "To Site");
        values.put(GateEntry.COLUMN_TYPE, "Concrete");
        values.put(GateEntry.COLUMN_DATE, 170303); // Placeholder int for now.
        values.put(GateEntry.COLUMN_TIME, 171930); // Placeholder int for now.

        // Insert the new row, returning the primary key value of the new row.
        long newRowId = SQLiteDb.insert(GateEntry.TABLE_NAME, null, values);
    }
}

The logcat is the following;

03-19 19:58:08.190 24751-24751/com.example.android.gatekeeper E/AndroidRuntime: FATAL EXCEPTION: main
                                                                                Process: com.example.android.gatekeeper, PID: 24751
                                                                                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)' on a null object reference
                                                                                    at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:283)
                                                                                    at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:223)
                                                                                    at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163)
                                                                                    at com.example.android.gatekeeper.gateData.DbAccess.insertConcreteIn(DbAccess.java:20)
                                                                                    at com.example.android.gatekeeper.MaterialsIn$1.onClick(MaterialsIn.java:34)
                                                                                    at android.view.View.performClick(View.java:5702)
                                                                                    at android.widget.TextView.performClick(TextView.java:10888)
                                                                                    at android.view.View$PerformClick.run(View.java:22541)
                                                                                    at android.os.Handler.handleCallback(Handler.java:739)
                                                                                    at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                                    at android.os.Looper.loop(Looper.java:158)
                                                                                    at android.app.ActivityThread.main(ActivityThread.java:7229)
                                                                                    at java.lang.reflect.Method.invoke(Native Method)
                                                                                    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
                                                                                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
03-19 19:58:08.190 3464-5216/? W/ActivityManager:   Force finishing activity com.example.android.gatekeeper/.MaterialsIn

Any help here would be appreciated.

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
  • 3
    There is a bug in your code. You need to fix it. – ajb Mar 19 '17 at 20:04
  • 1
    provide your code if you want help. Also, consider reading the documentation on how to ask good questions. – Ousmane D. Mar 19 '17 at 20:05
  • You code shows lack of understanding how intents/activities work in Android. Start here https://developer.android.com/training/index.html – Eugen Pechanec Mar 19 '17 at 20:28
  • I think you should look into extending [AsyncTask](https://developer.android.com/reference/android/os/AsyncTask.html) for your DbAccess instead. – Sammy T Mar 19 '17 at 20:28

1 Answers1

1

The problem is that you're passing an invalid Context to SQLiteOpenHelper constructor. That is because of

DbAccess db = new DbAccess();

and

public class DbAccess extends AppCompatActivity

Never instantiate Activity classes yourself. Such instances are not suitable for anything you'd want an activity for, such as to be used as a Context.

Instead, pass a valid Context set up by the framework to methods that need it.

laalto
  • 150,114
  • 66
  • 286
  • 303
  • Second problem is `new DbHelper(this)`. (Hint: Your activity name should end in `Activity`, even you can't follow this mess.) The activity is not fully setup in the constructor. Every instantiation that takes an activity (or context) as a parameter should happen no sooner than in `onCreate`. – Eugen Pechanec Mar 19 '17 at 20:24
  • 1
    @EugenPechanec Generally yes but in `SQLiteOpenHelper`'s case the `Context` is only used at time of `get{Read,Writ}ableDatabase()` (not in constructor) – laalto Mar 19 '17 at 20:28
  • @IaaIto Thanks for the answer. I don't properly understand how to use `Context` yet, I'm fairly new to programming. How do I pass in a valid `Context` in this case? If I can't instantiate `DbAccess` from `MaterialsIn` then how can I call the `insertConcreteIn()` method? –  Mar 21 '17 at 20:53