1.项目的需求(功能需求,数据库的需求)

实现功能,可以创建记事本。用户可以随时增加记事,如果不为记事的内容起名,以时间命名。将记事本的内容存储到数据库中,可实现内容的增删改查。

查询时,可查询模糊查询内容,按创建的时间查询。主页面要展示所有记事内容,在浏览时,可按类别进行浏览,按时间顺序浏览。此外还有设置定时闹钟的功能。

2.项目的设计

本项目要开发的备忘录功能很简单,但是使用起来也很方便,类似于便签纸的功能。一

个标题,一个内容加上可以设置闹钟,就基本组成了备忘录所有的功能。备忘录的主界面

如图1所示,最上面一个大大的“添加”按钮用于新建文件,中间显示备忘录的内容。

最下面一排按钮用于切换页面。

3.关键的代码

Android主要代码

主要代码(要有必要的注释,注释内容不少于10%)

  1. 布局文件

主界面设计步骤如下:

在res/layout下新建home.xml, 代码如下所示,整个根节点采用RelativeLayout布局,最上方采用一个大大的Button用于显示“添加”。中间显示数据库中所有的备忘录文件,最下面是一个分页的组件,用一个Linearlayout包含4个按钮。

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_height="match_parent"

>

<!-- 添加按钮 -->

<Button

android:id="@+id/btnAdd"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:gravity="center_vertical|center_horizontal"

android:text="添加"

/>

<!-- 文章列表,用于显示所有备忘录 -->

<ListView

android:id="@+id/listview"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:layout_below="@+id/btnAdd"

android:layout_above="@+id/linearLayout1"

/>

<!-- 底部按钮 -->

<LinearLayout

android:id="@+id/linearLayout1"

android:orientation="horizontal"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerHorizontal="true"

android:gravity="center"

android:layout_alignParentBottom="true"

>

<!-- 首页按钮 -->

<Button

android:id="@+id/btnFirst"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="   "

/>

<!-- 上一页按钮 -->

<ImageButton

android:id="@+id/btnPre"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/preview"

/>

<!-- 下一个按钮 -->

<ImageButton

android:id="@+id/btnNext"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/next"

/>

<!-- 下一页按钮 -->

<Button

android:id="@+id/btnEnd"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="   "

/>

<!-- 进度条 -->

</LinearLayout>

<ProgressBar

android:id="@+id/progressBar"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

style="?android:attr/progressBarStyleLarge"

android:max="100"

android:progress="50"

android:secondaryProgress="70"

android:layout_centerInParent="true"

android:visibility="gone"

/>

</RelativeLayout>

其中用于匹配ListView每二行元素的布局文件如下所示,用一个TextView显示备忘录的标题。

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="horizontal"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="@drawable/item"

>

<!-- ListView元素 -->

<TextView

android:id="@+id/noteName"

android:layout_width="130px"

android:layout_height="30px"

android:gravity="center_vertical|left"

android:textSize="20px"

android:layout_marginLeft="10px"

android:textColor="#333333"

/>

</LinearLayout>

主界面功能

主界面功能的实现分以下几步:

  1. 首先这个程序是采用Sqlite存储数据的,因此首先需要新建一个数据库帮助类,用于创建、打开和读写数据库。代码如下所示,新建SqliteDBConneet.java,并重写onCrete()和onUpgrade()函数。

package com.guo.memorandum;

import android.content.Context;

import android.database.sqlite.SQLiteDatabase;

import android.database.sqlite.SQLiteOpenHelper;

public class SqliteDBConnect extends SQLiteOpenHelper {

//创建一个帮助类,用于创建、打开和管理数据库

public SqliteDBConnect(Context context) {

super(context, "NotePad", null, 1);

}

//创建数据库,第一次调用的时候执行,之后不再执行

@Override

public void onCreate(SQLiteDatabase db) {

System.out.println("Table before Create");

db.execSQL("create table note(noteId Integer primary key,noteName varchar(20),noteTime varchar(20),noteContent varchar(400))");

System.out.println("Table after Create");

}

//数据库升级的时候调用

@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

}

}

新建MainActivity.java,首先声明一些需要用到的变量,如每页显示的数目、数据库帮助类、当前的页码、总页数等。接者在onCreate中初始化页面的元素,实例化数据库帮助类。

public class MainActivity extends Activity {

//用于显示备忘录文件

private ListView lv;

//数据库帮助类

private SqliteDBConnect sd;

//每页显示的数目

private static int page_size = 8;

//初始化页数

private static int page_no = 1, page_count = 0, count = 0;

//添加、首页、末页按钮

private Button btnAdd, btnFirst, btnEnd;

//图像按钮:前一页、后一页

private ImageButton btnNext, btnPre;

//适配器

private SimpleAdapter sa;

//进度条

private ProgressBar m_ProgressBar;

private ActivityManager am;

@Override

protected void onCreate(Bundle savedInstanceState) {

// TODO Auto-generated method stub

super.onCreate(savedInstanceState);

// 设置显示进度条

setProgressBarVisibility(true);

setContentView(R.layout.home);

//实例化ActivityManager

am = ActivityManager.getInstance();

am.addActivity(this);

//初始化按钮

btnAdd = (Button) findViewById(R.id.btnAdd);

btnFirst = (Button) findViewById(R.id.btnFirst);

btnPre = (ImageButton) findViewById(R.id.btnPre);

btnNext = (ImageButton) findViewById(R.id.btnNext);

btnEnd = (Button) findViewById(R.id.btnEnd);

//初始化进度条

m_ProgressBar = (ProgressBar) findViewById(R.id.progressBar);

lv = (ListView) findViewById(R.id.listview);

//初始化数据库

sd = new SqliteDBConnect(MainActivity.this);

//获取数据库数据并分页显示

fenye();

//设置ListView按键监听器

lv.setOnItemClickListener(new OnItemClickListener() {

@Override

public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,

long arg3) {

@SuppressWarnings("unchecked")

Map<String, Object> map = (Map<String, Object>) arg0

.getItemAtPosition(arg2);

Intent intent = new Intent();

//传递备忘录的noteId

intent.putExtra("noteId", map.get("noteId").toString());

intent.setClass(MainActivity.this, Lookover.class);

//查看备忘录

startActivity(intent);

}

});

最后,我们要为各个按键绑定监听器。首先是单击列表选项时将进入Lookover查看备忘录信息,如代码002~016行所示,长按列表选项时将弹出对话框并提供“删除”和“修改”两个选项,如代码018~063行所示。065~076行用于为“添加”按钮设置按键监听器,当单击“添加”按钮时,页面将跳转到AddActivity。 078~139行用于设置分页相关按钮的功能。

//设置ListView长按监听器

lv.setOnItemLongClickListener(new OnItemLongClickListener() {

@Override

public boolean onItemLongClick(AdapterView<?> arg0, View arg1,

int arg2, long arg3) {

@SuppressWarnings("unchecked")

final Map<String, Object> map = (Map<String, Object>) arg0

.getItemAtPosition(arg2);

AlertDialog.Builder adb = new Builder(MainActivity.this);

adb.setTitle(map.get("noteName").toString());

//设置弹出选项

adb.setItems(new String[] { "删除", "修改"},

new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog,

int which) {

switch (which) {

//删除

case 0:

SQLiteDatabase sdb = sd

.getReadableDatabase();

sdb.delete("note", "noteId=?",

new String[] { map.get("noteId")

.toString() });

Toast.makeText(MainActivity.this, "删除成功",

Toast.LENGTH_SHORT).show();

sdb.close();

//刷新页面

fenye();

break;

//修改

case 1:

Intent intent = new Intent();

intent.putExtra("noteId", map.get("noteId")

.toString());

intent.setClass(MainActivity.this, AddActivity.class);

//进入编辑页面

startActivity(intent);

break;

}

}

});

//显示对话框

adb.show();

return true;

}

});

//设置添加按钮监听器

btnAdd.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

//显示进度条

m_ProgressBar.setVisibility(View.VISIBLE);

m_ProgressBar.setProgress(0);

Intent intent = new Intent();

intent.setClass(MainActivity.this, AddActivity.class);

//进入添加页面

startActivity(intent);

}

});

//进入首页

btnFirst.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

//如果是首页,提示用户当前已经是首页了

if (page_no == 1) {

Toast.makeText(MainActivity.this, "已经是首页了", Toast.LENGTH_SHORT)

.show();

} else {

//如果不是首页则将当前页码置为1

page_no = 1;

}

//刷新页面

fenye();

}

});

//下一页按键监听器

btnNext.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

//如果当前是最后一页,则提示用户已经到最后一页了

if (page_no == page_count) {

Toast.makeText(MainActivity.this, "已经是末页了", Toast.LENGTH_SHORT)

.show();

} else {

//否则,当前的页码加1

page_no += 1;

}

//刷新页面

fenye();

}

});

//上一页按键监听器

btnPre.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

//如果当前是第一页,则提示用户当前已经是首页了

if (page_no == 1) {

Toast.makeText(MainActivity.this, "已经是首页了", Toast.LENGTH_SHORT)

.show();

} else {

//否则,当前页码减1

page_no -= 1;

}

//刷新页面

fenye();

}

});

//设置末页按键监听器

btnEnd.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

//如果当前是最后一页,提示用户当前已经是末页了

if (page_no == page_count) {

Toast.makeText(MainActivity.this, "已经是末页了", Toast.LENGTH_SHORT)

.show();

} else {

//否则将当前页置为末页

page_no = page_count;

}

//刷新页面

fenye();

}

});

}

接着执行分页函数用于获取数据库的数据显示到页面中,分页函数的实现代码如下所示。

如代码06~17行所示,先取得数据的总页数。接着根根据当前选择的页码,从数据库中取得相应的数据存储到一 个个map中,然后将所有的map存储到lst中,最后为ListView,新建一 个简单适配器,将list 中数据适配到LstView中

//获取数据库数据并分页显示

public void fenye() {

SQLiteDatabase sdb = sd.getReadableDatabase();

count = 0;

// 从数据库中查询数据,按升序排列

Cursor c1 = sdb.query("note", new String[] { "noteId", "noteName",

"noteTime" }, null, null, null, null, "noteId asc");

while (c1.moveToNext()) {

int noteid = c1.getInt(c1.getColumnIndex("noteId"));

//保存数据的总数

if (noteid > count)

count = noteid;

}

c1.close();

//取得总页数

page_count = count % page_size == 0 ? count / page_size : count

/ page_size + 1;

//到达首页

if (page_no < 1)

page_no = 1;

//到达末页

if (page_no > page_count)

page_no = page_count;

//查询指定页的数据

Cursor c=sdb.rawQuery("select noteId,noteName,noteTime from note limit ?,?", new String[] {

(page_no - 1) * page_size + "", page_size + "" });

List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();

//遍历循环,取得所有数据,并存储到list中

while (c.moveToNext()) {

Map<String, Object> map = new HashMap<String, Object>();

//取得备忘录的名字

String strName = c.getString(c.getColumnIndex("noteName"));

//如果字数超过12个则去掉后面的字符用...代替

if (strName.length() > 20) {

map.put("noteName", strName.substring(0, 20) + "...");

} else {

map.put("noteName", strName);

}

//取得时间和id信息,存储到map中

map.put("noteTime", c.getString(c.getColumnIndex("noteTime")));

map.put("noteId", c.getInt(c.getColumnIndex("noteId")));

//将map添加到list中

list.add(map);

}

c.close();

sdb.close();

if (count > 0) {

//新建适配器

sa = new SimpleAdapter(MainActivity.this, list, R.layout.items,

new String[] { "noteName", "noteTime" }, new int[] {

R.id.noteName, R.id.noteTime });

//设置适配器

lv.setAdapter(sa);

}

}

接着我们设置菜单按钮的功能,重写面写onMenuItemSelectedO函数menu. add添加菜单项“设置铃声”和“退出”。同时需要重万生页面将跳转到设置铃声的页为菜单项设置相应的功能,当单击“设置铃声”按钮的时候,“退出”按钮时,页面将会跳转关于设置铃声页面,我们接下去会讲解到,目前 先略过。当单击会弹出对话程,询问用户是否确定退出,若确定退出则关闭所有Activity此外,当用户想要退出程序的时候也可以按Back键,重写onKeyDown方法,对Back按键进行判断,若是Back按键则弹出对话框,让用户选择是否退出本程序。

//菜单按钮

@Override

public boolean onCreateOptionsMenu(Menu menu) {

//添加菜单项

menu.add(0, 1, 1, "设置铃声");

menu.add(0, 2, 2, "退出");

return super.onCreateOptionsMenu(menu);

}

//为菜单按钮绑定按键监听器

@Override

public boolean onMenuItemSelected(int featureId, MenuItem item) {

switch (item.getItemId()) {

//设置铃声

case 1:

Intent intent=new Intent();

intent.setClass(MainActivity.this,SetAlarm.class);

//跳转到设置铃声的界面

startActivity(intent);

break;

//退出

case 2:

AlertDialog.Builder adb2 = new Builder(MainActivity.this);

adb2.setTitle("消息");

adb2.setMessage("真的要退出吗?");

adb2.setPositiveButton("确定", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

//关闭所有的Activity

am.exitAllProgress();

}

});

adb2.setNegativeButton("取消", null);

//显示对话框,询问用户是否确定要退出

adb2.show();

break;

default:

break;

}

return super.onMenuItemSelected(featureId, item);

}

//当用户按键时触发

@Override

public boolean onKeyDown(int keyCode, KeyEvent event) {

//如果用户按下了back键

if (keyCode == KeyEvent.KEYCODE_BACK) {

AlertDialog.Builder adb = new Builder(MainActivity.this);

adb.setTitle("消息");

adb.setMessage("真的要退出?");

adb.setPositiveButton("确定", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

am.exitAllProgress();

}

});

adb.setNegativeButton("取消", null);

//显示对话框询问用户是否确定要退出

adb.show();

}

return super.onKeyDown(keyCode, event);

}

}

3添加和更新备忘承页面

如图所示为添加备忘录的页面,从上到下分为四部分:标题、闹钟、内容和功能按钮。

如下所示,是添加页面的代码实现部分,标题和闹钟采用EditText, 其中闹钟为了保

证格式的正确,将其设置成不可编辑,而通过其他方式去改变闹钟的时间。view采用我们

自定义的视图类com.guo.memorandum.LinedEditText实现,接下去会作进一步分析,最下

面两个按钮分别用于实现保存和取消的功能。

<?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:orientation="vertical" >

<!-- 标题 -->

<EditText

android:id="@+id/noteName"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:hint="请输入标题"

android:textColor="#0000ff" />

<!-- 闹钟时间 -->

<EditText

android:id="@+id/noteTime"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_below="@+id/noteName"

android:editable="false"

android:textColor="#0000ff" />

<!-- 备忘录内容 -->

<view

xmlns:android="http://schemas.android.com/apk/res/android"

android:id="@+id/noteMain"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:layout_below="@+id/noteTime"

android:layout_above="@+id/relativeLayout1"

class="com.guo.memorandum.LinedEditText"

android:background="@drawable/background"

android:capitalize="sentences"

android:fadingEdge="vertical"

android:gravity="top"

android:padding="5dip"

android:scrollbars="vertical"

android:hint="请输入内容"

android:textColor="#0000ff" />

<!-- 底部按钮 -->

<RelativeLayout

android:id="@+id/relativeLayout1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_alignParentBottom="true"

android:layout_centerHorizontal="true" >

<!-- 保存按钮 -->

<Button

android:id="@+id/btnCommit"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="保  存" />

<!-- 取消按钮 -->

<Button

android:id="@+id/btnCancel"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_toRightOf="@+id/btnCommit"

android:text="取  消" />

</RelativeLayout>

</RelativeLayout>

如下所示是上面view的实现代码,通过继承于EditText,自定义一些风格, 如文字颜

色变成蓝色,为每行文字增加 下划线等。

public class LinedEditText extends EditText {

private Rect mRect;

private Paint mPaint;

//构造函数

public LinedEditText(Context context, AttributeSet attrs) {

super(context, attrs);

mRect = new Rect();

//设置颜料颜色为蓝色

mPaint = new Paint();

mPaint.setColor(Color.BLUE);

}

//生成视图

@Override

protected void onDraw(Canvas canvas) {

int count = getLineCount();

Rect r = mRect;

Paint paint = mPaint;

//设置每一行的格式

for (int i = 0; i < count; i++) {

//取得每一行的基准Y坐标,并将每一行的界限值填写到r中

int baseline = getLineBounds(i, r);

//设置每一行的文字下带下划线

canvas.drawLine(r.left, baseline + 5, r.right, baseline + 5, paint);

}

super.onDraw(canvas);

}

}

4添加和更新备忘录功能实现

(1)这部分的核心功能主要分为两部分,一个是闹钟的设定,一个是内容的保存。 当然,一如既往地,我们需要先声明一些变量以及初始化界面元素,代码如下所示。代码15行声明了一个编辑模式的标志变量EDIT,默认值为false,即非编辑模式。当获得的noteId变量不为null时,说明目前正在进入的是编辑模式,将EDIT变量设置为true,并从数据库中取得相应的信息,填入对应的文本框中。

public class AddActivity extends Activity {

//标题、内容和时间

private EditText etName,etMain, etTime;

//保存按钮、取消按钮

private Button btnCommit,btnCancel;

//数据库操作类

private SQLiteDatabase sdb;

private ActivityManager am;

//年月日时分秒,用于保存日历详细信息

private int year, month, day, hours, minute, second;

private Calendar c;

private PendingIntent pi;

private AlarmManager alm;

//编辑模式标志

private boolean EDIT=false;

private String noteId;

//初始化函数

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.add);

//将当前Activity添加到Activity列表中

am = ActivityManager.getInstance();

am.addActivity(this);

//初始化各个元素

etName = (EditText) findViewById(R.id.noteName);

etMain = (EditText) findViewById(R.id.noteMain);

btnCommit = (Button) findViewById(R.id.btnCommit);

btnCancel = (Button) findViewById(R.id.btnCancel);

etTime = (EditText) findViewById(R.id.noteTime);

Intent intent=getIntent();

noteId = intent.getStringExtra("noteId");

//如果noteId值不为空,则进入编辑模式

if(noteId != null)

EDIT=true;

else

EDIT=false;

//数据库连接类

SqliteDBConnect sd = new SqliteDBConnect(AddActivity.this);

//获得数据库操作类

sdb = sd.getReadableDatabase();

if(EDIT)

{

//通过noteId取得对应的信息

Cursor c = sdb.query("note", new String[] { "noteId", "noteName",

"noteContent", "noteTime" }, "noteId=?",

new String[] { noteId }, null, null, null);

//将获得的信息写入对应的EditText

while (c.moveToNext()) {

etName.setText(c.getString(c.getColumnIndex("noteName")));

etMain.setText(c.getString(c.getColumnIndex("noteContent")));

etTime.setText(c.getString(c.getColumnIndex("noteTime")));

}

c.close();

}else{

//设置默认闹钟为当前时间

etTime.setText(am.returnTime());

}

//设置文本颜色为红色

(2)接下去要为界面中一 些可单击的地方设置监听器,首先是日期和时间的设定。如代码001~110行所示,分别为时间显示区域设置长按监听器和单击监听器,这两种方式类似,下面就以日期为例讲解一下吧。首先获得当前的日历,并分别提取时分秒的信息,接着新建一个DatePickerDialog 用于选择日期,默认日期显示为当前日期。当用户设置好日期后,将触发onDateSet()函数,在该函数中将当前日期更新到对应的EditText中。单击“保存”按钮和“取消”按钮均会弹出对话框让用户进一步选择, 若确定保存则调用saveNote()函数保存备忘录,若取消保存则直接进入主页面并关闭当前页面。

etTime.setTextColor(Color.RED);

//为闹钟设置长按监听器,弹出日期选择界面

etTime.setOnLongClickListener(new OnLongClickListener() {

@Override

public boolean onLongClick(View v) {

//实例化日历

c = Calendar.getInstance();

//取得日历信息中的年月日时分秒

year = c.get(Calendar.YEAR);

month = c.get(Calendar.MONTH);

day = c.get(Calendar.DAY_OF_MONTH);

hours = c.get(Calendar.HOUR);

minute = c.get(Calendar.MINUTE);

second = c.get(Calendar.SECOND);

//新建一个日期选择控件

DatePickerDialog dpd = new DatePickerDialog(AddActivity.this,

new DatePickerDialog.OnDateSetListener() {

//设置日期的时候触发

@Override

public void onDateSet(DatePicker view, int y,

int monthOfYear, int dayOfMonth) {

String[] time = { "",

hours + ":" + minute + ":" + second };

try {

//将日期和时间分割

String[] time2 = etTime.getText()

.toString().trim().split(" ");

//取得时间的信息保存到time[1]中

if (time2.length == 2) {

time[1] = time2[1];

}

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

String mo = "", da = "";

//将月份转换成两位数

if (monthOfYear < 9) {

mo = "0" + (monthOfYear + 1);

} else {

mo = monthOfYear+1 + "";

}

//将天数转换成两位数

if (dayOfMonth < 10) {

da = "0" + dayOfMonth;

} else {

da = dayOfMonth + "";

}

//将设置的结果保存到etTime中

etTime.setText(y + "-" + mo + "-" + da + " "

+ time[1]);

}

}, year, month, day);

dpd.setTitle("设置日期");

//显示日期控件

dpd.show();

return true;

}

});

//设置单击监听器,弹出时间选择界面

etTime.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

//实例化日历

c = Calendar.getInstance();

//取得当前的年月日信息

year = c.get(Calendar.YEAR);

month = c.get(Calendar.MONTH);

day = c.get(Calendar.DAY_OF_MONTH);

//注意这里不是HOUR,HOUR返回的是12制的时间格式

hours = c.get(Calendar.HOUR_OF_DAY);

minute = c.get(Calendar.MINUTE);

second = c.get(Calendar.SECOND);

//新建时间选择器

TimePickerDialog tpd = new TimePickerDialog(AddActivity.this,

new OnTimeSetListener() {

@Override

public void onTimeSet(TimePicker view,

int hourOfDay, int minute) {

String[] time = {

year + "-" + month + "-" + day, "" };

try {

//分割时间和日期

time = etTime.getText().toString().trim()

.split(" ");

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

String ho = "", mi = "";

//设置小时

if (hourOfDay < 10) {

ho = "0" + hourOfDay;

} else {

ho = hourOfDay + "";

}

//设置分钟

if (minute < 10) {

mi = "0" + minute;

} else {

mi = minute + "";

}

//将设置的结果保存到etTime中

etTime.setText(time[0] + " " + ho + ":" + mi);

}

}, hours, minute, true);

tpd.setTitle("设置时间");

//显示时间控件

tpd.show();

}

});

//保存按钮监听器

btnCommit.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

AlertDialog.Builder adb = new Builder(AddActivity.this);

//设置标题和信息

adb.setTitle("保存");

adb.setMessage("确定要保存吗?");

//设置按钮功能

adb.setPositiveButton("保存",

new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog,

int which) {

//保存备忘录信息

saveNote();

}

});

adb.setNegativeButton("取消",

new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog,

int which) {

Toast.makeText(AddActivity.this, "不保存",

Toast.LENGTH_SHORT).show();

}

});

//显示对话框

adb.show();

}

});

//设置取消按钮监听器

btnCancel.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

AlertDialog.Builder adb = new Builder(AddActivity.this);

//设置标题和消息

adb.setTitle("提示");

adb.setMessage("确定不保存吗?");

//设置按键监听器

adb.setPositiveButton("确定",

new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog,

int which) {

//进入主界面

Intent intent = new Intent();

intent.setClass(AddActivity.this,

MainActivity.class);

startActivity(intent);

}

});

adb.setNegativeButton("取消", null);

//显示对话框

adb.show();

}

});

}

我们要为页面设置菜单选项,如02~ 08行所示。接着为菜单选项设置相应的功能。如代码11~ 47行所示。代码50~ 76保存当前文档。代码78~ 83行所示,意外按到Back键时不会立即退出,而会询问用户是否果界面退出前关闭了数据库。我们在onDestroyO函数中关闭了数据库,这样就确保界面退出前关闭了数据库。

//新建菜单选项

@Override

public boolean onCreateOptionsMenu(Menu menu) {

menu.add(0, 1, 1, "关于");

menu.add(0, 2, 2, "设置闹铃");

menu.add(0, 3, 3, "退出");

return super.onCreateOptionsMenu(menu);

}

//为菜单选项绑定监听器

@Override

public boolean onMenuItemSelected(int featureId, MenuItem item) {

switch (item.getItemId()) {

//关于

case 1:

AlertDialog.Builder adb = new Builder(AddActivity.this);

adb.setTitle("关于");

adb.setMessage("备忘录V1.0");

adb.setPositiveButton("确定", null);

adb.show();

break;

//设置闹铃

case 2:

Intent intent = new Intent();

intent.setClass(AddActivity.this, SetAlarm.class);

startActivity(intent);

break;

//退出

case 3:

AlertDialog.Builder adb2 = new Builder(AddActivity.this);

adb2.setTitle("消息");

adb2.setMessage("真的要退出吗?");

adb2.setPositiveButton("确定", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

//关闭列表中的所有Activity

am.exitAllProgress();

}

});

adb2.setNegativeButton("取消", null);

//显示对话框

adb2.show();

break;

default:

break;

}

return super.onMenuItemSelected(featureId, item);

}

//按键判断

@Override

public boolean onKeyDown(int keyCode, KeyEvent event) {

//当按键是返回键时

if (keyCode == KeyEvent.KEYCODE_BACK) {

AlertDialog.Builder adb = new Builder(AddActivity.this);

adb.setTitle("消息");

adb.setMessage("是否要保存?");

adb.setPositiveButton("保存", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

//保存备忘录

saveNote();

}

});

adb.setNegativeButton("不保存", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

Intent intent2 = new Intent();

intent2.setClass(AddActivity.this, MainActivity.class);

//回到主页面

startActivity(intent2);

}

});

//显示对话框

adb.show();

}

return super.onKeyDown(keyCode, event);

}

(3)保存备忘录的函数如下所示,根据编辑模式与否,选择是添加记录或者更新记录,

保存完记录之后还要设置闹钟。代码46~ 56行为设置闹钟的函数,通过PendingIntent 将

备忘录的标题和内容信息传递给AlarmNote,在指定时间将会调用AlarmNote,并显示标题

和内容信息。

//保存备忘录

public void saveNote() {

//取得输入的内容

String name = etName.getText().toString().trim();

String content = etMain.getText().toString().trim();

String time = etTime.getText().toString().trim();

//内容和标题都不能为空

if ("".equals(name) || "".equals(content)) {

Toast.makeText(this, "名称和内容都不能为空", Toast.LENGTH_SHORT)

.show();

} else {

if(EDIT)

{

am.saveNote(sdb, name, content, noteId, time);

Toast.makeText(this, "更新成功", Toast.LENGTH_SHORT)

.show();

}

else

{

am.addNote(sdb, name, content, time);

Toast.makeText(this, "添加成功", Toast.LENGTH_SHORT)

.show();

}

//分割日期和时间

String[] t = etTime.getText().toString().trim().split(" ");

//分割日期

String[] t1 = t[0].split("-");

//分割时间

String[] t2 = t[1].split(":");

//实例化日历

Calendar c2 = Calendar.getInstance();

//设置日历为闹钟的时间

c2.set(Integer.parseInt(t1[0]), Integer.parseInt(t1[1])-1,

Integer.parseInt(t1[2]), Integer.parseInt(t2[0]),

Integer.parseInt(t2[1]));

c=Calendar.getInstance();

//闹钟的时间应至少比现在多10s

if (c.getTimeInMillis() + 1000 * 10 <= c2.getTimeInMillis()) {

String messageContent;

//当内容字数大于20个字时,切掉一部分以‘...’代替,并存储在messageContent中

if (content.length() > 20) {

messageContent = content.substring(0, 18) + "...";

} else {

messageContent = content;

}

Intent intent = new Intent();

intent.setClass(this, AlarmNote.class);

//传递标题和内容信息

intent.putExtra("messageTitle", name);

intent.putExtra("messageContent", messageContent);

pi = PendingIntent.getBroadcast(this, 0, intent,

PendingIntent.FLAG_UPDATE_CURRENT);

//获得闹钟服务

alm = (AlarmManager) getSystemService(ALARM_SERVICE);

//设置闹钟

alm.set(AlarmManager.RTC_WAKEUP, c2.getTimeInMillis(), pi);

}

Intent intent2 = new Intent();

intent2.setClass(this, MainActivity.class);

//回到主目录

startActivity(intent2);

AddActivity.this.finish();

}

}

@Override

public void onDestroy()

{

super.onDestroy();

//关闭数据库连接

sdb.close();

}

}

5闹钟设置和实现

当我们单击主页面菜单中或者备忘录添加页面菜单中的“设置铃声”选项时,页面将跳转到SetAarmjava,如图所示。

下面分几个步骤讲解:

铃声设置的页面设计代码如下所示,最上面使用一个TextView显示“音乐列表”,ListView显示音乐文件列表。

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_height="match_parent"

>

<!-- 标题 -->

<TextView

android:id="@+id/title"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/music"

android:gravity="center_vertical|center_horizontal"

android:textSize="20px"

/>

<!-- 显示SD卡目录下的音乐文件列表 -->

<ListView

android:id="@+id/list"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="#aaaaaa"

/>

</LinearLayout>

(3)设置阔铃界面对应的程序代码如下所示,先声明需要用到的几个变量,将音乐的

搜索目录设置为SD根目录。在初始化函数onCreate0中执行musicList初始化音乐列表,

在函数musicListO中遍历SD根目录,搜索所有以.mp3结尾的文件,并显示在列表中。接

着为列表元素绑定监听器,如代码40行所示,当单击“列表元素”时将弹出对话框,询问

用户是否将当前选中的音乐设置为铃声,单击“确定”按钮将会保存当前的铃声方案。

public class SetAlarm extends Activity {

//显示音乐文件的列表

private ListView listV;

//列表适配器

private SimpleAdapter sa;

//音乐文件搜索路径

private static final String MUSIC_PATH = new String("/sdcard/");

@Override

protected void onCreate(Bundle savedInstanceState) {

// TODO Auto-generated method stub

super.onCreate(savedInstanceState);

setContentView(R.layout.musicmain);

listV = (ListView) findViewById(R.id.list);

//显示音乐文件

musicList();

//设置按键监听器

listV.setOnItemClickListener(new OnItemClickListener() {

@SuppressWarnings("unchecked")

@Override

public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,

long arg3) {

Map<String, String> map = (Map<String, String>)arg0.getItemAtPosition(arg2);

//取得音乐文件名称

final String name = map.get("musicName");

//创建对话框

AlertDialog.Builder adb = new Builder(SetAlarm.this);

adb.setTitle("提示消息");

adb.setMessage("确定要将 "+name+" 设置为默认闹铃声吗?");

adb.setPositiveButton("确定", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

Uri uri = Uri.parse(MUSIC_PATH + name);

//设置闹铃的路径

ActivityManager.setUri(uri);

Toast.makeText(SetAlarm.this, "设置成功",Toast.LENGTH_SHORT).show();

//关闭当前页面

finish();

}

});

adb.setNegativeButton("取消",null);

//显示对话框

adb.show();

}

});

}

//显示音乐文件列表

public void musicList() {

//取得需要遍历的文件目录

File home = new File(MUSIC_PATH);

List<Map<String, String>> list = new ArrayList<Map<String, String>>();

//遍历文件目录

if (home.listFiles(new MusicFilter()).length > 0) {

for (File file : home.listFiles(new MusicFilter())) {

Map<String, String> map = new HashMap<String, String>();

map.put("musicName", file.getName());

list.add(map);

}

sa = new SimpleAdapter(SetAlarm.this, list, R.layout.musicitems,

new String[] { "musicName" }, new int[] { R.id.musicName });

listV.setAdapter(sa);

}

}

}

//过滤所有不是以.mp3结尾的文件

class MusicFilter implements FilenameFilter {

public boolean accept(File dir, String name) {

return (name.endsWith(".mp3"));

}

}

在Alarm中主要实现播放闹铃,并显示对话框让用户可以关掉闹铃。如下所示,

代码35~43行用于显示备忘录的标题和内容。

public class Alarm extends Activity {

//媒体播放器

private MediaPlayer mMediaPlayer;

@Override

protected void onCreate(Bundle savedInstanceState) {

// TODO Auto-generated method stub

super.onCreate(savedInstanceState);

setContentView(R.layout.alarm);

try {

//播放指定的音乐

mMediaPlayer=MediaPlayer.create(Alarm.this,ActivityManager.getUri());

//设置播放的音量

mMediaPlayer.setVolume(300, 350);

//设置循环

mMediaPlayer.setLooping(true);

} catch (Exception e) {

Toast.makeText(Alarm.this,"音乐文件播放异常",Toast.LENGTH_SHORT);

}

//开始播放

mMediaPlayer.start();

Intent intent=getIntent();

//获得标题

String messageTitle=intent.getStringExtra("messageTitle");

//获得内容

String messageContent=intent.getStringExtra("messageContent");

//新建对话框

AlertDialog.Builder adb=new Builder(Alarm.this);

adb.setTitle(messageTitle);

adb.setMessage(messageContent);

adb.setPositiveButton("确定", new OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

//关闭媒体播放器

mMediaPlayer.stop();

mMediaPlayer.release();

finish();

}

});

//显示对话框

adb.show();

}

}

6.公共类的实现,新建AcriManagrgiava代码如下所示,这个类主要用来实现整个程序需要共同使用的一些函数, 代码15 行声明了个静态变量instarce 用于存储AtiviyManager 的实例,每次对这个类进行实例化,得到的都是同一个实例。getUri和setUri分别用于获取和设置铃声的地址,exitAllProcess()函 数用于在程序退出时调用,以关闭所有界面,addNote 和saveNote 分别用于添加备忘录和保存备忘录,retumTime用于以特定格式返回当前的时间和日期。

public class ActivityManager {

//用静态变量存储实例

private static ActivityManager instance;

private List<Activity> list;

//默认铃声的地址

private static Uri uri=Uri.parse("/sdcard/demo.mp3");

public static ActivityManager getInstance() {

if (instance == null)

instance = new ActivityManager();

return instance;

}

//添加Activity进列表

public void addActivity(Activity av) {

//如果列表为空则新建列表

if(list==null)

list=new ArrayList<Activity>();

if (av != null) {

list.add(av);

}

}

//获得铃声的路径

public static Uri getUri() {

return uri;

}

//设置铃声

public static void setUri(Uri uri) {

ActivityManager.uri = uri;

}

//退出所有程序

public void exitAllProgress() {

for (int i = 0; i < list.size(); i++) {

Activity av = list.get(i);

av.finish();

}

}

//更新文件

public void saveNote(SQLiteDatabase sdb,String name,String content,String noteId,String time){

ContentValues cv=new ContentValues();

cv.put("noteName", name);

cv.put("noteContent", content);

cv.put("noteTime", time);

sdb.update("note", cv, "noteId=?", new String[]{noteId});

}

//添加文件

public void addNote(SQLiteDatabase sdb,String name,String content,String time){

ContentValues cv=new ContentValues();

cv.put("noteName", name);

cv.put("noteContent", content);

cv.put("noteTime", time);

sdb.insert("note", null, cv);

}

//返回当前的时间

public String returnTime(){

Date d=new Date();

SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

String time=sdf.format(d);

return time;

}

}

4.测试用例

(1)用例包括:用例名称,输入数据或操作过程,预期结果,实际结果。

Appium 自动化移动App测试整体流程

一、使用Eclipse直接创建案例工程

  1、打开Eclipse,【File】-->【New】-->【Java Project】 2、选择【Java Project】  3、输入工程名称Appium_demo,点击【Finish】4、右键点击工程 Appium_demo -->【New】-【Folder】->【Folder name】apps,目录结构如下:

  • 导入测试的类库

1、右键点击工程,选择【Build Path】-->【Configure Build Path】--> 【libraries】-->【Add External JARs】把以下4个文件导入。

1)导入Selenum类库:

建议使用版本,selenium-java-3.1.0.zip中的client-combined-3.1.0-nodeps.jar文件;

https://npm.taobao.org/mirrors/selenium/

2)建议使用版本,  selenium-server-standalone-3.1.0.jar;

https://npm.taobao.org/mirrors/selenium/
        3)导入Appium类库:强烈建议使用版本,java-client-4.1.2.jar,       

  1. 导入Appium类库java-client-4.1.2-sources.jar

Maven Central Repository Search

三、1、下载测试的文件,

2、将下载的apk放到项目的apps目录下(直接拖拽就可以) (注意:由于.apk文件易过期,所以,要下载最新版本,多试几个)

四、建立package包和案例文件

  1、在src文件夹上右键单击,【New】-->【package】,输入包名:com.glen.demo,点击【Finish】

 脚本代码:

package com.glen.demo;

import java.net.URL;

import org.openqa.selenium.By;

import org.openqa.selenium.WebElement;

import io.appium.java_client.android.AndroidDriver;

import org.openqa.selenium.remote.CapabilityType;

import org.openqa.selenium.remote.DesiredCapabilities;

public class ContactsTest {

public static void main(String[] args)throws Exception {

//参数初始化

DesiredCapabilities capabilities = new DesiredCapabilities();

capabilities.setCapability(CapabilityType.BROWSER_NAME,"");

capabilities.setCapability("platformName", "Android");

capabilities.setCapability("deviceName", "emulator-5554");

capabilities.setCapability("platformVersion", "5.1.1");

capabilities.setCapability("app-package", "com.jingdong.app.mall");

capabilities.setCapability("app-activity","com.jingdong.app.mall.main.MainActivity");

//启动Androiddriver

AndroidDriver driver = new AndroidDriver<WebElement>(new URL("http://127.0.0.1:4723/wd/hub"),capabilities);

Thread.sleep(6000);//有的app打开慢,加大等待时间

//点击首页输入框

driver.findElement(By.id("com.jingdong.app.mall:id/a3z")).click();

//输入搜索内容

WebElement search = driver.findElement(By.className("android.widget.EditText"));

search.sendKeys("华为手机预售最高1元抵200元");

driver.findElement(By.className("android.widget.TextView")).click();

//Thread.sleep(6000);

//driver.quit();

}

}

(查看Android应用包名、Activity的方法:

cmd命令行

1、adb logcat  –c

2、adb logcat ActivityManager:I *:s)

五、启动Android模拟器(也可以连接真机)

1、启动模拟器后,cmd输入:adb devices,确定设备是否连接上,

六、 运行测试案例:

  1、在eclipse中,项目右键>【Run As】>【Java Application】 

5.项目及课程总结

通过这个Android备忘录程序,可以更加熟练sqlite这种数据存储方式的使用。

移动终端应用开发基础---便签App相关推荐

  1. 力荐一款好用的便签APP:让你2022效率飞起来

    2022年开工之后,不少人又立下了flag,想要大干一场.想在原有的基础上更进一步,提高工作效率必不可少,因为每个人一天都是24小时.不同的效率,在24小时之内产出差异也很大.关于提高工作效率的软件有 ...

  2. 安卓定时启动软件app_便签app排行榜前十名安卓手机哪个高颜值便签软件好用?...

    手机上用的便签app,在手机便签app排行榜前十名的便签软件哪个好用?安卓手机上用的便签app哪个好用? 对于这些问题,考虑的角度与衡量的标准不同,所得出的答案想必也会不同,对于小编这个即将踏入职场的 ...

  3. web系统 手机app 能访问吗?_苹果手机能下载什么好用的桌面便签?有什么好的便签app推荐吗...

    经常使用苹果手机的人,应该都知道:和安卓手机不同,苹果iPhone手机使用的是苹果公司自己的iOS系统:而且,在苹果手机上添加软件,需要去App Store里下载安装.当然了,苹果App Store里 ...

  4. android记事本添加图片功能,安卓手机上有什么便签app既可以写日记又可以添加照片?...

    原标题:安卓手机上有什么便签app既可以写日记又可以添加照片? 当前,有很多人一直保持着写日记的习惯,因为这样可以及时记录自己的成长轨迹,使得自己可以追寻到时光的记忆,但是我们记录日记的工具,却随着时 ...

  5. pc控制iphone的软件_哪个备忘录便签app可以和PC电脑一块儿用

    原标题:哪个备忘录便签app可以和PC电脑一块儿用 移动互联网的今天,大家和手机的关系是越来越亲密.这不,很多人一天几乎手机不离身的.这当然和手机的功能越来越完善有很大关系.以前,手机只是一个简单的通 ...

  6. 好用的便签APP排行榜前十名?

    我是一名时间管理与自律达人,而便签应用程序就是必备与理想的时间管理工具.经过自己长期的总结认为好用的电脑手机云便签APP应用程序应该具备以下功能. 1.多设备同步:可以方便地将电脑和手机之间的数据同步 ...

  7. 小米MIUI里的便签APP是如何实现插入图片功能的?

    小米手机因为其超高的性价比,非常受年轻人的欢迎.那么小米MIUI里的便签APP,功能非常多样化,如果有碎片信息需要记录,选择记录到便签APP上是非常不错的.有时候,我们有一些重要的图片,想存入便签AP ...

  8. 敬业签苹果ios手机便签APP里的录音怎么转文字?

    一.打开敬业签苹果手机便签App并登录账号,进入便签主页面,可长按底部中间的"+"按钮选择"语音便签"添加语音记事并保存,点击录音便签打开查看内容详情页: 二. ...

  9. 安卓系统好用的手机便签APP

    你使用的手机是安卓系统吗?在国内,使用安卓系统手机的用户数量是非常庞大的,于是也就产生了各种各样的使用需求,例如当我们需要随时记录一些重要的事情和想法时,手机自带的便签或备忘录不能够满足我们的使用需求 ...

最新文章

  1. Codeforces Round #546 (Div. 2) B. Nastya Is Playing Computer Games
  2. oracle spm使用1
  3. 运用贪心思想解决跳跃游戏
  4. c语言最小点对问题_C语言教程(一):程序开发理论基础!
  5. golang并发的一篇文章
  6. RTT时钟管理篇——软硬定时器理解(一)
  7. 下面哪个对象能代表当前的HTML文件,华师网络学院作业答案-WEB程序设计选择题...
  8. Python文件操作小案例:交替合并两个记事本文件
  9. 计算机网络设计 pdf,计算机网络教学设计.pdf
  10. Pycharm远程调试报错:undefined symbol: AttachDebuggerTracing
  11. 系统无法执行指定的程序。_自制操作系统-函数代码副本跳转无法正确执行的问题...
  12. halcon-高速下载
  13. 编译原理完整学习笔记(三):词法分析
  14. pyinstaller编译出的exe被杀毒软件认为是木马
  15. USB转232和485的区别
  16. JVM - 类加载器
  17. win10任务栏透明+变窄+免安装
  18. 学习html+css+js笔记
  19. Windows进程管理
  20. 公众号二维码怎么生成

热门文章

  1. GY-33 颜色传感器模块
  2. 解决虚拟机中ubuntu无法识别U盘
  3. bim建模计算机配置,BIM对电脑配置的要求
  4. HTML Canvas 参考手册
  5. STK + C# + Cesium联合编程(一):技术路线验证
  6. 测试结果-HTML测试报告
  7. Windows+IIS+PHP——PHP安装与环境配置
  8. 1、Chrome之Elements功能面板
  9. js getElementById().innerHTML和getElementById().value区别
  10. 景德镇特色的部门级别与权限