-1

my app is displaying various text fields, date and time pickers and, most important, an image button. The image button has his own sql database whereas the text fields, date and time pickers are stored in another sql database.

When you click on the image button you can chose to go to the gallery. My question is: Why is my app crashing after clicking on one of the images in the gallery. There must be a problem with the onActivityResult method but I can´t figure it out. What is wrong with my app and how can I make it work?

Here is the code of my activity:

public class ReminderEditActivity extends Activity {

//
// Private instance variables
//
private Button mDateButton;
private Calendar mCalendar;
private Button mTimeButton;
private EditText mTitleText;
private EditText mBodyText;
private Button mConfirmButton;

private RemindersDbAdapter mDbHelper;
private ImageAdapter mImageHelper;

private Long mRowId;
private Long mImageRowId;

private ImageButton mImageButton;

private Uri mImageCaptureUri;

public String imageFilePath;


//
// Private constants
//
private static final int DATE_PICKER_DIALOG = 0;
private static final int TIME_PICKER_DIALOG = 1;
private static final String DATE_FORMAT = "dd-MM-yyyy";
private static final String TIME_FORMAT = "kk:mm";

public static final String DATE_TIME_FORMAT = "dd-MM-yyyy kk:mm:ss";

private static final int PICK_FROM_CAMERA = 1;
private static final int PICK_FROM_FILE = 2;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Instantiate mDbHelper and mImageHelper
    mDbHelper = new RemindersDbAdapter(this);
    mImageHelper = new ImageAdapter(this);

    setContentView(R.layout.reminder_edit);

    //
    // Instantiate instance variables
    //
    mTimeButton = (Button)findViewById(R.id.reminder_time);
    mCalendar = Calendar.getInstance();
    mDateButton = (Button)findViewById(R.id.reminder_date);
    mConfirmButton = (Button)findViewById(R.id.confirm);
    mTitleText = (EditText)findViewById(R.id.title);
    mBodyText = (EditText)findViewById(R.id.body);

    mImageButton =(ImageButton)findViewById(R.id.image);

    //Checks whether mRowId contains any values.
    mRowId = savedInstanceState != null ? savedInstanceState.getLong(RemindersDbAdapter.KEY_ROWID) : null;
    //mImageRowId = savedInstanceState != null ? savedInstanceState.getLong(ImageAdapter.KEY_ROWID) : null;

    registerButtonListenerandSetDefaultText();
}

//
// Sets the row id from the intent. If mRowId is null its content is null.
//
private void setRowIdFromIntent() {
    if(mRowId == null) {
        Bundle extras = getIntent().getExtras();
        mRowId = extras != null ? extras.getLong(RemindersDbAdapter.KEY_ROWID) : null;
    }
}

//
// Executed on pause.
//
@Override
protected void onPause() {
    super.onPause();
    mDbHelper.close();
    mImageHelper.close();
}

//
// Executed on resume
//
@Override
protected void onResume() {
    super.onResume();
    mDbHelper.open();
    mImageHelper.open();
    setRowIdFromIntent();
    populateFields();
    populateImageField();
}

//
// Register the Date, Time and Save Button and set the default text
//
private void registerButtonListenerandSetDefaultText() {

    mDateButton.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            showDialog(DATE_PICKER_DIALOG); 
        }
    });

    mTimeButton.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            showDialog(TIME_PICKER_DIALOG);
        }
    });

    mConfirmButton.setOnClickListener(new View.OnClickListener() {
        public void onClick(View view) {
            saveState();
            setResult(RESULT_OK);
            Toast.makeText(ReminderEditActivity.this, getString(R.string.task_saved_message), Toast.LENGTH_SHORT).show();
            finish();
        }
    }); 

    mImageButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            showImageDialog();
        }
    });

    updateDateButtonText();
    updateTimeButtonText(); 
}


private void showImageDialog() {
    final String [] items = new String [] {"From Camera", "From SD Card"};
    ArrayAdapter<String> adapter = new ArrayAdapter<String> (this, android.R.layout.select_dialog_item,items);
    AlertDialog.Builder builder = new AlertDialog.Builder(this);

    builder.setTitle("Select Image");
    builder.setAdapter( adapter, new DialogInterface.OnClickListener() {
        public void onClick( DialogInterface dialog, int item ) {
            if (item == 0) {
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                File file = new File(Environment.getExternalStorageDirectory(),
                                    "tmp_avatar_" + String.valueOf(System.currentTimeMillis()) + ".jpg");
                mImageCaptureUri = Uri.fromFile(file);

                try {
                    intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, mImageCaptureUri);
                    intent.putExtra("return-data", true);

                    startActivityForResult(intent, PICK_FROM_CAMERA);
                } catch (Exception e) {
                    e.printStackTrace();
                }

                dialog.cancel();
            } else {
                Intent intent = new Intent();

                intent.setType("image/*");
                intent.setAction(Intent.ACTION_GET_CONTENT);

                startActivityForResult(Intent.createChooser(intent, "Complete action using"), PICK_FROM_FILE);
            }
        }
    } );

    final AlertDialog dialog = builder.create();
    dialog.show();
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
       if(requestCode == PICK_FROM_FILE && data != null && data.getData() != null) {
           Uri uri = data.getData();
           if(uri != null) {
              Cursor cursor = getContentResolver().query(uri, new String[] {   
                                       android.provider.MediaStore.Images.ImageColumns.DATA}, 
                                       null, null, null);
                    cursor.moveToFirst();
                    String imagePath = cursor.getString(0);             
                    cursor.close();

                    if(imagePath != null) {
                        // Save the image to the database
                        long id = mImageHelper.createImage(imagePath);
                        if (id > 0) {
                            mRowId = id;
                        } 
                        // Set the image and display it in the edit activity
                        Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
                        mImageButton.setImageBitmap(bitmap);
                        }
           }
       }
    }


//
// If mRowId is not null (it contains value and we want to edit the task)
// this method is called.
//
private void populateFields() {
    if (mRowId != null) {
        Cursor reminder = mDbHelper.fetchReminder(mRowId);
        startManagingCursor(reminder);
        mTitleText.setText(reminder.getString(reminder.getColumnIndexOrThrow(RemindersDbAdapter.KEY_TITLE)));
        mBodyText.setText(reminder.getString(reminder.getColumnIndexOrThrow(RemindersDbAdapter.KEY_BODY)));


        SimpleDateFormat dateTimeFormat = new SimpleDateFormat(DATE_TIME_FORMAT);
        Date date = null;
        try {
            String dateString = reminder.getString(reminder.getColumnIndexOrThrow(RemindersDbAdapter.KEY_DATE_TIME));
            date = dateTimeFormat.parse(dateString);
            mCalendar.setTime(date);
        } catch (ParseException e) {
            Log.e("ReminderEditActivity", e.getMessage(), e);
        }
    } 

    updateDateButtonText();
    updateTimeButtonText();
}

private void populateImageField() {
    if (mImageRowId != null) {
        Cursor reminderImage = mImageHelper.fetchImage(mImageRowId);
        startManagingCursor(reminderImage);
        String imagePath = reminderImage.getString(reminderImage.getColumnIndexOrThrow(ImageAdapter.KEY_IMAGE));

        Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
        mImageButton.setImageBitmap(bitmap);

    }
} 


//
// Saves the state so that it can be restored.
//
@Override
protected void onSaveInstanceState(Bundle outState) {

    outState.putLong(RemindersDbAdapter.KEY_ROWID, mRowId);
    super.onSaveInstanceState(outState);
}

//
// Saves the content by communicating with the RemindersDbAdapter.
//
private void saveState() {
    String title = mTitleText.getText().toString();
    String body = mBodyText.getText().toString();

    SimpleDateFormat dateTimeFormat = new SimpleDateFormat(DATE_TIME_FORMAT);
    String reminderDateTime = dateTimeFormat.format(mCalendar.getTime());

    // Creates a new reminder if the value is null.
    if (mRowId == null) {
        long id = mDbHelper.createReminder(title, body, reminderDateTime);
        if (id > 0) {
            mRowId = id;

        } 
    // Updates the reminder if the content is not null.     
    } else {
        mDbHelper.updateReminder(mRowId, title, body, reminderDateTime);
    }
}

//
// Opens up an alert dialog box and asks the user if he wants to discard his task.
//
@Override
public void onBackPressed() {
    AlertDialog.Builder builder = new AlertDialog.Builder(ReminderEditActivity.this);
    builder.setMessage("Are you sure you want to discard your task?");
            builder.setTitle("Are you sure?");
            builder.setCancelable(false);
            builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int id) {
                    Intent j = new Intent(((Dialog)dialog).getContext(), ReminderListActivity.class);
                    startActivity(j);
                    return;

                }
            });

            builder.setNegativeButton("No", new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int id) {
                    dialog.cancel();

                }
            });
            builder.create().show();        
}

//
// When creating a dialog box, it either shows up a date or time picker.
//
@Override
protected Dialog onCreateDialog(int id) {
    switch (id) {
        case DATE_PICKER_DIALOG:
            return showDatePicker();
        case TIME_PICKER_DIALOG:
            return showTimePicker();
    }
    return super.onCreateDialog(id);
}

//
// Creates the date picker dialog box.
//
private DatePickerDialog showDatePicker() {
    DatePickerDialog datePicker = new DatePickerDialog(ReminderEditActivity.this, new DatePickerDialog.OnDateSetListener() {

        @Override
        public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
            mCalendar.set(Calendar.YEAR, year);
            mCalendar.set(Calendar.MONTH, monthOfYear);
            mCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
            updateDateButtonText();
        }
    }, mCalendar.get(Calendar.YEAR), mCalendar.get(Calendar.MONTH), mCalendar.get(Calendar.DAY_OF_MONTH));
    return datePicker;
}

//
// Creates the time picker dialog box.
//
private TimePickerDialog showTimePicker() {
    TimePickerDialog timePicker = new TimePickerDialog(ReminderEditActivity.this, new TimePickerDialog.OnTimeSetListener() {

        @Override
        public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
            mCalendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
            mCalendar.set(Calendar.MINUTE, minute);
            updateTimeButtonText();
        }
    }, mCalendar.get(Calendar.HOUR_OF_DAY), mCalendar.get(Calendar.MINUTE), true);
    return timePicker;
}

//
// Updates the Date Button text.
//
private void updateDateButtonText() {
    SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
    String dateForButton = dateFormat.format(mCalendar.getTime());
    mDateButton.setText(dateForButton);
}

//
// Updates the Time Button text.
//
private void updateTimeButtonText() {
    SimpleDateFormat timeFormat = new SimpleDateFormat(TIME_FORMAT);
    String timeForButton = timeFormat.format(mCalendar.getTime());
    mTimeButton.setText(timeForButton);
}

}

This is my database for the Image:

public class ImageAdapter {

//
// Database Related Constants
//
private static final String DATABASE_NAME = "dataImage";
private static final String DATABASE_TABLE = "remindersImage";
private static final int DATABASE_VERSION = 3;

public static final String KEY_IMAGE = "image";
public static final String KEY_ROWID = "_id";


private static final String TAG = "ImageAdapter";
private DatabaseHelper mImageHelper;
private SQLiteDatabase mImageDb;

/**
 * Database creation SQL statement
 */
private static final String DATABASE_CREATE =
        "create table " + DATABASE_TABLE + " ("
                + KEY_IMAGE + " integer primary key autoincrement);";



private final Context mImageCtx;

private static class DatabaseHelper extends SQLiteOpenHelper {

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

    @Override
    public void onCreate(SQLiteDatabase db) {

        db.execSQL(DATABASE_CREATE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
                + newVersion + ", which will destroy all old data");
        db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE);
        onCreate(db);
    }
}

/**
 * Constructor - takes the context to allow the database to be
 * opened/created
 * 
 * @param ctx the Context within which to work
 */
public ImageAdapter(Context ctx) {
    this.mImageCtx = ctx;
}

/**
 * Open the database. If it cannot be opened, try to create a new
 * instance of the database. If it cannot be created, throw an exception to
 * signal the failure
 * 
 * @return this (self reference, allowing this to be chained in an
 *         initialization call)
 * @throws SQLException if the database could be neither opened or created
 */
public ImageAdapter open() throws SQLException {
    mImageHelper = new DatabaseHelper(mImageCtx);
    mImageDb = mImageHelper.getWritableDatabase();
    return this;
}

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


// Create new image entry
public long createImage(String image) {
    ContentValues initialValues = new ContentValues();
    initialValues.put(KEY_IMAGE, image);


    return mImageDb.insert(DATABASE_TABLE, null, initialValues);
}

// Delete image.
public boolean deleteImage(long rowId) {

    return mImageDb.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null) > 0;
}



public Cursor fetchAllImages() {

    return mImageDb.query(DATABASE_TABLE, new String[] {KEY_ROWID, KEY_IMAGE}, null, null, null, null, null);
}



public Cursor fetchImage(long rowId) throws SQLException {

    Cursor mCursor =

            mImageDb.query(true, DATABASE_TABLE, new String[] {KEY_ROWID,
                    KEY_IMAGE}, KEY_ROWID + "=" + rowId, null,
                    null, null, null, null);
    if (mCursor != null) {
        mCursor.moveToFirst();
    }
    return mCursor;

}


public boolean updateImages(long rowId, String image) {
    ContentValues args = new ContentValues();
    args.put(KEY_IMAGE, image);

    return mImageDb.update(DATABASE_TABLE, args, KEY_ROWID + "=" + rowId, null) > 0;
}
}

This is the LogCat:

05-31 00:16:14.372: E/ActivityThread(528): Activity com.android.internal.app.ChooserActivity has leaked IntentReceiver com.android.internal.app.ResolverActivity$1@4155fa60 that was originally registered here. Are you missing a call to unregisterReceiver()?
05-31 00:16:14.372: E/ActivityThread(528): android.app.IntentReceiverLeaked: Activity com.android.internal.app.ChooserActivity has leaked IntentReceiver com.android.internal.app.ResolverActivity$1@4155fa60 that was originally registered here. Are you missing a call to unregisterReceiver()?
05-31 00:16:14.372: E/ActivityThread(528):  at android.app.LoadedApk$ReceiverDispatcher.<init>(LoadedApk.java:763)
05-31 00:16:14.372: E/ActivityThread(528):  at android.app.LoadedApk.getReceiverDispatcher(LoadedApk.java:567)
05-31 00:16:14.372: E/ActivityThread(528):  at android.app.ContextImpl.registerReceiverInternal(ContextImpl.java:1043)
05-31 00:16:14.372: E/ActivityThread(528):  at android.app.ContextImpl.registerReceiver(ContextImpl.java:1030)
05-31 00:16:14.372: E/ActivityThread(528):  at android.app.ContextImpl.registerReceiver(ContextImpl.java:1024)
05-31 00:16:14.372: E/ActivityThread(528):  at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:341)
05-31 00:16:14.372: E/ActivityThread(528):  at com.android.internal.content.PackageMonitor.register(PackageMonitor.java:65)
05-31 00:16:14.372: E/ActivityThread(528):  at com.android.internal.app.ResolverActivity.onCreate(ResolverActivity.java:99)
05-31 00:16:14.372: E/ActivityThread(528):  at com.android.internal.app.ChooserActivity.onCreate(ChooserActivity.java:53)
05-31 00:16:14.372: E/ActivityThread(528):  at android.app.Activity.performCreate(Activity.java:4465)
05-31 00:16:14.372: E/ActivityThread(528):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
05-31 00:16:14.372: E/ActivityThread(528):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920)
05-31 00:16:14.372: E/ActivityThread(528):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
05-31 00:16:14.372: E/ActivityThread(528):  at android.app.ActivityThread.access$600(ActivityThread.java:123)
05-31 00:16:14.372: E/ActivityThread(528):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
05-31 00:16:14.372: E/ActivityThread(528):  at android.os.Handler.dispatchMessage(Handler.java:99)
05-31 00:16:14.372: E/ActivityThread(528):  at android.os.Looper.loop(Looper.java:137)
05-31 00:16:14.372: E/ActivityThread(528):  at android.app.ActivityThread.main(ActivityThread.java:4424)
05-31 00:16:14.372: E/ActivityThread(528):  at java.lang.reflect.Method.invokeNative(Native Method)
05-31 00:16:14.372: E/ActivityThread(528):  at java.lang.reflect.Method.invoke(Method.java:511)
05-31 00:16:14.372: E/ActivityThread(528):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
05-31 00:16:14.372: E/ActivityThread(528):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
05-31 00:16:14.372: E/ActivityThread(528):  at dalvik.system.NativeStart.main(Native Method)
05-31 00:16:17.051: D/AndroidRuntime(528): Shutting down VM
05-31 00:16:17.061: W/dalvikvm(528): threadid=1: thread exiting with uncaught exception (group=0x409c01f8)
05-31 00:16:17.102: E/AndroidRuntime(528): FATAL EXCEPTION: main
05-31 00:16:17.102: E/AndroidRuntime(528): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=2, result=-1, data=Intent { dat=content://media/external/images/media/22 }} to activity {com.ndroidstudios.android.taskreminder/com.ndroidstudios.android.taskreminder.ReminderEditActivity}: java.lang.NullPointerException
05-31 00:16:17.102: E/AndroidRuntime(528):  at android.app.ActivityThread.deliverResults(ActivityThread.java:2980)
05-31 00:16:17.102: E/AndroidRuntime(528):  at android.app.ActivityThread.handleSendResult(ActivityThread.java:3023)
05-31 00:16:17.102: E/AndroidRuntime(528):  at android.app.ActivityThread.access$1100(ActivityThread.java:123)
05-31 00:16:17.102: E/AndroidRuntime(528):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1177)
05-31 00:16:17.102: E/AndroidRuntime(528):  at android.os.Handler.dispatchMessage(Handler.java:99)
05-31 00:16:17.102: E/AndroidRuntime(528):  at android.os.Looper.loop(Looper.java:137)
05-31 00:16:17.102: E/AndroidRuntime(528):  at android.app.ActivityThread.main(ActivityThread.java:4424)
05-31 00:16:17.102: E/AndroidRuntime(528):  at java.lang.reflect.Method.invokeNative(Native Method)
05-31 00:16:17.102: E/AndroidRuntime(528):  at java.lang.reflect.Method.invoke(Method.java:511)
05-31 00:16:17.102: E/AndroidRuntime(528):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
05-31 00:16:17.102: E/AndroidRuntime(528):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
05-31 00:16:17.102: E/AndroidRuntime(528):  at dalvik.system.NativeStart.main(Native Method)
05-31 00:16:17.102: E/AndroidRuntime(528): Caused by: java.lang.NullPointerException
05-31 00:16:17.102: E/AndroidRuntime(528):  at android.database.sqlite.SQLiteStatement.releaseAndUnlock(SQLiteStatement.java:290)
05-31 00:16:17.102: E/AndroidRuntime(528):  at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:115)
05-31 00:16:17.102: E/AndroidRuntime(528):  at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1718)
05-31 00:16:17.102: E/AndroidRuntime(528):  at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1591)
05-31 00:16:17.102: E/AndroidRuntime(528):  at com.ndroidstudios.android.taskreminder.ImageAdapter.createImage(ImageAdapter.java:113)
05-31 00:16:17.102: E/AndroidRuntime(528):  at com.ndroidstudios.android.taskreminder.ReminderEditActivity.onActivityResult(ReminderEditActivity.java:232)
05-31 00:16:17.102: E/AndroidRuntime(528):  at android.app.Activity.dispatchActivityResult(Activity.java:4649)
05-31 00:16:17.102: E/AndroidRuntime(528):  at android.app.ActivityThread.deliverResults(ActivityThread.java:2976)
05-31 00:16:17.102: E/AndroidRuntime(528):  ... 11 more
  • Is the null pointer exception happening on this line: return mImageDb.insert(DATABASE_TABLE, null, initialValues); If so, has mImageDb actually been initialized (ie was "open" ever called on the adapter?) – Glenn May 30 '12 at 22:49
  • Storing images in to database is not advisable, please visit my [answer](http://stackoverflow.com/a/9141116/996493), it may help you :) – Lucifer May 31 '12 at 02:49

1 Answers1

0

I think you database create statement is wrong... At the moment, you are trying to store a string in an integer column, and that integer column is even marked as autoincrement.

private static final String DATABASE_CREATE = "create table " + DATABASE_TABLE + " (" + KEY_IMAGE + " integer primary key autoincrement);";

KEY_ROWID is not included in the statement, and is probably the column you want as primary key. And KEY_IMAGE must be a column of strings, if you want to store strings there.

Try it like this

private static final String DATABASE_CREATE = "CREATE TABLE IF NOT EXISTS " + DATABASE_TABLE +   " (" + KEY_ROWID + " integer primary key autoincrement, " + KEY_IMAGE + " text not null);";

Remember to a clear data, or upgrade database version, after altering the create statement.

Ole
  • 7,899
  • 2
  • 29
  • 34