我试图通过示例操作 Google 已经编写的代码来学习 android 平台。我一直在编辑记事本示例,并在笔记本身中添加了一些新项目,现在正试图让它保存。它似乎没有问题,直到它尝试将值输入数据库以保存它似乎,但作为一个新手,我很难指出该位置。下面我决定从 NoteEditor.java 文件中复制我的代码:
public class NoteEditor extends Activity {
private static final String TAG = "NoteEditor";
/**
* Standard projection for the interesting columns of a normal note.
*/
private static final String[] PROJECTION = new String[] {
NoteColumns._ID, // 0
NoteColumns.NOTE, // 1
NoteColumns.TITLE, // 2
//NoteColumns.DATE, //3
//NoteColumns.TIME, //4
//NoteColumns.CHOICE, //5
};
/** The index of the note column */
private static final int COLUMN_INDEX_NOTE = 1;
/** The index of the title column */
private static final int COLUMN_INDEX_TITLE = 2;
// This is our state data that is stored when freezing.
private static final String ORIGINAL_CONTENT = "origContent";
// The different distinct states the activity can be run in.
private static final int STATE_EDIT = 0;
private static final int STATE_INSERT = 1;
private int mState;
private Uri mUri;
private Cursor mCursor;
private DatePicker mPicker;
private TimePicker mTime;
private Spinner mChoice;
private EditText mText;
private String mOriginalContent;
/**
* A custom EditText that draws lines between each line of text that is displayed.
*/
public static class LinedEditText extends EditText {
private Rect mRect;
private Paint mPaint;
// we need this constructor for LayoutInflater
public LinedEditText(Context context, AttributeSet attrs) {
super(context, attrs);
mRect = new Rect();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(0x800000FF);
}
@Override
protected void onDraw(Canvas canvas) {
int count = getLineCount();
Rect r = mRect;
Paint paint = mPaint;
for (int i = 0; i < count; i++) {
int baseline = getLineBounds(i, r);
canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, paint);
}
super.onDraw(canvas);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Intent intent = getIntent();
// Do some setup based on the action being performed.
final String action = intent.getAction();
if (Intent.ACTION_EDIT.equals(action)) {
// Requested to edit: set that state, and the data being edited.
mState = STATE_EDIT;
mUri = intent.getData();
} else if (Intent.ACTION_INSERT.equals(action)) {
// Requested to insert: set that state, and create a new entry
// in the container.
mState = STATE_INSERT;
mUri = getContentResolver().insert(intent.getData(), null);
// If we were unable to create a new note, then just finish
// this activity. A RESULT_CANCELED will be sent back to the
// original activity if they requested a result.
if (mUri == null) {
Log.e(TAG, "Failed to insert new project into " + getIntent().getData());
finish();
return;
}
// The new entry was created, so assume all will end well and
// set the result to be returned.
setResult(RESULT_OK, (new Intent()).setAction(mUri.toString()));
} else {
// Whoops, unknown action! Bail.
Log.e(TAG, "Unknown action, exiting");
finish();
return;
}
// Set the layout for this activity. You can find it in res/layout/note_editor.xml
setContentView(R.layout.note_editor);
Spinner spinner = (Spinner) findViewById(R.id.spinner1);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.spinnerss, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
// The text view for our note, identified by its ID in the XML file.
mText = (EditText) findViewById(R.id.note);
mTime = (TimePicker) findViewById(R.id.timePicker1);
mPicker = (DatePicker) findViewById(R.id.datePicker1);
mChoice = (Spinner) findViewById(R.id.spinner1);
// Get the note!
mCursor = managedQuery(mUri, PROJECTION, null, null, null);
// If an instance of this activity had previously stopped, we can
// get the original text it started with.
if (savedInstanceState != null) {
mOriginalContent = savedInstanceState.getString(ORIGINAL_CONTENT);
}
}
@Override
protected void onResume() {
super.onResume();
// If we didn't have any trouble retrieving the data, it is now
// time to get at the stuff.
if (mCursor != null) {
// Requery in case something changed while paused (such as the title)
mCursor.requery();
// Make sure we are at the one and only row in the cursor.
mCursor.moveToFirst();
// Modify our overall title depending on the mode we are running in.
if (mState == STATE_EDIT) {
// Set the title of the Activity to include the note title
String title = mCursor.getString(COLUMN_INDEX_TITLE);
Resources res = getResources();
String text = String.format(res.getString(R.string.title_edit), title);
setTitle(text);
} else if (mState == STATE_INSERT) {
setTitle(getText(R.string.title_create));
}
// This is a little tricky: we may be resumed after previously being
// paused/stopped. We want to put the new text in the text view,
// but leave the user where they were (retain the cursor position
// etc). This version of setText does that for us.
String note = mCursor.getString(COLUMN_INDEX_NOTE);
mText.setTextKeepState(note);
// If we hadn't previously retrieved the original text, do so
// now. This allows the user to revert their changes.
if (mOriginalContent == null) {
mOriginalContent = note;
}
} else {
setTitle(getText(R.string.error_title));
mText.setText(getText(R.string.error_message));
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
// Save away the original text, so we still have it if the activity
// needs to be killed while paused.
outState.putString(ORIGINAL_CONTENT, mOriginalContent);
}
@Override
protected void onPause() {
super.onPause();
// The user is going somewhere, so make sure changes are saved
String text = mText.getText().toString();
int length = text.length();
// If this activity is finished, and there is no text, then we
// simply delete the note entry.
// Note that we do this both for editing and inserting... it
// would be reasonable to only do it when inserting.
if (isFinishing() && (length == 0) && mCursor != null) {
setResult(RESULT_CANCELED);
deleteNote();
} else {
saveNote();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate menu from XML resource
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.editor_options_menu, menu);
// Append to the
// menu items for any other activities that can do stuff with it
// as well. This does a query on the system for any activities that
// implement the ALTERNATIVE_ACTION for our data, adding a menu item
// for each one that is found.
Intent intent = new Intent(null, getIntent().getData());
intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0,
new ComponentName(this, NoteEditor.class), null, intent, 0, null);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (mState == STATE_EDIT) {
menu.setGroupVisible(R.id.menu_group_edit, true);
menu.setGroupVisible(R.id.menu_group_insert, false);
// Check if note has changed and enable/disable the revert option
String savedNote = mCursor.getString(COLUMN_INDEX_NOTE);
String currentNote = mText.getText().toString();
if (savedNote.equals(currentNote)) {
menu.findItem(R.id.menu_revert).setEnabled(false);
} else {
menu.findItem(R.id.menu_revert).setEnabled(true);
}
} else {
menu.setGroupVisible(R.id.menu_group_edit, false);
menu.setGroupVisible(R.id.menu_group_insert, true);
}
return super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle all of the possible menu actions.
switch (item.getItemId()) {
case R.id.menu_save:
saveNote();
finish();
break;
case R.id.menu_delete:
deleteNote();
finish();
break;
case R.id.menu_revert:
case R.id.menu_discard:
cancelNote();
break;
}
return super.onOptionsItemSelected(item);
}
private final void saveNote() {
// Make sure their current
// changes are safely saved away in the provider. We don't need
// to do this if only editing.
if (mCursor != null) {
// Get out updates into the provider.
ContentValues values = new ContentValues();
// Bump the modification time to now.
values.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
String text = mText.getText().toString();
//String date = mPicker.toString();
//String time = mTime.toString();
String choice = mChoice.toString();
int length = text.length();
// If we are creating a new note, then we want to also create
// an initial title for it.
if (mState == STATE_INSERT) {
if (length == 0) {
Toast.makeText(this, R.string.nothing_to_save, Toast.LENGTH_SHORT).show();
return;
}
String title = text.substring(0, Math.min(30, length));
if (length > 30) {
int lastSpace = title.lastIndexOf(' ');
if (lastSpace > 0) {
title = title.substring(0, lastSpace);
}
}
values.put(NoteColumns.TITLE, title);
}
// Write our text back into the provider.
values.put(NoteColumns.NOTE, text);
//values.put(NoteColumns.DATE, date);
//values.put(NoteColumns.TIME, time);
//values.put(NoteColumns.CHOICE, choice);
// Commit all of our changes to persistent storage. When the update completes
// the content provider will notify the cursor of the change, which will
// cause the UI to be updated.
try {
getContentResolver().update(mUri, values, null, null);
} catch (NullPointerException e) {
Log.e(TAG, e.getMessage());
}
}
}
/**
* Take care of canceling work on a note. Deletes the note if we
* had created it, otherwise reverts to the original text.
*/
private final void cancelNote() {
if (mCursor != null) {
if (mState == STATE_EDIT) {
// Put the original note text back into the database
mCursor.close();
mCursor = null;
ContentValues values = new ContentValues();
values.put(NoteColumns.NOTE, mOriginalContent);
getContentResolver().update(mUri, values, null, null);
} else if (mState == STATE_INSERT) {
// We inserted an empty note, make sure to delete it
deleteNote();
}
}
setResult(RESULT_CANCELED);
finish();
}
/**
* Take care of deleting a note. Simply deletes the entry.
*/
private final void deleteNote() {
if (mCursor != null) {
mCursor.close();
mCursor = null;
getContentResolver().delete(mUri, null, null);
mText.setText("");
}
}
}
希望我没有从文件中包含太多内容,我删除了顶部的导入和版权以节省更多空间,但不确定需要什么来正确分析问题并帮助更好地向我解释。
谢谢迈克尔
数据管理系统:
07-18 10:27:49.757: ERROR/Database(25136): Error updating choice=android.widget.Spinner@40551ea0 note=Blah burger
07-18 10:27:49.757: ERROR/Database(25136): T
07-18 10:27:49.757: ERROR/Database(25136): modified=1311002869768 using UPDATE notes SET choice=?, note=?, modified=? WHERE _id=1
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): FATAL EXCEPTION: main
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): java.lang.RuntimeException: Unable to pause activity {com.example.android.notepad/com.example.android.notepad.NoteEditor}: android.database.sqlite.SQLiteException: no such column: choice: , while compiling: UPDATE notes SET choice=?, note=?, modified=? WHERE _id=1
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at android.app.ActivityThread.performPauseActivity(ActivityThread.java:2731)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at android.app.ActivityThread.performPauseActivity(ActivityThread.java:2678)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:2651)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at android.app.ActivityThread.access$1700(ActivityThread.java:132)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1049)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at android.os.Handler.dispatchMessage(Handler.java:99)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at android.os.Looper.loop(Looper.java:143)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at android.app.ActivityThread.main(ActivityThread.java:4263)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at java.lang.reflect.Method.invokeNative(Native Method)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at java.lang.reflect.Method.invoke(Method.java:507)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at dalvik.system.NativeStart.main(Native Method)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): Caused by: android.database.sqlite.SQLiteException: no such column: choice: , while compiling: UPDATE notes SET choice=?, note=?, modified=? WHERE _id=1
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at android.database.sqlite.SQLiteCompiledSql.native_compile(Native Method)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at android.database.sqlite.SQLiteCompiledSql.compile(SQLiteCompiledSql.java:92)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at android.database.sqlite.SQLiteCompiledSql.<init>(SQLiteCompiledSql.java:65)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:83)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java:41)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at android.database.sqlite.SQLiteDatabase.compileStatement(SQLiteDatabase.java:1231)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at android.database.sqlite.SQLiteDatabase.updateWithOnConflict(SQLiteDatabase.java:1813)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at android.database.sqlite.SQLiteDatabase.update(SQLiteDatabase.java:1763)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at com.example.android.notepad.NotePadProvider.update(NotePadProvider.java:235)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at android.content.ContentProvider$Transport.update(ContentProvider.java:240)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at android.content.ContentResolver.update(ContentResolver.java:726)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at com.example.android.notepad.NoteEditor.saveNote(NoteEditor.java:357)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at com.example.android.notepad.NoteEditor.onPause(NoteEditor.java:247)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at android.app.Activity.performPause(Activity.java:3988)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at android.app.Instrumentation.callActivityOnPause(Instrumentation.java:1313)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): at android.app.ActivityThread.performPauseActivity(ActivityThread.java:2708)
07-18 10:27:49.817: ERROR/AndroidRuntime(25136): ... 12 more
NotepadProvider.java:
public class NotePadProvider extends ContentProvider {
private static final String TAG = "NotePadProvider";
private static final String DATABASE_NAME = "notepad.db";
private static final int DATABASE_VERSION = 2;
private static final String NOTES_TABLE_NAME = "notes";
private static HashMap<String, String> sNotesProjectionMap;
private static HashMap<String, String> sLiveFolderProjectionMap;
private static final int NOTES = 1;
private static final int NOTE_ID = 2;
private static final int LIVE_FOLDER_NOTES = 3;
private static final UriMatcher sUriMatcher;
/**
* This class helps open, create, and upgrade the database file.
*/
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + NOTES_TABLE_NAME + " ("
+ NoteColumns._ID + " INTEGER PRIMARY KEY,"
+ NoteColumns.TITLE + " TEXT,"
+ NoteColumns.NOTE + " TEXT,"
+ NoteColumns.TIME + " TEXT,"
+ NoteColumns.DATE + " TEXT,"
+ NoteColumns.CHOICE + " TEXT,"
+ NoteColumns.CREATED_DATE + " INTEGER,"
+ NoteColumns.MODIFIED_DATE + " INTEGER"
+ ");");
}
@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 notes");
onCreate(db);
}
}
private DatabaseHelper mOpenHelper;
@Override
public boolean onCreate() {
mOpenHelper = new DatabaseHelper(getContext());
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables(NOTES_TABLE_NAME);
switch (sUriMatcher.match(uri)) {
case NOTES:
qb.setProjectionMap(sNotesProjectionMap);
break;
case NOTE_ID:
qb.setProjectionMap(sNotesProjectionMap);
qb.appendWhere(NoteColumns._ID + "=" + uri.getPathSegments().get(1));
break;
case LIVE_FOLDER_NOTES:
qb.setProjectionMap(sLiveFolderProjectionMap);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
// If no sort order is specified use the default
String orderBy;
if (TextUtils.isEmpty(sortOrder)) {
orderBy = NoteColumns.DEFAULT_SORT_ORDER;
} else {
orderBy = sortOrder;
}
// Get the database and run the query
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
// Tell the cursor what uri to watch, so it knows when its source data changes
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
@Override
public String getType(Uri uri) {
switch (sUriMatcher.match(uri)) {
case NOTES:
case LIVE_FOLDER_NOTES:
return NoteColumns.CONTENT_TYPE;
case NOTE_ID:
return NoteColumns.CONTENT_ITEM_TYPE;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
}
@Override
public Uri insert(Uri uri, ContentValues initialValues) {
// Validate the requested uri
if (sUriMatcher.match(uri) != NOTES) {
throw new IllegalArgumentException("Unknown URI " + uri);
}
ContentValues values;
if (initialValues != null) {
values = new ContentValues(initialValues);
} else {
values = new ContentValues();
}
Long now = Long.valueOf(System.currentTimeMillis());
// Make sure that the fields are all set
if (values.containsKey(NoteColumns.CREATED_DATE) == false) {
values.put(NoteColumns.CREATED_DATE, now);
}
if (values.containsKey(NoteColumns.MODIFIED_DATE) == false) {
values.put(NoteColumns.MODIFIED_DATE, now);
}
if (values.containsKey(NoteColumns.TITLE) == false) {
Resources r = Resources.getSystem();
values.put(NoteColumns.TITLE, r.getString(android.R.string.untitled));
}
if (values.containsKey(NoteColumns.NOTE) == false) {
values.put(NoteColumns.NOTE, "");
}
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
long rowId = db.insert(NOTES_TABLE_NAME, NoteColumns.NOTE, values);
if (rowId > 0) {
Uri noteUri = ContentUris.withAppendedId(NoteColumns.CONTENT_URI, rowId);
getContext().getContentResolver().notifyChange(noteUri, null);
return noteUri;
}
throw new SQLException("Failed to insert row into " + uri);
}
@Override
public int delete(Uri uri, String where, String[] whereArgs) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count;
switch (sUriMatcher.match(uri)) {
case NOTES:
count = db.delete(NOTES_TABLE_NAME, where, whereArgs);
break;
case NOTE_ID:
String noteId = uri.getPathSegments().get(1);
count = db.delete(NOTES_TABLE_NAME, NoteColumns._ID + "=" + noteId
+ (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
@Override
public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count;
switch (sUriMatcher.match(uri)) {
case NOTES:
count = db.update(NOTES_TABLE_NAME, values, where, whereArgs);
break;
case NOTE_ID:
String noteId = uri.getPathSegments().get(1);
count = db.update(NOTES_TABLE_NAME, values, NoteColumns._ID + "=" + noteId
+ (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
static {
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES);
sUriMatcher.addURI(NotePad.AUTHORITY, "choice", NOTES);
sUriMatcher.addURI(NotePad.AUTHORITY, "date", NOTES);
sUriMatcher.addURI(NotePad.AUTHORITY, "time", NOTES);
sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);
sUriMatcher.addURI(NotePad.AUTHORITY, "live_folders/notes", LIVE_FOLDER_NOTES);
sNotesProjectionMap = new HashMap<String, String>();
sNotesProjectionMap.put(NoteColumns._ID, NoteColumns._ID);
sNotesProjectionMap.put(NoteColumns.TITLE, NoteColumns.TITLE);
sNotesProjectionMap.put(NoteColumns.NOTE, NoteColumns.NOTE);
sNotesProjectionMap.put(NoteColumns.CHOICE, NoteColumns.CHOICE);
sNotesProjectionMap.put(NoteColumns.TIME, NoteColumns.TIME);
sNotesProjectionMap.put(NoteColumns.DATE, NoteColumns.DATE);
sNotesProjectionMap.put(NoteColumns.CREATED_DATE, NoteColumns.CREATED_DATE);
sNotesProjectionMap.put(NoteColumns.MODIFIED_DATE, NoteColumns.MODIFIED_DATE);
// Support for Live Folders.
sLiveFolderProjectionMap = new HashMap<String, String>();
sLiveFolderProjectionMap.put(LiveFolders._ID, NoteColumns._ID + " AS " +
LiveFolders._ID);
sLiveFolderProjectionMap.put(LiveFolders.NAME, NoteColumns.TITLE + " AS " +
LiveFolders.NAME);
// Add more columns here for more robust Live Folders.
}
}