十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
本篇文章给大家分享的是有关Android中怎么开发一个记事本项目,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。
成都创新互联专注于叙永网站建设服务及定制,我们拥有丰富的企业做网站经验。 热诚为您提供叙永营销型网站建设,叙永网站制作、叙永网页设计、叙永网站官网定制、小程序开发服务,打造叙永网络公司原创品牌,更为您提供叙永网站排名全网营销落地服务。
DBHelper.java
package com.ikok.notepad.DBUtil; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class DBHelper extends SQLiteOpenHelper { /** * 创建笔记表 */ private static final String CREATE_NOTE = "create table Note(" + "id integer primary key autoincrement," + "content text," + "time text)"; private Context mContext; public DBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); mContext = context; } @Override public void onCreate(SQLiteDatabase sqLiteDatabase) { sqLiteDatabase.execSQL(CREATE_NOTE); // Toast.makeText(mContext,"Created",Toast.LENGTH_SHORT).show(); } @Override public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) { } }
创建完数据表后,自然需要操作数据库,CRUD数据,我把所有跟数据库有关的操作封装在一起:NoteDB.java
package com.ikok.notepad.DBUtil; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import com.ikok.notepad.Entity.Note; import java.util.ArrayList; import java.util.List; /** * Created by Anonymous on 2016/3/24. */ public class NoteDB { public static final String DB_NAME = "notepad"; public static final int VERSION = 1; private static NoteDB mNoteDB; private SQLiteDatabase db; public NoteDB(Context context) { DBHelper dbHelper = new DBHelper(context,DB_NAME,null,VERSION); db = dbHelper.getWritableDatabase(); } /** * 获取 NoteDB 的实例 * @param context * @return */ public synchronized static NoteDB getInstance(Context context){ if (mNoteDB == null){ mNoteDB = new NoteDB(context); } return mNoteDB; } public void saveNote(Note note){ if (note != null) { ContentValues values = new ContentValues(); values.put("content", note.getContent()); values.put("time", note.getTime()); db.insert("Note", null, values); } } public ListloadNotes(){ List noteList = new ArrayList (); /** * 先按时间降序排列,再按id降序排列 */ Cursor cursor = db.query("Note",null,null,null,null,null,"time desc,id desc"); if (cursor.moveToNext()){ do { Note note = new Note(); note.setId(cursor.getInt(cursor.getColumnIndex("id"))); note.setContent(cursor.getString(cursor.getColumnIndex("content"))); note.setTime(cursor.getString(cursor.getColumnIndex("time"))); noteList.add(note); } while (cursor.moveToNext()); } return noteList; } public Note loadById(int id){ Note note = null; Cursor cursor = db.query("Note",null,"id = " + id,null,null,null,null); if (cursor.moveToNext()){ note = new Note(); note.setContent(cursor.getString(cursor.getColumnIndex("content"))); note.setTime(cursor.getString(cursor.getColumnIndex("time"))); } return note; } public void deleteById(Integer id){ db.delete("Note","id = " + id,null); } public void deleteAllNote(){ db.delete("Note", null, null); } public void updateById(String noteTime, String noteContent, int noteId){ ContentValues values = new ContentValues(); values.put("content",noteContent); values.put("time",noteTime); db.update("Note",values,"id = " + noteId,null); } }
设计完数据库后,与数据库对应的需要一个实体类:Note.java
package com.ikok.notepad.Entity; import java.io.Serializable; /** * Created by Anonymous on 2016/3/24. */ public class Note implements Serializable { private int id; private String content; private String time; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getTime() { return time; } public void setTime(String time) { this.time = time; } }
接下来进行App主页的设计:main_activity.xml
具体效果如下(图标懒得去改颜色了):
左边的是一个关于App的按钮,右边的新建记事本的按钮。
因为主页需要显示已经记录的内容,所以我选择用ListView去显示。用到ListView,则与之对应的是要一个数据源,一个适配器。所以我为每一条子项设计了一个样式,去让它左边显示创建或更新的时间,右边显示内容。如下:list_item.xml
创建好了ListView,接下来为它准备适配器:MyAdapter.java
package com.ikok.notepad.Util; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.TextView; import com.ikok.notepad.Entity.Note; import com.ikok.notepad.R; import java.util.List; /** * Created by Anonymous on 2016/3/24. */ public class MyAdapter extends BaseAdapter { private ListnoteList; private LayoutInflater mInflater; private Context mContext; private int index; public MyAdapter(Context context,List noteList,ListView listView) { this.mInflater = LayoutInflater.from(context); this.noteList = noteList; this.mContext = context; } @Override public int getCount() { return noteList.size(); } @Override public Object getItem(int i) { return noteList.get(i); } @Override public long getItemId(int i) { return i; } @Override public View getView(int i, View convertView, ViewGroup viewGroup) { ViewHolder viewHolder = null; if (convertView == null){ viewHolder = new ViewHolder(); convertView = mInflater.inflate(R.layout.list_item, null); viewHolder.mTime = (TextView) convertView.findViewById(R.id.show_time); viewHolder.mContent = (TextView) convertView.findViewById(R.id.show_content); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.mTime.setText(noteList.get(i).getTime()); viewHolder.mContent.setText(noteList.get(i).getContent()); index = i; // convertView.setOnClickListener(new View.OnClickListener() { // @Override // public void onClick(View view) { // Intent intent = new Intent(mContext,UpdateOrReadActivity.class); //// Bundle bundle = new Bundle(); //// bundle.putSerializable("note_item",noteList.get(index)); //// intent.putExtras(bundle); // intent.putExtra("note_id",noteList.get(index).getId()); // Log.d("Anonymous","备忘录ID:"+noteList.get(index).getId()); // mContext.startActivity(intent); // Log.d("Anonymous","执行了适配器里的点击事件"); // } // }); return convertView; } class ViewHolder{ public TextView mTime; public TextView mContent; } }
这里采用了使用ViewHolder,来使ListView滚动的时候不必每次重新创建对象,提升性能。
创建好了ListView,准备好了适配器,接下来要为ListView准备数据源,而这数据源是要从数据库读出来的。但是数据库操作和网络访问等都是属于耗时操作,如果用主UI线程去执行响应操作的话,很可能会出现ANR现象,所以这里我用AsyncTask去执行数据库操作。主Activity代码如下:MainActivity.java
package com.ikok.notepad.Activity; import android.app.Activity; import android.content.DialogInterface; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.support.v7.app.AlertDialog; import android.view.View; import android.view.Window; import android.widget.AdapterView; import android.widget.ImageButton; import android.widget.ListView; import android.widget.TextView; import com.ikok.notepad.DBUtil.NoteDB; import com.ikok.notepad.Entity.Note; import com.ikok.notepad.R; import com.ikok.notepad.Util.DeleteAsyncTask; import com.ikok.notepad.Util.MyAdapter; import java.util.ArrayList; import java.util.List; /** * Created by Anonymous on 2016/3/24. */ public class MainActivity extends Activity { /** * 布局控件 */ private TextView mTitle; private TextView mNoteNum; private ImageButton mWrite; private ListView mNoteListView; private ImageButton mAbout; /** * 数据库实例,数据源 */ private ListmNoteList = new ArrayList () ; private NoteDB mNoteDB; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.main_activity); initView(); new NewAsyncTask().execute(); initEvent(); } private void initEvent() { /** * 新写一条备忘录 */ mWrite.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(MainActivity.this, AddNoteActivity.class); startActivity(intent); } }); /** * 修改或查看一条已有的备忘录 */ mNoteListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView> adapterView, View view, int i, long l) { Note note = (Note) adapterView.getItemAtPosition(i); // Log.d("Anonymous", "点击ListView获取的note id: " + note.getId()); Intent intent = new Intent(MainActivity.this, UpdateOrReadActivity.class); intent.putExtra("note_id", note.getId()); startActivity(intent); } }); /** * listview长按删除 */ mNoteListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView> parent, View view, int position, long id) { final Note note = (Note) parent.getItemAtPosition(position); // Log.d("Anonymous", "长按ListView获取的note id: " + note.getId()); /** * 长按提示是否删除 */ new AlertDialog.Builder(MainActivity.this) .setTitle("提示") .setMessage("真的要删除这条记录吗?") .setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { new DeleteAsyncTask(mNoteDB).execute(note.getId()); new NewAsyncTask().execute(); } }) .setNegativeButton("取消", null) .show(); return true; } }); /** * 关于自己 */ mAbout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this,AboutActivity.class); startActivity(intent); } }); } public void initView() { /** * 布局控件初始化 */ mTitle = (TextView) findViewById(R.id.app_title); // 画TextView文字下的下划线 // mTitle.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG); mNoteNum = (TextView) findViewById(R.id.note_num); mWrite = (ImageButton) findViewById(R.id.write_btn); mNoteListView = (ListView) findViewById(R.id.listview); mAbout = (ImageButton) findViewById(R.id.about_btn); /** * 获取数据库实例 */ mNoteDB = NoteDB.getInstance(this); } /** * 异步加载备忘录 */ class NewAsyncTask extends AsyncTask >{ @Override protected List doInBackground(Void... voids) { mNoteList = mNoteDB.loadNotes(); return mNoteList; } @Override protected void onPostExecute(List notes) { super.onPostExecute(notes); /** * 设置适配器,绑定适配器 */ MyAdapter myAdapter = new MyAdapter(MainActivity.this,notes,mNoteListView); mNoteListView.setAdapter(myAdapter); /** * 更新备忘录记录数 */ int temp = mNoteList.size(); mNoteNum.setText("共 " + temp + " 条备忘录"); } } /** * 当活动恢复时,刷新listview和备忘录记录数 */ @Override protected void onResume() { super.onResume(); new NewAsyncTask().execute(); } }
在上面的代码中,我新建了一个 NewAsyncTask 类去继承 AsyncTask,去执行从数据库读取数据的操作,在onPostExecute()方法中,去更新UI,比如显示ListView中的数据,一下页面底部中间有几条数据等。还有我考虑了新建记事本的话,是另外一个Activity。当从另外的Activity返回到主Activity时,主页面应该再刷新一次,刷新数据和显示,所以我在onResume()方法中调用了 NewAsyncTask().execute() 方法,当活动恢复时刷新显示。
接下来是新建记事本的Activity,布局如下:write_note.xml
具体效果如下:
新建记事本的Activity如下:AddNoteActivity.java
package com.ikok.notepad.Activity; import android.app.Activity; import android.content.DialogInterface; import android.os.AsyncTask; import android.os.Bundle; import android.support.v7.app.AlertDialog; import android.view.View; import android.view.Window; import android.widget.EditText; import android.widget.ImageButton; import android.widget.TextView; import android.widget.Toast; import com.ikok.notepad.DBUtil.NoteDB; import com.ikok.notepad.Entity.Note; import com.ikok.notepad.R; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by Anonymous on 2016/3/24. */ public class AddNoteActivity extends Activity { /** * 布局控件 */ private TextView mComplete; private ImageButton mBackBtn; private EditText mContent; /** * 备忘录数据 */ private String noteTime; private String noteContent; /** * 数据库 */ private NoteDB mNoteDB; private Note note; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.write_note); initView(); initEvent(); } private void initView() { /** * 布局控件初始化 */ mComplete = (TextView) findViewById(R.id.complete_btn); mBackBtn = (ImageButton) findViewById(R.id.back_btn); mContent = (EditText) findViewById(R.id.note_content); /** * 获取数据库实例 */ mNoteDB = NoteDB.getInstance(this); } /** * 事件处理 */ private void initEvent() { /** * 返回上一级菜单,如果有内容,提示是否保存 * 是、保存,销毁活动;否,直接销毁活动 */ mBackBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { saveDataOrNot(); } }); /** * 完成按钮,保存备忘录到数据库 */ mComplete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (!mContent.getText().toString().equals("")){ new AddAsyncTask().execute(); finish(); } else { finish(); } } }); } /** * 根据是否有内容,提示保存 */ private void saveDataOrNot() { if (!mContent.getText().toString().trim().equals("")) { new AlertDialog.Builder(AddNoteActivity.this) .setTitle("提示") .setMessage("需要保存您编辑的内容吗?") .setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { new AddAsyncTask().execute(); finish(); } }) .setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }) .show(); } else { finish(); } } /** * 添加数据到数据库 */ class AddAsyncTask extends AsyncTask{ @Override protected Void doInBackground(Void... voids) { mNoteDB.saveNote(note); return null; } @Override protected void onPreExecute() { super.onPreExecute(); /** * 记录数据 */ SimpleDateFormat sdf = new SimpleDateFormat("MM-dd HH:mm"); Date date = new Date(System.currentTimeMillis()); noteTime = sdf.format(date); noteContent = mContent.getText().toString(); note = new Note(); note.setTime(noteTime); note.setContent(noteContent); } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); Toast.makeText(AddNoteActivity.this, "保存成功!", Toast.LENGTH_SHORT).show(); } } /** * 按返回键,有内容时,提示保存 */ @Override public void onBackPressed() { saveDataOrNot(); } }
新建记事本,插入数据到数据库,如从数据库读取数据一样,都是耗时操作,所以我还是用了AsyncTask,在 onPreExecute()方法中,先获取到系统当前时间,进行格式化,存储下来,把输入的文本存储下来,然后再 doInBackground()去保存数据。这里我考虑了,用户输入了内容,但是没有保存,在顶部的返回键或者系统的返回键的处理事件中都加了判断。如果文本为空,空格也算空,则不保存,直接退出当前Activity,如果有内容,则弹出对话框提示用户是否保存,是则保存,否则不保存,退出当前活动。
接下来是查看或修改一条记事本了,布局我是直接复用新建记事本的布局。因为没有区别 - -
接下来是查看或修改一条记事本的Activity了,之前,我想的是点击一条记事本,则进入这条记事本,把这条记事本直接显示在页面上,用户直接在内容最后进行编辑。所以这里需要一个子项点击事件。我在MainActivity里已经写了,先获取当前点击的这一项的对象,这里我费了好多时间,我不知道点击这一项的时候,怎么把该项的对象读取出来。最后自己查看源码,查API,看到参数中AdapterView是个泛型,我试着从它着手,把它强转成Note对象,然后试试获取id,没想到就成了。 - -
所以,我获取了当前点击的item中的Note对象的id,把它放在Intent中,带着这个参数去开启活动。
这里,查看或修改一条记事本的Activity正式开始了,如下:UpdateOrReadActivity.java
package com.ikok.notepad.Activity; import android.app.Activity; import android.content.DialogInterface; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.support.v7.app.AlertDialog; import android.util.Log; import android.view.View; import android.view.Window; import android.widget.EditText; import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.TextView; import com.ikok.notepad.DBUtil.NoteDB; import com.ikok.notepad.Entity.Note; import com.ikok.notepad.R; import com.ikok.notepad.Util.DeleteAsyncTask; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by Anonymous on 2016/3/24. */ public class UpdateOrReadActivity extends Activity { /** * 布局控件 */ private TextView mComplete; private ImageButton mBackBtn; private EditText mContent; private LinearLayout mScreen; /** * 备忘录数据 */ private int noteId; private String noteTime; private String noteContent; private String originData; /** * 数据库 */ private NoteDB mNoteDB; private static Note note; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.write_note); /** * 获取传递过来的note对象 */ Intent intent = getIntent(); // 传递Note对象,必须要Note实体实现Serializable // note = (Note) intent.getSerializableExtra("note_item"); noteId = intent.getIntExtra("note_id",0); Log.d("Anonymous", "传递后的备忘录ID:" + noteId); initView(); /** * 加载显示数据 */ new LoadAsyncTask().execute(); initEvent(); } private void initView() { /** * 布局控件初始化 */ mComplete = (TextView) findViewById(R.id.complete_btn); mBackBtn = (ImageButton) findViewById(R.id.back_btn); mContent = (EditText) findViewById(R.id.note_content); mScreen = (LinearLayout) findViewById(R.id.screen_view); /** * 获取数据库实例 */ mNoteDB = NoteDB.getInstance(this); } private void initEvent() { /** * 返回上一级菜单,直接销毁当前活动 */ mBackBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { updateDataOrNot(); } }); /** * 完成按钮,修改备忘录到数据库 */ mComplete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (mContent.getText().toString().trim().equals("")){ // Log.d("Anonymous","进入判断为空函数"); new DeleteAsyncTask(mNoteDB).execute(noteId); finish(); } else if (mContent.getText().toString().equals(originData)) { finish(); } else { // Log.d("Anonymous","进入判断不为空函数"); new UpdateAsyncTask().execute(); // Toast.makeText(UpdateOrReadActivity.this, "修改成功!", Toast.LENGTH_SHORT).show(); finish(); } } }); /** * 点击屏幕空白区域,EditText选中 */ } /** * 根据id从数据库读数据的异步任务 */ class LoadAsyncTask extends AsyncTask{ @Override protected Note doInBackground(Void... voids) { note = mNoteDB.loadById(noteId); return note; } @Override protected void onPostExecute(Note note) { super.onPostExecute(note); /** * 根据传递进来的Note显示备忘录内容,并把光标移动到最后 * 记录最初的文本内容 */ originData = note.getContent(); mContent.setText(note.getContent()); mContent.setSelection(mContent.getText().toString().length()); } } /** * 更新数据库的异步任务 */ class UpdateAsyncTask extends AsyncTask { @Override protected void onPreExecute() { super.onPreExecute(); /** * 记录数据 */ SimpleDateFormat sdf = new SimpleDateFormat("MM-dd HH:mm"); Date date = new Date(System.currentTimeMillis()); noteTime = sdf.format(date); noteContent = mContent.getText().toString(); note.setTime(noteTime); note.setContent(noteContent); } @Override protected Void doInBackground(Void... voids) { mNoteDB.updateById(noteTime, noteContent, noteId); return null; } } /** * 根据是否有内容,提示保存 */ private void updateDataOrNot() { if (!mContent.getText().toString().equals(originData)) { new AlertDialog.Builder(UpdateOrReadActivity.this) .setTitle("提示") .setMessage("需要保存您编辑的内容吗?") .setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { new UpdateAsyncTask().execute(); finish(); } }) .setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }) .show(); } else { finish(); } } /** * 返回键事件 * 根据内容是否有变化,提示是否保存 */ @Override public void onBackPressed() { updateDataOrNot(); } }
操作数据库还是用了AsyncTask。这里,我考虑了,是否有改动,用一个变量,去存放原始的数据,在用户点击顶部返回或者系统返回键的时候去判断是否有改动,如果有,则提示用户是否需要保存更改。如果修改内容,没有字了,则自动删除该条记事本。因为删除记事本的操作,在主页还需要用到,所以我把它提出来,单独作为一个类,不再是内部类了。如下:
package com.ikok.notepad.Util; import android.os.AsyncTask; import com.ikok.notepad.DBUtil.NoteDB; /** * Created by Anonymous on 2016/3/25. */ public class DeleteAsyncTask extends AsyncTask{ private NoteDB noteDB; public DeleteAsyncTask(NoteDB noteDB) { this.noteDB = noteDB; } @Override protected Void doInBackground(Integer... params) { noteDB.deleteById(params[0]); return null; } }
接下来是CRUD的最后一项,删除数据了,在主页的时候,我设计的是单击进入该条记事本,去查看或修改这一条记事本,然后我考虑的是长按删除。长按,弹出对话框,提示是否删除,是则删除,否则不做任何事。所以在MainActivity中可以看到长按事件的监听器。但是因为Android的事件分发机制,长按事件必定会触发点击事件。所以需要在ListView中设置这样一个属性,才能点击事件和长按事件同时监听。
android:descendantFocusability="blocksDescendants"
主要功能都差不多完成了。接下来就是优化App了。我设计了过渡动画,引导页,以及是否第一次启动App。是则过渡动画过渡完到引导页,引导页完才到主页。否则过渡动画过渡完则直接进入主页。还设计了引导页的切换动画,使用了nineoldandroid,保证动画在低版本手机上可显示。
以上就是Android中怎么开发一个记事本项目,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注创新互联行业资讯频道。