Android实现记事本项目完整实例,附源代码

2014年12月3日14:42:40
by tops

一、需求分析

一个记事本,能够输入标题和内容,创建日期、最新修改日期等信息。
如果没有输入标题则使用内容的第一句话作为标题,创建日期和修改日期均由系统自动生成,无需用户干预。
提供笔记列表,列表中笔记展示位标题、创建日期/修改日期
高级的可以给笔记添加照片或视频,这既可以自己拍摄也可以添加手机中已有的视频。

二、可行性分析

技术可行,经济可行,作为练习使用
技术方面主要用到SQLite,listview、Intent等知识点。

三、编写项目计划书

项目功能模块划分

打开应用的第一个页面用于展示已有的笔记列表,列表中的每一个笔记条目都可以点击,点击之后呈现此笔记的完整内容/编辑页面,列表下方有一个添加笔记的按钮,

开发周期

开发人员安排及工作分配

四、系统设计-功能结构设计,业务流程设计

uml建模工具的使用

新建笔记

点击添加笔记按钮→打开编辑笔记页面
用户分别在标题栏和内容栏输入内容;
点击添加视频时,打开系统录像拍摄视频并保存,然后在多媒体列表 中显示视频图片、文件名称、路径;
点击添加图像时,打开照相机拍摄图片并保存, 然后在多媒体列表 中显示图像图片、文件名称、路径;
→点击保存按钮,将笔记和多媒体信息保存到数据库;
→点击取消按钮,关闭当前页面,返回主页面/笔记列表页面。

修改笔记

点击笔记列表中的笔记时,打开编辑笔记页面,并传入当前笔记的信息,在编辑页面有用户对笔记操作,跟新建笔记的操作相同

删除笔记

选择已有笔记,进行数据库删除操作。

保存笔记

将编辑页面里的笔记信息存入到笔记数据库表中,多媒体信息存入到多媒体数据库表中

五、数据库设计

笔记表-notes
id- Integer型、主键、自动增加  INTEGER PRIMARY KEY AUTOINCREMENT,
name- text型,不为空,默认为“”   TEXT NOT NULL DEFAULT \"\",
content, text型,不为空,默认为“”   TEXT NOT NULL DEFAULT \"\",
date, text型,不为空,默认为“”   TEXT NOT NULL DEFAULT \"\",

多媒体信息表-media
id- Integer型、主键、自动增加  INTEGER PRIMARY KEY AUTOINCREMENT,
path- text型,不为空,默认为“”  TEXT NOT NULL DEFAULT \"\",
note_id-   Integer型,不为空,默认为0     INTEGER NOT NULL DEFAULT 0

六、架构设计

模块与模块之间的通信机制,MVC、

视图层,使用LinearLayout,列表使用ListView
项目工程结构:

七、代码开发及工作分配

主页面/笔记列表显示页面的布局代码:

/Notes/res/layout/activity_main.xml
   
   
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
 
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1" >
</ListView>
 
<Button
android:id="@+id/btnAddNote"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="添加日志" />
 
</LinearLayout>

编辑笔记页面的布局代码:

/Notes/res/layout/aty_eidt_note.xml
   
   
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
 
<EditText
android:id="@+id/etName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:singleLine="true" >
 
<requestFocus />
</EditText>
 
<EditText
android:id="@+id/etContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10"
android:gravity="top" />
 
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="2" >
</ListView>
 
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
 
<Button
android:id="@+id/btnSave"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="保存" />
 
<Button
android:id="@+id/btnCancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="取消" />
 
<Button
android:id="@+id/btnAddPhoto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="拍照" />
 
<Button
android:id="@+id/btnAddVideo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="录像"
android:layout_weight="1" />
</LinearLayout>
 
</LinearLayout>

显示多媒体列表的条目布局:

/Notes/res/layout/media_list_cell.xml
   
   
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:gravity="center_vertical" >
 
<ImageView
android:id="@+id/ivIcon"
android:layout_width="80dp"
android:layout_height="80dp" />
 
<TextView
android:id="@+id/tvPath"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge" />
 
</LinearLayout>

显示笔记列表的条目布局:

/Notes/res/layout/notes_list_cell.xml
   
   
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
 
<TextView
android:id="@+id/tvName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge" />
 
<TextView
android:id="@+id/tvDate"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
 
</LinearLayout>

主页面/笔记列表显示页面的java代码

/Notes/src/com/tops/notes/MainActivity.java
   
   
package com.tops.notes;
 
import com.tops.notes.db.NotesDB;
import android.app.Activity;
import android.app.ListActivity;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
 
/**
* 继承ListActivity的Activity,呈现已经存在的日志和添加日志按钮
*
* @author TOPS
*
*/
public class MainActivity extends ListActivity {
private SimpleCursorAdapter adapter = null;
private NotesDB db;
private SQLiteDatabase dbRead;
 
public static final int REQUEST_CODE_ADD_NOTE = 1;
public static final int REQUEST_CODE_EDIT_NOTE = 2;
 
/**
* 实现OnClickListener接口,添加日志按钮的监听
*/
private OnClickListener btnAddNote_clickHandler = new OnClickListener() {
 
@Override
public void onClick(View v) {
// 有返回结果的开启编辑日志的Activity,
// requestCode If >= 0, this code will be returned
// in onActivityResult() when the activity exits.
startActivityForResult(new Intent(MainActivity.this,
AtyEditNote.class), REQUEST_CODE_ADD_NOTE);
}
};
 
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
 
// 操作数据库
db = new NotesDB(this);
dbRead = db.getReadableDatabase();
 
// 查询数据库并将数据显示在ListView上。
// 建议使用CursorLoader,这个操作因为在UI线程,容易引起无响应错误
adapter = new SimpleCursorAdapter(this, R.layout.notes_list_cell, null,
new String[] { NotesDB.COLUMN_NAME_NOTE_NAME,
NotesDB.COLUMN_NAME_NOTE_DATE }, new int[] {
R.id.tvName, R.id.tvDate });
setListAdapter(adapter);
 
refreshNotesListView();
 
findViewById(R.id.btnAddNote).setOnClickListener(
btnAddNote_clickHandler);
}
 
/**
* 复写方法,笔记列表中的笔记条目被点击时被调用,打开编辑笔记页面,同事传入当前笔记的信息
*/
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
 
// 获取当前笔记条目的Cursor对象
Cursor c = adapter.getCursor();
c.moveToPosition(position);
 
// 显式Intent开启编辑笔记页面
Intent i = new Intent(MainActivity.this, AtyEditNote.class);
 
// 传入笔记id,name,content
i.putExtra(AtyEditNote.EXTRA_NOTE_ID,
c.getInt(c.getColumnIndex(NotesDB.COLUMN_NAME_ID)));
i.putExtra(AtyEditNote.EXTRA_NOTE_NAME,
c.getString(c.getColumnIndex(NotesDB.COLUMN_NAME_NOTE_NAME)));
i.putExtra(AtyEditNote.EXTRA_NOTE_CONTENT,
c.getString(c.getColumnIndex(NotesDB.COLUMN_NAME_NOTE_CONTENT)));
 
// 有返回的开启Activity
startActivityForResult(i, REQUEST_CODE_EDIT_NOTE);
 
super.onListItemClick(l, v, position, id);
}
 
/**
* Called when an activity you launched exits, giving you the requestCode
* you started it with 当被开启的Activity存在并返回结果时调用的方法
*
* 当从编辑笔记页面返回时调用,刷新笔记列表
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 
switch (requestCode) {
case REQUEST_CODE_ADD_NOTE:
case REQUEST_CODE_EDIT_NOTE:
if (resultCode == Activity.RESULT_OK) {
refreshNotesListView();
}
break;
 
default:
break;
}
 
super.onActivityResult(requestCode, resultCode, data);
}
 
/**
* 刷新笔记列表,内容从数据库中查询
*/
public void refreshNotesListView() {
/**
* Change the underlying cursor to a new cursor. If there is an existing
* cursor it will be closed.
*
* Parameters: cursor The new cursor to be used
*/
adapter.changeCursor(dbRead.query(NotesDB.TABLE_NAME_NOTES, null, null,
null, null, null, null));
 
}
 
}

编辑笔记页面的java代码:

/Notes/src/com/tops/notes/AtyEditNote.java
   
   
package com.tops.notes;
 
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
 
import android.app.ListActivity;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.tops.notes.db.NotesDB;
 
public class AtyEditNote extends ListActivity {
 
private int noteId = -1;
private EditText etName, etContent;
private MediaAdapter adapter;
private NotesDB db;
private SQLiteDatabase dbRead, dbWrite;
private String currentPath = null;
 
public static final int REQUEST_CODE_GET_PHOTO = 1;
public static final int REQUEST_CODE_GET_VIDEO = 2;
 
public static final String EXTRA_NOTE_ID = "noteId";
public static final String EXTRA_NOTE_NAME = "noteName";
public static final String EXTRA_NOTE_CONTENT = "noteContent";
 
/**
* 按钮点击的监听器,实现OnClickListener接口
*/
private OnClickListener btnClickHandler = new OnClickListener() {
 
Intent i;
File f;
 
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnAddPhoto:// 添加照片按钮
// 使用Intent调用系统照相机,传入图像保存路径和名称
i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
f = new File(getMediaDir(), System.currentTimeMillis() + ".jpg");
if (!f.exists()) {
try {
f.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
currentPath = f.getAbsolutePath();
i.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
startActivityForResult(i, REQUEST_CODE_GET_PHOTO);
break;
case R.id.btnAddVideo:// 添加视频按钮
// 使用Intent调用系统录像器,传入视频保存路径和名称
i = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
f = new File(getMediaDir(), System.currentTimeMillis() + ".mp4");
if (!f.exists()) {
try {
f.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
currentPath = f.getAbsolutePath();
i.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
 
startActivityForResult(i, REQUEST_CODE_GET_VIDEO);
break;
case R.id.btnSave:// 保存按钮
// 保存多媒体信息和笔记信息到数据库,然后关闭当前页面,返回到笔记列表页面/主页面
saveMedia(saveNote());
setResult(RESULT_OK);
finish();
break;
case R.id.btnCancel:// 取消按钮
// 关闭当前页面,返回到笔记列表页面/主页面
setResult(RESULT_CANCELED);
finish();
break;
 
default:
break;
}
}
};
 
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.aty_eidt_note);
 
db = new NotesDB(this);
dbRead = db.getReadableDatabase();
dbWrite = db.getWritableDatabase();
 
// 显示多媒体列表
adapter = new MediaAdapter(this);
setListAdapter(adapter);
 
etName = (EditText) findViewById(R.id.etName);
etContent = (EditText) findViewById(R.id.etContent);
 
// 获取Activity传递过来的noteId
noteId = getIntent().getIntExtra(EXTRA_NOTE_ID, -1);
 
if (noteId > -1) {
etName.setText(getIntent().getStringExtra(EXTRA_NOTE_NAME));
etContent.setText(getIntent().getStringExtra(EXTRA_NOTE_CONTENT));
 
// 查询本笔记的noteId并且检查是否有对应的多媒体,有则遍历显示在MediaList中
Cursor c = dbRead.query(NotesDB.TABLE_NAME_MEDIA, null,
NotesDB.COLUMN_NAME_MEDIA_OWNER_NOTE_ID + "=?",
new String[] { noteId + "" }, null, null, null);
while (c.moveToNext()) {
adapter.add(new MediaListCellData(c.getString(c
.getColumnIndex(NotesDB.COLUMN_NAME_MEDIA_PATH)), c
.getInt(c.getColumnIndex(NotesDB.COLUMN_NAME_ID))));
}
/**
* Notifies the attached observers that the underlying data has been
* changed and any View reflecting the data set should refresh
* itself.
*/
adapter.notifyDataSetChanged();
}
 
findViewById(R.id.btnSave).setOnClickListener(btnClickHandler);
findViewById(R.id.btnCancel).setOnClickListener(btnClickHandler);
findViewById(R.id.btnAddPhoto).setOnClickListener(btnClickHandler);
findViewById(R.id.btnAddVideo).setOnClickListener(btnClickHandler);
}
 
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
 
MediaListCellData data = adapter.getItem(position);
Intent i;
 
switch (data.type) {
case MediaType.PHOTO:
i = new Intent(this, AtyPhotoViewer.class);
i.putExtra(AtyPhotoViewer.EXTRA_PATH, data.path);
startActivity(i);
break;
case MediaType.VIDEO:
i = new Intent(this, AtyVideoViewer.class);
i.putExtra(AtyVideoViewer.EXTRA_PATH, data.path);
startActivity(i);
break;
}
 
super.onListItemClick(l, v, position, id);
}
 
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 
System.out.println(data);
 
switch (requestCode) {
case REQUEST_CODE_GET_PHOTO:
case REQUEST_CODE_GET_VIDEO:
if (resultCode == RESULT_OK) {
adapter.add(new MediaListCellData(currentPath));
adapter.notifyDataSetChanged();
}
break;
default:
break;
}
 
super.onActivityResult(requestCode, resultCode, data);
}
 
/**
* 获取存储Media的目录路径
*
* @return File类型的目录路径
*/
public File getMediaDir() {
File dir = new File(Environment.getExternalStorageDirectory(),
"NotesMedia");
if (!dir.exists()) {
dir.mkdirs();
}
return dir;
}
 
/**
* 保存Media信息到数据库
*
* @param noteId
*/
public void saveMedia(int noteId) {
 
MediaListCellData data;
ContentValues cv;
 
for (int i = 0; i < adapter.getCount(); i++) {
data = adapter.getItem(i);
 
if (data.id <= -1) {
cv = new ContentValues();
cv.put(NotesDB.COLUMN_NAME_MEDIA_PATH, data.path);
cv.put(NotesDB.COLUMN_NAME_MEDIA_OWNER_NOTE_ID, noteId);
dbWrite.insert(NotesDB.TABLE_NAME_MEDIA, null, cv);
}
}
 
}
 
/**
* 保存日志到数据库
*
* @return
*/
public int saveNote() {
 
ContentValues cv = new ContentValues();
cv.put(NotesDB.COLUMN_NAME_NOTE_NAME, etName.getText().toString());
cv.put(NotesDB.COLUMN_NAME_NOTE_CONTENT, etContent.getText().toString());
cv.put(NotesDB.COLUMN_NAME_NOTE_DATE, new SimpleDateFormat(
"yyyy-MM-dd hh:mm:ss").format(new Date()));
 
if (noteId > -1) {
dbWrite.update(NotesDB.TABLE_NAME_NOTES, cv, NotesDB.COLUMN_NAME_ID
+ "=?", new String[] { noteId + "" });
return noteId;
} else {
return (int) dbWrite.insert(NotesDB.TABLE_NAME_NOTES, null, cv);
}
}
 
/**
* 复写Activity的生命周期方法,用于关闭读写数据库的操作
*/
@Override
protected void onDestroy() {
dbRead.close();
dbWrite.close();
super.onDestroy();
}
 
/**
* 继承BaseAdapter类的MediaAdapter类,用于显示媒体信息
*
* @author TOPS
*
*/
static class MediaAdapter extends BaseAdapter {
private Context context;
private List<MediaListCellData> list = new ArrayList<AtyEditNote.MediaListCellData>();
 
public MediaAdapter(Context context) {
this.context = context;
}
 
public void add(MediaListCellData data) {
list.add(data);
}
 
@Override
public int getCount() {
return list.size();
}
 
@Override
public MediaListCellData getItem(int position) {
return list.get(position);
}
 
@Override
public long getItemId(int position) {
return position;
}
 
@Override
public View getView(int position, View convertView, ViewGroup parent) {
 
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(
R.layout.media_list_cell, null);
}
 
MediaListCellData data = getItem(position);
 
ImageView ivIcon = (ImageView) convertView
.findViewById(R.id.ivIcon);
TextView tvPath = (TextView) convertView.findViewById(R.id.tvPath);
 
ivIcon.setImageResource(data.iconId);
tvPath.setText(data.path);
return convertView;
}
 
}
 
/**
* 显示多媒体的条目类
*
* @author TOPS
*
*/
static class MediaListCellData {
int type = 0;
int id = -1;
String path = "";
int iconId = R.drawable.ic_launcher;
 
public MediaListCellData(String path, int id) {
this(path);
 
this.id = id;
}
 
public MediaListCellData(String path) {
this.path = path;
 
if (path.endsWith(".jpg")) {
iconId = R.drawable.icon_photo;
type = MediaType.PHOTO;
} else if (path.endsWith(".mp4")) {
iconId = R.drawable.icon_video;
type = MediaType.VIDEO;
}
}
 
}
 
/**
* 多媒体的种类
*
* @author TOPS
*
*/
static class MediaType {
static final int PHOTO = 1;
static final int VIDEO = 2;
}
}

显示图片的页面:

/Notes/src/com/tops/notes/AtyPhotoViewer.java
   
   
package com.tops.notes;
 
import java.io.File;
 
import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.widget.ImageView;
 
/**
* 显示照片的Activity
*
* @author TOPS
*
*/
public class AtyPhotoViewer extends Activity {
 
private ImageView iv;
 
public static final String EXTRA_PATH = "path";
 
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
 
iv = new ImageView(this);
setContentView(iv);
 
String path = getIntent().getStringExtra(EXTRA_PATH);
if (path != null) {
iv.setImageURI(Uri.fromFile(new File(path)));
} else {
finish();
}
}
 
}

显示视频的页面:

/Notes/src/com/tops/notes/AtyVideoViewer.java
   
   
package com.tops.notes;
 
import android.app.Activity;
import android.os.Bundle;
import android.widget.MediaController;
import android.widget.VideoView;
 
/**
* 显示视频的Activity
*
* @author TOPS
*
*/
public class AtyVideoViewer extends Activity {
 
private VideoView vv;
 
public static final String EXTRA_PATH = "path";
 
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
 
vv = new VideoView(this);
vv.setMediaController(new MediaController(this));
setContentView(vv);
 
String path = getIntent().getStringExtra(EXTRA_PATH);
if (path != null) {
vv.setVideoPath(path);
} else {
finish();
}
}
 
}

操作数据库的类:

/Notes/src/com/tops/notes/db/NotesDB.java
   
   
package com.tops.notes.db;
 
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
 
/**
* 实现SQLiteOpenHelper接口的NotesDB类,用于创建数据库表
*
* @author TOPS
*
*/
public class NotesDB extends SQLiteOpenHelper {
 
public static final String TABLE_NAME_NOTES = "notes";
public static final String TABLE_NAME_MEDIA = "media";
public static final String COLUMN_NAME_ID = "_id";
public static final String COLUMN_NAME_NOTE_NAME = "name";
public static final String COLUMN_NAME_NOTE_CONTENT = "content";
public static final String COLUMN_NAME_NOTE_DATE = "date";
public static final String COLUMN_NAME_MEDIA_PATH = "path";
public static final String COLUMN_NAME_MEDIA_OWNER_NOTE_ID = "note_id";
 
public NotesDB(Context context) {
super(context, "notes", null, 1);
}
 
/**
* 当第一次打开数据库,表不存在时调用,以创建表
*/
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_NAME_NOTES + "(" + COLUMN_NAME_ID
+ " INTEGER PRIMARY KEY AUTOINCREMENT," + COLUMN_NAME_NOTE_NAME
+ " TEXT NOT NULL DEFAULT \"\"," + COLUMN_NAME_NOTE_CONTENT
+ " TEXT NOT NULL DEFAULT \"\"," + COLUMN_NAME_NOTE_DATE
+ " TEXT NOT NULL DEFAULT \"\"" + ")");
db.execSQL("CREATE TABLE " + TABLE_NAME_MEDIA + "(" + COLUMN_NAME_ID
+ " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ COLUMN_NAME_MEDIA_PATH + " TEXT NOT NULL DEFAULT \"\","
+ COLUMN_NAME_MEDIA_OWNER_NOTE_ID
+ " INTEGER NOT NULL DEFAULT 0" + ")");
 
}
 
/**
* 当表存在且是旧版本时调用,删除旧表,创建新表
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
 
}
 
}

manifest文件代码:

/Notes/AndroidManifest.xml
   
   
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tops.notes"
android:versionCode="1"
android:versionName="1.0" >
 
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="21" />
 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:configChanges="keyboardHidden|orientation"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
 
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="AtyEditNote"
android:configChanges="keyboardHidden|orientation" >
</activity>
<activity
android:name="AtyPhotoViewer"
android:configChanges="keyboardHidden|orientation" >
</activity>
<activity
android:name="AtyVideoViewer"
android:configChanges="keyboardHidden|orientation" >
</activity>
</application>
 
</manifest>

八、测试

列出要测试的功能、记录测试时间及操作方式、记录造成BUg出现的操作步骤
发布给提交给客户

测试功能和操作方式:

应用的功能是否达到需求,达到了。
数据库创建是否成功,成功了,两个理由:查看目录知道有数据库文件;关闭应用重新打开时笔记不会消失。

运行截图:





查看照片

播放视频




后记:

这因为只是学习实践,为了练习Android使用SQLite,listview、Intent等知识点所做,但是功能还是太简单、界面太简陋、需要慢慢优化,比较好的学习对象是随笔记/gnote。

源码下载:http://download.csdn.net/detail/huolangge/8221669


  • 36
    点赞
  • 234
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值