I have an fragment that inflates a layout of three EditText
views. After collecting the user's input I want to save that data to my SQLite database. The Save button is located on the options menu and is inflated by the same Activity that calls the fragment.
When I try to save the data to my database, I get the following NPE,
NullPointerException: Attempt to invoke virtual method 'android.text.Editable android.widget.EditText.getText()' on a null object reference
even though all three fields have been filled with valid data when I click Save.
I'm also confused as to what logic should be in my Fragment vs the Activity, currently all of the logic is in the Activity and the fragment really just inflates a layout.
EditActivity
public class EditActivity extends ActionBarActivity implements DatePickerDialog.OnDateSetListener{
EditText mTitleText;
EditText mDueDate;
EditText mTaskNotes;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_edit, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
switch (item.getItemId()) {
case R.id.action_settings:
return true;
case R.id.action_save:
insertNewTask(findViewById(R.id.task_title));
return true;
case R.id.action_delete:
startActivity(new Intent(this, MainActivity.class));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onDateSet(DatePicker view, int year, int month, int day) {
//do some stuff for example write on log and update TextField on activity
String myFormat = "MM/dd/yy"; //In which you need put here
SimpleDateFormat sdf = new SimpleDateFormat(myFormat, Locale.US);
Calendar calendar = Calendar.getInstance();
calendar.set(year, month, day);
((EditText) findViewById(R.id.task_due_date)).setText(sdf.format(calendar.getTime()));
}
public void showDatePickerDialog(View v) {
DialogFragment newFragment = new DatePickerFragment();
newFragment.show(getFragmentManager(), "datePicker");
}
private void insertNewTask(View view) {
Task task = new Task();
//TODO this is horribles and only for test
task.setId("TaskId" + Math.random());
mTitleText = ((EditText) view.findViewById(R.id.task_title));
mDueDate = ((EditText) view.findViewById(R.id.task_due_date));
mTaskNotes = ((EditText) view.findViewById(R.id.task_notes));
task.setTitle(mTitleText.getText().toString());
//Holy Shit do the date dance.
try {
SimpleDateFormat sdf = new SimpleDateFormat();
Date taskDueDate = sdf.parse(mDueDate.getText().toString());
DateTime googleDate = new DateTime(taskDueDate);
task.setDue(googleDate);
} catch (ParseException ex) {
Logger.getLogger("EDITFRAGMENT").log(Level.SEVERE, null, ex);
}
task.setNotes(mTaskNotes.getText().toString());
boolean insertSuccess = new TaskTableController(this).insertRow(task);
if(insertSuccess){
Toast.makeText(this, "Task information was saved.", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(this, "Unable to save task information.", Toast.LENGTH_SHORT).show();
}
}
EditFragment
public class EditFragment extends Fragment {
public EditFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_edit, container, false);
}
TaskTableController
public class TaskTableController extends TaskDbHelper {
public TaskTableController(Context context) {
super(context);
}
/***
*
* @param task
* @return
*/
public boolean insertRow(Task task) {
ContentValues values = new ContentValues();
values.put("_id",task.getId());
values.put("title",task.getTitle());
values.put("due", task.getDue().toString());
values.put("notes", task.getNotes());
SQLiteDatabase db = this.getWritableDatabase();
boolean createSuccessful = db.insert(TaskContract.TaskEntry.TABLE_NAME, null, values) > 0;
db.close();
return createSuccessful;
}
}
I'm calling insertRow
which is wrapped by insertNewTask
from OnOptionsItemSelected
in the Activity at which point the NPE is thrown and neither of my Toasts is ever displayed. Why am I getting a null object reference even after all three fields have been populated with data? And is there a better pattern to follow? right now my fragment doesn't contain any logic.
Instead to retrieve the view from Fragment, define methods the activity can call. Example:
in onCreate():
and when you need:
and so on