我是Android新手。我已经关注了一些关于ContentProviders和Loaders的教程。我创建了一个记事本应用程序,但我认为它无法将内容保存到数据库中。我有两个活动:带有注释列表的NoteList和创建注释的NoteEdit,以及一个ContentProvider:NotesDbAdapter。保存注释时,列表为空。
NoteEdit.java
public class NoteEdit extends Activity{
public static int numTitle = 1;
public static String curDate = "";
public static String curText = "";
private EditText mTitleText;
private EditText mBodyText;
private TextView mDateText;
private Long mRowId;
private String mode;
private Cursor note;
private NotesDbAdapter mDbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// mDbHelper = new NotesDbAdapter(this);
// mDbHelper.open();
setContentView(R.layout.note_edit);
setTitle(R.string.app_name);
mTitleText = (EditText) findViewById(R.id.title);
mBodyText = (EditText) findViewById(R.id.body);
mDateText = (TextView) findViewById(R.id.notelist_date);
long msTime = System.currentTimeMillis();
Date curDateTime = new Date(msTime);
SimpleDateFormat formatter = new SimpleDateFormat("d'/'M'/'y");
curDate = formatter.format(curDateTime);
mDateText.setText(""+curDate);
mRowId = (savedInstanceState == null) ? null :
(Long) savedInstanceState.getSerializable(NotesDbAdapter.KEY_ROWID);
if (mRowId == null) {
Bundle extras = getIntent().getExtras();
mode = extras.getString("mode");
mRowId = extras != null ? extras.getLong(NotesDbAdapter.KEY_ROWID)
: null;
}
populateFields();
}
public static class LineEditText extends EditText{
// we need this constructor for LayoutInflater
public LineEditText(Context context, AttributeSet attrs) {
super(context, attrs);
mRect = new Rect();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setColor(Color.BLUE);
}
private Rect mRect;
private Paint mPaint;
@Override
protected void onDraw(Canvas canvas) {
int height = getHeight();
int line_height = getLineHeight();
int count = height / line_height;
if (getLineCount() > count)
count = getLineCount();
Rect r = mRect;
Paint paint = mPaint;
int baseline = getLineBounds(0, r);
for (int i = 0; i < count; i++) {
canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, paint);
baseline += getLineHeight();
super.onDraw(canvas);
}
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
saveState();
outState.putSerializable(NotesDbAdapter.KEY_ROWID, mRowId);
}
@Override
protected void onPause() {
super.onPause();
saveState();
}
@Override
protected void onResume() {
super.onResume();
populateFields();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.noteedit_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_delete:
if(note != null){
note.close();
note = null;
}
if(mRowId != null){
//mDbHelper.deleteNote(mRowId);
Uri uri = Uri.parse(NotesDbAdapter.CONTENT_URI+"/"+mRowId);
//getContentResolver().delete(uri, null, null);
mDbHelper.delete(uri,null,null);
}
finish();
return true;
case R.id.menu_save:
saveState();
finish();
default:
return super.onOptionsItemSelected(item);
}
}
private void saveState() {
String title = mTitleText.getText().toString();
String body = mBodyText.getText().toString();
String date = mDateText.getText().toString();
ContentValues values = new ContentValues();
values.put(NotesDbAdapter.KEY_TITLE, title);
values.put(NotesDbAdapter.KEY_BODY, body);
values.put(NotesDbAdapter.KEY_DATE,date);
if(mode.trim().equalsIgnoreCase("add")){
getContentResolver().insert(NotesDbAdapter.CONTENT_URI,values);
}
else {
Uri uri = Uri.parse(NotesDbAdapter.CONTENT_URI + "/" + mRowId);
getContentResolver().update(uri, values, null, null);
}
}
private void populateFields() {
if (mRowId != null) {
String[] projection = {
NotesDbAdapter.KEY_ROWID,
NotesDbAdapter.KEY_TITLE,
NotesDbAdapter.KEY_BODY,
NotesDbAdapter.KEY_DATE};
Uri uri = Uri.parse(NotesDbAdapter.CONTENT_URI + "/" + mRowId);
Cursor cursor = getContentResolver().query(uri, projection, null, null,
null);
if (cursor.moveToFirst()) {
String title = cursor.getString(cursor.getColumnIndexOrThrow(NotesDbAdapter.KEY_TITLE));
String body = cursor.getString(cursor.getColumnIndexOrThrow(NotesDbAdapter.KEY_BODY));
String date = cursor.getString(cursor.getColumnIndexOrThrow(NotesDbAdapter.KEY_DATE));
mTitleText.setText(title);
mBodyText.setText(body);
mDateText.setText(date);
}
}
}
NoteList.java
public class NoteList extends ListActivity implements LoaderManager.LoaderCallbacks<Cursor>{
private SimpleCursorAdapter dataAdapter;
private static final int ACTIVITY_CREATE=0;
private static final int ACTIVITY_EDIT=1;
private static final int DELETE_ID = Menu.FIRST;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.notelist);
// mDbHelper = new NotesDbAdapter(this);
// mDbHelper.open();
fillData();
registerForContextMenu(getListView());
Button addnote = (Button)findViewById(R.id.addnotebutton);
addnote.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
createNote();
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.notelist_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}
private void createNote() {
Intent i = new Intent(this, NoteEdit.class);
Bundle bundle = new Bundle();
bundle.putString("mode", "add");
i.putExtras(bundle);
startActivityForResult(i, ACTIVITY_CREATE);
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
Intent i = new Intent(this, NoteEdit.class);
Bundle bundle = new Bundle();
bundle.putString("mode", "update");
bundle.putLong(NotesDbAdapter.KEY_ROWID, id);
i.putExtras(bundle);
// i.putExtra(NotesDbAdapter.KEY_ROWID, id);
startActivityForResult(i, ACTIVITY_EDIT);
}
private void fillData() {
// The desired columns to be bound
String[] columns = new String[] {
NotesDbAdapter.KEY_TITLE,
NotesDbAdapter.KEY_DATE
};
// the XML defined views which the data will be bound to
int[] to = new int[] {
R.id.text1,
R.id.date_row
};
// create an adapter from the SimpleCursorAdapter
dataAdapter = new SimpleCursorAdapter(
this,
R.layout.notes_row,
null,
columns,
to,
0);
setListAdapter(dataAdapter);
//Ensures a loader is initialized and active.
getLoaderManager().initLoader(0, null, this);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.add(0, DELETE_ID, 0, R.string.menu_delete);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
switch(item.getItemId()) {
case DELETE_ID:
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
// mDbHelper.deleteNote(info.id);
Uri uri = Uri.parse(NotesDbAdapter.CONTENT_URI + "/" + info.id);
getContentResolver().delete(uri, null, null);
fillData();
return true;
}
return super.onContextItemSelected(item);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
fillData();
}
protected void onResume() {
super.onResume();
//Starts a new or restarts an existing Loader in this manager
getLoaderManager().restartLoader(0, null, this);
}
// This is called when a new Loader needs to be created.
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection = {
NotesDbAdapter.KEY_ROWID,
NotesDbAdapter.KEY_TITLE,
NotesDbAdapter.KEY_BODY,
NotesDbAdapter.KEY_DATE};
CursorLoader cursorLoader = new CursorLoader(this,
NotesDbAdapter.CONTENT_URI, projection, null, null, null);
return cursorLoader;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
dataAdapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
// This is called when the last Cursor provided to onLoadFinished()
// above is about to be closed. We need to make sure we are no
// longer using it.
dataAdapter.swapCursor(null);
}
NotesDbAdapter.java
public class NotesDbAdapter extends ContentProvider{
private Context mCtx;
static final String PROVIDER_NAME = "com.example.note.contentprovider.notesdbadapter";
static final String URL = "content://" + PROVIDER_NAME + "/notes";
static final Uri CONTENT_URI = Uri.parse(URL);
public static final String KEY_TITLE = "title";
public static final String KEY_DATE = "date";
public static final String KEY_BODY = "body";
public static final String KEY_ROWID = "_id";
public static final int NOTES = 1;
public static final int NOTES_ID = 2;
private static HashMap<String,String> Notes;
static final UriMatcher uriMatcher;
static{
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(PROVIDER_NAME, "notes", NOTES);
uriMatcher.addURI(PROVIDER_NAME, "notes/#", NOTES_ID);
}
private static final String TAG = "NotesDbAdapter";
private DatabaseHelper mhelper;
private SQLiteDatabase database;
private static final String DATABASE_NAME = "data";
private static final String DATABASE_TABLE = "notes";
private static final int DATABASE_VERSION = 2;
private static final String DATABASE_CREATE =
"create table notes (_id integer primary key autoincrement, "
+ "title text not null, body text not null, date text not null);";
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 notes");
onCreate(db);
}
}
public boolean onCreate() {
// TODO Auto-generated method stub
Context context = getContext();
mhelper = new DatabaseHelper(context);
// permissions to be writabl
database =mhelper.getWritableDatabase();
if(database == null)
return false;
else
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// TODO Auto-generated method stub
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
// the TABLE_NAME to query on
queryBuilder.setTables(DATABASE_TABLE);
switch (uriMatcher.match(uri)) {
// maps all database column names
case NOTES:
queryBuilder.setProjectionMap(Notes);
break;
case NOTES_ID:
queryBuilder.appendWhere( KEY_ROWID + "=" + uri.getLastPathSegment());
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
Cursor cursor = queryBuilder.query(database, projection, selection,
selectionArgs, null, null, sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
long row = database.insert(DATABASE_TABLE, "", values);
// If record is added successfully
if(row > 0) {
Uri newUri = ContentUris.withAppendedId(CONTENT_URI, row);
getContext().getContentResolver().notifyChange(newUri, null);
return newUri;
}
throw new SQLException("Fail to add a new record into " + uri);
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO Auto-generated method stub
int count = 0;
switch (uriMatcher.match(uri)){
case NOTES:
count = database.update(DATABASE_TABLE, values, selection, selectionArgs);
break;
case NOTES_ID:
count = database.update(DATABASE_TABLE, values, KEY_ROWID +
" = " + uri.getLastPathSegment() +
(!TextUtils.isEmpty(selection) ? " AND (" +
selection + ')' : ""), selectionArgs);
break;
default:
throw new IllegalArgumentException("Unsupported URI " + uri );
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
int count = 0;
switch (uriMatcher.match(uri)){
case NOTES:
// delete all the records of the table
count = database.delete(DATABASE_TABLE, selection, selectionArgs);
break;
case NOTES_ID:
String id = uri.getLastPathSegment(); //gets the id
count = database.delete( DATABASE_TABLE, KEY_ROWID + " = " + id +
(!TextUtils.isEmpty(selection) ? " AND (" +
selection + ')' : ""), selectionArgs);
break;
default:
throw new IllegalArgumentException("Unsupported URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
switch (uriMatcher.match(uri)){
// Get all friend-birthday record
case NOTES:
return "vnd.android.cursor.dir/vnd.com.example.note.contentprovider.notesdbadapter/notes";
// Get a particular friend
case NOTES_ID:
return "vnd.android.cursor.item/vnd.com.example.note.contentprovider.notesdbadapter/notes";
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
public NotesDbAdapter(){
}
public NotesDbAdapter(Context ctx) {
this.mCtx = ctx;
}
public NotesDbAdapter open() throws SQLException {
mhelper = new DatabaseHelper(mCtx);
database = mhelper.getWritableDatabase();
return this;
}
public void close() {
mhelper.close();
}
notelist.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/notelist">
<TextView
android:id="@+id/textViewTop"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:paddingBottom="35dp" />
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/btmLayout"
android:layout_below="@+id/textViewTop"
android:background="#FFF9C8"
android:divider="#D3D3D3"
android:dividerHeight="1sp"
android:footerDividersEnabled="true" />
<LinearLayout
android:id="@+id/btmLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:layout_alignParentBottom="true"
android:layout_marginBottom="3dp"
android:layout_marginTop="10dp">
<Button
android:id="@+id/addnotebutton"
android:layout_width="50dp"
android:layout_height="wrap_content"
android:background="@drawable/create_note" />
</LinearLayout>
notes_row.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginLeft="10sp"
android:textSize="25sp"
android:hint="@string/no_title"
android:id="@+id/text1"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize = "25sp"
android:id="@+id/date_row"
android:layout_alignParentRight="true"
android:layout_marginRight="10sp"/>
</RelativeLayout>