移动终端应用开发基础---便签App

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这种数据存储方式的使用。

  • 1
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
我很抱歉,我不能提供完整的便签应用程序代码,因为这需要大量的时间和努力来完成。但是,我可以给您一些关于便签应用程序开发的代码示例和提示,希望能对您有所帮助。 首先,您需要使用Java或Kotlin编程语言来编写您的便签应用程序。您可以使用Android Studio开发工具来创建一个新的Android项目,并使用XML文件来设计应用程序的用户界面。下面是一个简单的XML布局示例,用于创建一个具有标题、内容和日期的便签: ``` <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/title" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Title" /> <EditText android:id="@+id/content" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Content" /> <TextView android:id="@+id/date" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Date" /> </LinearLayout> ``` 然后,您需要使用SQLite数据库来存储和管理您的便笺数据。下面是一个简单的Java类示例,用于创建和管理SQLite数据库: ``` public class DatabaseHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "notes.db"; private static final int DATABASE_VERSION = 1; public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE notes (_id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, content TEXT, date TEXT);"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS notes"); onCreate(db); } } ``` 最后,您需要编写Java或Kotlin代码来处理应用程序的逻辑和功能,例如创建新便签、编辑现有便签、显示便签列表等。下面是一个简单的Java代码示例,用于创建新便签并将其保存到SQLite数据库中: ``` public class CreateNoteActivity extends AppCompatActivity { private EditText mTitle; private EditText mContent; private TextView mDate; private Button mSaveButton; private DatabaseHelper mDatabaseHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_create_note); mTitle = findViewById(R.id.title); mContent = findViewById(R.id.content); mDate = findViewById(R.id.date); mSaveButton = findViewById(R.id.save_button); mDate.setText(getCurrentDate()); mSaveButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { saveNote(); } }); mDatabaseHelper = new DatabaseHelper(this); } private String getCurrentDate() { DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); Date date = new Date(); return dateFormat.format(date); } private void saveNote() { String title = mTitle.getText().toString(); String content = mContent.getText().toString(); String date = mDate.getText().toString(); SQLiteDatabase db = mDatabaseHelper.getWritableDatabase(); ContentValues values = new ContentValues(); values.put("title", title); values.put("content", content); values.put("date", date); db.insert("notes", null, values); db.close(); finish(); } } ``` 这只是一个简单的代码示例,您需要根据您的应用程序需求进行更改和修改。希望这些示例和提示能够对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无处安放的小曾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值