【问题标题】:Android NPE when trying to insert data in SQLite database after user input用户输入后尝试在 SQLite 数据库中插入数据时的 Android NPE
【发布时间】:2015-06-07 13:51:02
【问题描述】:

我有一个片段可以扩展三个EditText 视图的布局。收集用户的输入后,我想将该数据保存到我的 SQLite 数据库中。保存按钮位于选项菜单上,由调用片段的同一个 Activity 扩展。

当我尝试将数据保存到我的数据库时,我得到以下 NPE,

NullPointerException: Attempt to invoke virtual method 'android.text.Editable android.widget.EditText.getText()' on a null object reference

即使当我单击“保存”时所有三个字段都已填充有效数据。

我也很困惑我的 Fragment 与 Activity 中的逻辑应该是什么,目前所有的逻辑都在 Activity 中,而 Fragment 实际上只是扩展了布局。

编辑活动

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();
        }
    }

编辑片段

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);
    }

任务表控制器

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;
    }
}

我正在调用insertRow,它被insertNewTask 中的OnOptionsItemSelected 包裹在Activity 中,此时NPE 被抛出并且我的Toast 都没有显示。为什么即使在所有三个字段都填充了数据之后,我仍然得到一个空对象引用?有没有更好的模式可以遵循?现在我的片段不包含任何逻辑。

【问题讨论】:

    标签: android sqlite android-fragments google-tasks-api


    【解决方案1】:

    而不是从 Fragment 中检索视图,而是定义 Activity 可以调用的方法。示例:

    在 onCreate() 中:

    MyFragment myf = (MyFragment) getSupportFragmentManager().findFragmentById(R.id.yourid);
    

    当您需要时:

    myf.getValueFoo();
    myf.getValueBar();
    

    等等

    【讨论】:

    • 所以基本上,这些值是空的,因为我一直在调用 getText() 而没有引用作为我的片段布局一部分的特定 EditText 小部件?
    • 是的,我认为这是问题
    猜你喜欢
    • 1970-01-01
    • 2011-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多