下面是对SDK中的NotePad smaple做的一些改进,效果图在最后。
刚开始看Android,这是继hello之后的第二个例子。
不对的地方,请批评指正。
java文件有:
1.NotesList.java
2.NoteEditor.java
3.NotePadProvider.java
4.NotePad.java
5.DateUtil.java
layout有:
1.note_editor.xml
2.noteslist_item.xml
贴出来修改之后的代码:
NotesList.java:
package com.cticc.notepad;
import android.app.ListActivity;
import android.content.ContentUris;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import com.cticc.notepad.NotePad.Notes;
/**
* Displays a list of notes. Will display notes from the {@link Uri} provided in the intent if there
* is one, otherwise defaults to displaying the contents of the {@link NotePadProvider}
*/
public class NotesList extends ListActivity
{
private static final String TAG = "NotesList";
public static final int MENU_ITEM_DELETE = Menu.FIRST;
public static final int MENU_ITEM_INSERT = Menu.FIRST + 1;
/**
* The columns we are interested in from the database
*/
private static final String[] PROJECTION = new String[] { Notes._ID, // 0
Notes.KEY_TITLE, // 1
Notes.KEY_CREATEAT // 2
};
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT);
// If no data was given in the intent (because we were started as a MAIN activity), then use our default content provider.
Intent intent = getIntent();
if (intent.getData() == null)
{
intent.setData(Notes.CONTENT_URI);
}
// Inform the list we provide context menus for items
getListView().setOnCreateContextMenuListener(this);
// Perform a managed query. The Activity will handle closing and requerying the cursor when needed.
Cursor cursor = managedQuery(getIntent().getData(), PROJECTION, null, null, Notes.DEFAULT_SORT_ORDER);
// Used to map notes entries from the database to views
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.noteslist_item, cursor, new String[] { Notes.KEY_CREATEAT, Notes.KEY_TITLE }, new int[] { android.R.id.text1,
android.R.id.text2 });
setListAdapter(adapter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
super.onCreateOptionsMenu(menu);
Log.i(TAG, "enter in onCreateOptionsMenu");
// This is our one standard application action -- inserting a new note into the list.
menu.add(0, MENU_ITEM_INSERT, 0, R.string.menu_insert).setShortcut('3', 'a').setIcon(android.R.drawable.ic_menu_add);
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu)
{
super.onPrepareOptionsMenu(menu);
Log.i(TAG, "enter in onPrepareOptionsMenu");
final boolean haveItems = getListAdapter().getCount() > 0;
// If there are any notes in the list (which implies that one of them is selected), then we need to generate the actions that
// can be performed on the current selection. This will be a combination of our own specific
// actions along with any extensions that can be found.
if (haveItems)
{
// This is the selected item.
Uri uri = ContentUris.withAppendedId(getIntent().getData(), getSelectedItemId());
// Build menu... always starts with the EDIT action...
Intent[] specifics = new Intent[1];
specifics[0] = new Intent(Intent.ACTION_EDIT, uri);
MenuItem[] items = new MenuItem[1];
// ... is followed by whatever other actions are available...
Intent intent = new Intent(null, uri);
intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, null, specifics, intent, 0, items);
// Give a shortcut to the edit action.
if (items[0] != null)
{
items[0].setShortcut('1', 'e').setIcon(android.R.drawable.ic_menu_edit);
}
}
else
{
menu.removeGroup(Menu.CATEGORY_ALTERNATIVE);
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case MENU_ITEM_INSERT:
// Launch activity to insert a new item
startActivity(new Intent(Intent.ACTION_INSERT, getIntent().getData()));
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id)
{
Uri uri = ContentUris.withAppendedId(getIntent().getData(), id);
String action = getIntent().getAction();
if (Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action))
{
// The caller is waiting for us to return a note selected by
// the user. The have clicked on one, so return it now.
setResult(RESULT_OK, new Intent().setData(uri));
}
else
{
// Launch activity to view/edit the currently selected item
startActivity(new Intent(Intent.ACTION_EDIT, uri));
}
}
}
NoteEditor.java:
package com.cticc.notepad;
import com.cticc.notepad.NotePad.Notes;
import com.cticc.notepad.util.DateUtil;
import android.app.Activity;
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.EditText;
/**
* A generic activity for editing a note in a database. This can be used either to simply view a
* note {@link Intent#ACTION_VIEW}, view and edit a note {@link Intent#ACTION_EDIT}, or create a new
* note {@link Intent#ACTION_INSERT}.
*/
public class NoteEditor extends Activity
{
private static final String TAG = "Notes";
// Standard projection for the interesting columns of a normal note.
private static final String[] PROJECTION = new String[] { Notes._ID, // 0
Notes.KEY_TITLE, // 1
Notes.KEY_CONTENT // 2
};
// The index of the note column
private static final int COLUMN_INDEX_TITLE = 1;
private static final int COLUMN_INDEX_CONTENT = 2;
// Identifiers for our menu items.
private static final int MENU_CONFIRM_ID = Menu.FIRST;
private static final int MENU_DELETE_ID = Menu.FIRST + 1;
private static final int MENU_DISCARD_ID = Menu.FIRST + 2;
// The different distinct states the activity can be run in.
private static final int ACTION_EDIT = 0;
private static final int ACTION_INSERT = 1;
private int mState;
private boolean mNoteOnly = false;
private Uri mUri;
private Cursor mCursor;
private EditText mContent;
private EditText mTitle;
//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 = ACTION_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 = ACTION_INSERT;
Log.i(TAG, "intent.getData() is : " + intent.getData());
//mUri = getContentResolver().insert(intent.getData(), null);
mUri = intent.getData();
// 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 note 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);
// The text view for our note, identified by its ID in the XML file.
mContent = (EditText) findViewById(R.id.content);
mTitle = (EditText) findViewById(R.id.title);
// Get the note!
mCursor = managedQuery(mUri, PROJECTION, null, null, null);
}
@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)
{
// 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 == ACTION_EDIT)
{
setTitle(getText(R.string.label_edit));
String content = mCursor.getString(COLUMN_INDEX_CONTENT);
String title = mCursor.getString(COLUMN_INDEX_TITLE);
mContent.setTextKeepState(content);
mTitle.setTextKeepState(title);
}
else if (mState == ACTION_INSERT)
{
setTitle(getText(R.string.label_insert));
}
}
else
{
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
super.onCreateOptionsMenu(menu);
menu.add(0, MENU_CONFIRM_ID, 0, R.string.menu_confirm).setShortcut('0', 'c').setIcon(android.R.drawable.ic_menu_save);
if (mState == ACTION_EDIT)
{
if (!mNoteOnly)
{
menu.add(0, MENU_DELETE_ID, 0, R.string.menu_delete).setShortcut('1', 'd').setIcon(android.R.drawable.ic_menu_delete);
}
}
menu.add(0, MENU_DISCARD_ID, 0, R.string.menu_discard).setShortcut('2', 'd').setIcon(android.R.drawable.ic_menu_revert);
if (!mNoteOnly)
{
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 true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
// Handle all of the possible menu actions.
switch (item.getItemId())
{
case MENU_CONFIRM_ID:
saveState();
finish();
break;
case MENU_DELETE_ID:
deleteNote();
finish();
break;
case MENU_DISCARD_ID:
finish();
break;
}
return super.onOptionsItemSelected(item);
}
private void saveState()
{
ContentValues values = new ContentValues();
values.put(Notes.KEY_CONTENT, mContent.getText().toString());
values.put(Notes.KEY_TITLE, mTitle.getText().toString());
String sdate = DateUtil.getTodayTimeStampString();
if (mState == ACTION_INSERT)
{
values.put(Notes.KEY_CREATEAT, DateUtil.getToday());
values.put(Notes.KEY_UPDATEAT, sdate);
getContentResolver().insert(mUri, values);
}
else if (mState == ACTION_EDIT)
{
values.put(Notes.KEY_UPDATEAT, sdate);
getContentResolver().update(mUri, values, null, null);
}
}
/**
* 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);
mContent.setText("");
}
}
}
NotePadProvider.java:
package com.cticc.notepad;
import com.cticc.notepad.NotePad.Notes;
import com.cticc.notepad.util.DateUtil;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import java.util.HashMap;
/**
* Provides access to a database of notes. Each note has a title, the note itself, a creation date and a modified data.
*/
public class NotePadProvider extends ContentProvider
{
private static final String TAG = "NotePadProvider";
private SQLiteDatabase sqlitedb;
private static HashMap sNotesProjectionMap;
private static final int NOTES = 1;
private static final int NOTE_ID = 2;
private static final UriMatcher sUriMatcher;
static
{
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES);
sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);
sNotesProjectionMap = new HashMap();
sNotesProjectionMap.put(Notes._ID, Notes._ID);
sNotesProjectionMap.put(Notes.KEY_TITLE, Notes.KEY_TITLE);
sNotesProjectionMap.put(Notes.KEY_CONTENT, Notes.KEY_CONTENT);
sNotesProjectionMap.put(Notes.KEY_CREATEAT, Notes.KEY_CREATEAT);
sNotesProjectionMap.put(Notes.KEY_UPDATEAT, Notes.KEY_UPDATEAT);
}
/**
* This class helps open, create, and upgrade the database file.
*/
private static class DatabaseHelper extends SQLiteOpenHelper
{
DatabaseHelper(Context context)
{
super(context, Notes.DATABASE_NAME, null, Notes.DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db)
{
db.execSQL("CREATE TABLE " + Notes.TABLE_NAME + " (" + Notes._ID + " INTEGER PRIMARY KEY," + Notes.KEY_TITLE + " TEXT," + Notes.KEY_CONTENT + " TEXT,"
+ Notes.KEY_CREATEAT + " TEXT," + Notes.KEY_UPDATEAT + " TEXT" + ");");
}
@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.TABLE_NAME);
onCreate(db);
}
}
private DatabaseHelper mOpenHelper;
@Override
public boolean onCreate()
{
mOpenHelper = new DatabaseHelper(getContext());
sqlitedb = mOpenHelper.getWritableDatabase();
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
{
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
switch (sUriMatcher.match(uri))
{
case NOTES:
qb.setTables(Notes.TABLE_NAME);
qb.setProjectionMap(sNotesProjectionMap);
break;
case NOTE_ID:
qb.setTables(Notes.TABLE_NAME);
qb.setProjectionMap(sNotesProjectionMap);
qb.appendWhere(Notes._ID + "=" + uri.getPathSegments().get(1));
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
// If no sort order is specified use the default
String orderBy;
if (TextUtils.isEmpty(sortOrder))
{
orderBy = Notes.DEFAULT_SORT_ORDER;
}
else
{
orderBy = sortOrder;
}
Cursor c = qb.query(sqlitedb, 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)
{
Log.i(TAG, "getType: the uri is: " + uri);
switch (sUriMatcher.match(uri))
{
case NOTES:
return Notes.CONTENT_TYPE;
case NOTE_ID:
return Notes.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();
}
// Make sure that the fields are all set
if (values.containsKey(NotePad.Notes.KEY_CREATEAT) == false)
{
values.put(NotePad.Notes.KEY_CREATEAT, DateUtil.getToday());
}
if (values.containsKey(NotePad.Notes.KEY_UPDATEAT) == false)
{
values.put(NotePad.Notes.KEY_UPDATEAT, DateUtil.getTodayTimeStampString());
}
if (values.containsKey(NotePad.Notes.KEY_TITLE) == false)
{
Resources r = Resources.getSystem();
values.put(NotePad.Notes.KEY_TITLE, r.getString(android.R.string.untitled));
}
if (values.containsKey(NotePad.Notes.KEY_CONTENT) == false)
{
values.put(NotePad.Notes.KEY_CONTENT, "");
}
long rowId = sqlitedb.insert(Notes.TABLE_NAME, Notes.KEY_CONTENT, values);
if (rowId > 0)
{
Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.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)
{
int count;
switch (sUriMatcher.match(uri))
{
case NOTES:
count = sqlitedb.delete(Notes.TABLE_NAME, where, whereArgs);
break;
case NOTE_ID:
String noteId = uri.getPathSegments().get(1);
count = sqlitedb.delete(Notes.TABLE_NAME, Notes._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)
{
int count;
switch (sUriMatcher.match(uri))
{
case NOTES:
count = sqlitedb.update(Notes.TABLE_NAME, values, where, whereArgs);
break;
case NOTE_ID:
String noteId = uri.getPathSegments().get(1);
count = sqlitedb.update(Notes.TABLE_NAME, values, Notes._ID + "=" + noteId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
}
NotePad.java
package com.cticc.notepad;
import android.net.Uri;
import android.provider.BaseColumns;
/**
* Convenience definitions for NotePadProvider
*/
public final class NotePad
{
public static final String AUTHORITY = "com.google.provider.NotePad";
// This class cannot be instantiated
private NotePad()
{
}
/**
* Notes table
*/
public static final class Notes implements BaseColumns
{
// This class cannot be instantiated
private Notes()
{
}
/****************************************************************************************
*
*
* **************************************************************************************/
public static final String DATABASE_NAME = "notepad.db";
public static final String TABLE_NAME = "notes";
public static final int DATABASE_VERSION = 2;
/****************************************************************************************
*
*
* **************************************************************************************/
// public static final String KEY_ROWID = "_id";
public static final String KEY_TITLE = "title";
public static final String KEY_CONTENT = "content";
public static final String KEY_CREATEAT = "createAt";
public static final String KEY_UPDATEAT = "updateAt";
/****************************************************************************************
*
*
* **************************************************************************************/
/**
* The content:// style URL for this table
*/
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + TABLE_NAME);
/**
* The MIME type of {@link #CONTENT_URI} providing a directory of notes.
*/
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.google.note";
/**
* The MIME type of a {@link #CONTENT_URI} sub-directory of a single note.
*/
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.google.note";
/**
* The default sort order for this table
*/
public static final String DEFAULT_SORT_ORDER = "updateAt DESC";
}
}
DateUtil.java
package com.cticc.notepad.util;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateUtil
{
private static String defaultDatePattern = "yyyy-MM-dd";
private static String defaultTimeStampPattern = "yyyy-MM-dd HH:mm:ss";
/**
* 返回默认格式的当前日期
*
* @return String
*/
public static String getToday()
{
Date today = new Date();
return convertDateToString(today,defaultDatePattern);
}
/**
* 返回默认格式的当前时间戳字符串格式
*
* @return String
*/
public static String getTodayTimeStampString()
{
Date today = new Date();
return convertDateToString(today, defaultTimeStampPattern);
}
/**
* 使用默认格式转换Date成字符串
*
* @param date
* @return String
*/
public static String convertDateToString(Date date)
{
return convertDateToString(date, defaultDatePattern);
}
/**
* 使用指定格式转换Date成字符串
*
* @param date
* @param pattern
* @return String
*/
public static String convertDateToString(Date date, String pattern)
{
String returnValue = "";
if (date != null)
{
SimpleDateFormat df = new SimpleDateFormat(pattern);
returnValue = df.format(date);
}
return returnValue;
}
}
note_editor.xml:
noteslist_item.xml
strings.xml
Confirm
Delete
Discard
Add note
Add note
Edit note
Title
note_editor
noteslist_item
NotePad
|
Error
Error loading note
AndroidManifest.xml
上几张图片:
在下面这个界面,我本来是想把edit换成delete,可是在onPrepareOptionsMenu()中换了之后菜单就出不来了。
郁闷~~~~