1、框架图
2、SQLite数据库
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#fefefe" tools:context=".MainActivity"> <TextView android:id="@+id/note_name" android:layout_width="match_parent" android:layout_height="45dp" android:textSize="20sp" android:textColor="@android:color/white" android:gravity="center" android:textStyle="bold" android:background="#fb7a6a" android:text="记事本"/> <ListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/note_name" android:cacheColorHint="#00000000" android:divider="#E4E4E4" android:dividerHeight="1dp" android:fadingEdge="none" android:listSelector="#00000000" android:scrollbars="none"></ListView> <ImageView android:id="@+id/add" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/add" android:layout_marginBottom="30dp" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true"/> </RelativeLayout>
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingLeft="12dp"> <TextView android:id="@+id/things" android:layout_width="match_parent" android:layout_height="wrap_content" android:maxLines="2" android:ellipsize="end" android:lineSpacingExtra="3dp" android:paddingTop="10dp" android:textColor="@android:color/black" /> <TextView android:id="@+id/time" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="#fb7a6a" android:paddingTop="5dp" android:paddingBottom="7dp"/> </LinearLayout>
android:theme="@style/Theme.AppCompat.NoActionBar">
package com.example.mynote; public class Bean { private String id; //记录的 id private String bthings; //记录的内容 private String btime; //保存记录的时间 public String getId() { return id; } public void setId(String id) { this.id = id; } public String getNotepadContent() { return bthings; } public void setNotepadContent(String notepadContent) { this.bthings = notepadContent; } public String getNotepadTime() { return btime; } public void setNotepadTime(String notepadTime) { this.btime = notepadTime; } }
//创建 NoteAdapter 类,继承自 BaseAdapter 类。 public class NoteAdapter extends BaseAdapter { private List <Bean> list; //数据准备 private Context mycontext; private LayoutInflater myinflate; //加载布局视图 //构造函数 public NoteAdapter(Context context,List <Bean> list) { this.list=list; this.mycontext=context; this.myinflate=LayoutInflater.from(context); } //实现4个方法 @Override public int getCount() { //返回列表长度 return list.size(); } @Override public Object getItem(int position) { //返回控件 return list.get(position); } @Override public long getItemId(int i) { //返回下标 return i; } @Override //参数convertview用于复用列表项布局View,vgroup用于加载列表项xml布局 public View getView(int i, View convertview, ViewGroup vgroup) { ViewHolder myholder; //如果没有空闲的列表项就新创建一个 if(convertview==null) { convertview=myinflate.inflate(R.layout.item,null); myholder=new ViewHolder(convertview); convertview.setTag(myholder); } else { myholder=(ViewHolder) convertview.getTag(); } final Bean info=(Bean) getItem(i); myholder.textView_things.setText(info.getNotepadContent()); myholder.textView_time.setText(info.getNotepadTime()); return convertview; } }
class ViewHolder { TextView textView_things; TextView textView_time; View wholeView; public ViewHolder(View view) { textView_things=(TextView) view.findViewById(R.id.things); textView_time=(TextView) view.findViewById(R.id.time); wholeView = view; } }
完整的NoteAdapter.java文件:
package com.example.mynote; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import androidx.recyclerview.widget.RecyclerView; import java.util.ArrayList; import java.util.List; //创建 NoteAdapter 类,继承自 BaseAdapter 类。 public class NoteAdapter extends BaseAdapter { private List <Bean> list; //数据准备 private Context mycontext; private LayoutInflater myinflate; //加载布局视图 //构造函数 public NoteAdapter(Context context,List <Bean> list) { this.list=list; this.mycontext=context; this.myinflate=LayoutInflater.from(context); } //实现4个方法 @Override public int getCount() { //返回列表长度 return list.size(); } //根据位置,再去list里面找数据 @Override public Object getItem(int position) { //返回控件 return list.get(position); } //返回位置 @Override public long getItemId(int i) { //返回下标 return i; } //创一个格子,获取两个控件,填数据 @Override //参数convertview用于复用列表项布局View,vgroup用于加载列表项xml布局 public View getView(int i, View convertview, ViewGroup vgroup) { ViewHolder myholder; //如果没有空闲的列表项(格子)就新创建一个 if(convertview==null) { convertview=myinflate.inflate(R.layout.item,null); myholder=new ViewHolder(convertview); convertview.setTag(myholder); } else { //有列表项(格子)就从里面拿 myholder=(ViewHolder) convertview.getTag(); } //把getItem(i)第i个位置的内容拿出来 final Bean info=(Bean) getItem(i); myholder.textView_things.setText(info.getNotepadContent()); myholder.textView_time.setText(info.getNotepadTime()); return convertview; } class ViewHolder { TextView textView_things; TextView textView_time; View wholeView; public ViewHolder(View view) { textView_things=(TextView) view.findViewById(R.id.things); textView_time=(TextView) view.findViewById(R.id.time); wholeView = view; } } }
public class DBSQLiteHelper extends SQLiteOpenHelper { public static final String DATABASE_NAME = "Notepad";//数据库名 public static final int DATABASE_VERION = 1; //数据库版本 public static final String DATABASE_NOTEPADTB = "Note"; //记事本数据表名 public static final String NOTEPAD_ID = "id"; //id字段名 public static final String NOTEPAD_CONTENT = "content"; //内容字段名 public static final String NOTEPAD_NOTETIME = "notetime"; //时间字段名 //建表语句 public static final String CREATE_NOTE = "create table Note (" + "id integer primary key autoincrement, " + "content text, " + "notetime text)"; //或以下建表语句 // public static final String CREATE_NOTE = "create table Note (" // + NOTEPAD_ID+" integer primary key autoincrement, " // + NOTEPAD_CONTENT+" text, " // + NOTEPAD_NOTETIME+" text)"; //构造函数 public DBSQLiteHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); Log.e("SQLiteHelper","construct func2"); } public DBSQLiteHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERION); Log.e("SQLiteHelper","construct func"); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_NOTE); Log.e("SQLiteHelper","onCreate func"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { String CREATE_USER = "create table User("+ "id integer primary key autoincrement,"+ "username text,"+ "password text)"; db.execSQL(CREATE_USER); Log.e("SQLiteHelper","onUpgrade func"); } }
package com.example.mynote; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.util.Log; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; public class DAO { private static final String DATABASE_NOTEPADTB = "Note"; public static final String NOTEPAD_ID = "id"; //id字段名 public static final String NOTEPAD_CONTENT = "content"; //内容字段名 public static final String NOTEPAD_NOTETIME = "notetime"; //时间字段名 private DBSQLiteHelper dbOpenHelper; public DAO(Context context) { //创建DBSQLiteHelper对象 dbOpenHelper = new DBSQLiteHelper(context); //dbOpenHelper.getWritableDatabase(); //创建数据库,可调用,否则在第一次查询时调用 } //添加数据 public boolean insertData(String userContent,String userTime) { //获取数据库对象 SQLiteDatabase sqLiteDatabase = dbOpenHelper.getReadableDatabase(); ContentValues contentValues = new ContentValues(); contentValues.put(NOTEPAD_CONTENT,userContent); contentValues.put(NOTEPAD_NOTETIME,userTime); return sqLiteDatabase.insert(DATABASE_NOTEPADTB,null,contentValues)>0; } //删除数据 public boolean deleteData(String id) { SQLiteDatabase sqLiteDatabase=dbOpenHelper.getReadableDatabase(); String whereClause = NOTEPAD_ID + "=?"; String[] whereArgs = new String[]{String.valueOf(id)}; return sqLiteDatabase.delete(DATABASE_NOTEPADTB,whereClause,whereArgs)>0; } //修改数据 public boolean updateData(String id,String content,String time) { SQLiteDatabase sqLiteDatabase=dbOpenHelper.getReadableDatabase(); ContentValues contentValues = new ContentValues(); contentValues.put(NOTEPAD_CONTENT,content); contentValues.put(NOTEPAD_NOTETIME,time); String whereClause = NOTEPAD_ID + "=?"; String[] whereArgs = new String[]{String.valueOf(id)}; return sqLiteDatabase.update(DATABASE_NOTEPADTB,contentValues,whereClause,whereArgs)>0; } //查询数据 public List<Bean> query() { SQLiteDatabase sqLiteDatabase=dbOpenHelper.getReadableDatabase(); List<Bean> list = new ArrayList<Bean>(); Cursor cursor = sqLiteDatabase.query(DATABASE_NOTEPADTB,null,null,null, null,null,NOTEPAD_ID+" desc");//按id降序排序 if (cursor.moveToFirst()) { do{ Bean noteInfo=new Bean(); String id = String.valueOf(cursor.getInt(cursor.getColumnIndex(NOTEPAD_ID))); String content = cursor.getString(cursor.getColumnIndex(NOTEPAD_CONTENT)); String time = cursor.getString(cursor.getColumnIndex(NOTEPAD_NOTETIME)); noteInfo.setId(id); noteInfo.setNotepadContent(content); noteInfo.setNotepadTime(time); list.add(noteInfo); }while(cursor.moveToNext()); cursor.close(); } return list; } //获取当前日期,格式化为yyyy年MM月dd日 HH:mm:ss形式的字符串 public static final String getTime() { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); Date date = new Date(System.currentTimeMillis()); return simpleDateFormat.format(date); } public void initData() { insertData("天气变冷了,记得穿棉衣哦",getTime()); insertData("今天要带小憨猪去外面玩",getTime()); } }
(1)Record.java文件
package com.example.mynote; import androidx.appcompat.app.AppCompatActivity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.EditText; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; public class Record extends AppCompatActivity implements View.OnClickListener { private ImageView note_back; //返回首页 private TextView noteName; //根据情况显示“添加便签”or“修改便签” private TextView note_time; //便签修改时间 private EditText content; //便签正文 private ImageView delete; //清除 private ImageView note_save; // 保存 private String id; @Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.record); setContentView(R.layout.record); note_back = (ImageView) findViewById(R.id.note_back); note_time = (TextView)findViewById(R.id.tv_time); content = (EditText) findViewById(R.id.note_content); delete = (ImageView) findViewById(R.id.delete); note_save = (ImageView) findViewById(R.id.note_save); noteName = (TextView) findViewById(R.id.note_name); initData();//根据来源决定顶部显示"添加便签"还是"修改便签" note_back.setOnClickListener(this); //返回首页 delete.setOnClickListener(this); //清除便签 note_save.setOnClickListener(this); //保存 } //根据来源决定顶部显示"添加便签"还是"修改便签" //如果是长按打开显示"修改便签",否则显示"添加便签" protected void initData() { noteName.setText("添加便签"); Intent intent = getIntent(); if(intent!= null) { id = intent.getStringExtra("id"); if (id != null) { //"修改便签",显示原便签内容 noteName.setText("修改便签"); content.setText(intent.getStringExtra("content")); note_time.setText(intent.getStringExtra("time")); //修改显示时间可见,新增不可见 note_time.setVisibility(View.VISIBLE); } } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.note_back: //返回键功能,关闭当前页面 finish(); break; case R.id.delete: //“清除按钮”功能:清除编辑框显示 content.setText(""); break; case R.id.note_save: String noteContent=content.getText().toString().trim(); if (id != null){//修改操作 if (noteContent.length()>0){ DAO notepadDAO = new DAO(this); if (notepadDAO.updateData(id, noteContent, notepadDAO.getTime())){ showToast("修改成功"); setResult(1); finish(); }else { showToast("修改失败"); } }else { showToast("修改内容不能为空!"); } }else { //向数据库中添加数据 if (noteContent.length()>0){ DAO notepadDAO = new DAO(this); if (notepadDAO.insertData(noteContent, notepadDAO.getTime())){ showToast("保存成功"); setResult(1); finish(); }else { showToast("保存失败"); } }else { showToast("内容不能为空!"); } } break; } } public void showToast(String message){ Toast.makeText(Record.this,message,Toast.LENGTH_SHORT).show(); } }
(2)record.xml文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#fefefe" android:orientation="vertical" tools:context=".Record"> <RelativeLayout android:layout_width="match_parent" android:layout_height="45dp" android:background="#fb7a6a"> <ImageView android:id="@+id/note_back" android:layout_width="45dp" android:layout_height="wrap_content" android:layout_centerVertical="true" android:paddingLeft="11dp" android:src="@drawable/back" /> <TextView android:id="@+id/note_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="记事本" android:textColor="@android:color/white" android:textSize="15sp" android:textStyle="bold" /> </RelativeLayout> <TextView android:id="@+id/tv_time" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="15sp" android:paddingTop="10dp" android:paddingBottom="10dp" android:gravity="center" android:visibility="gone" android:textColor="#fb7a6a"/> <EditText android:id="@+id/note_content" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:gravity="top" android:hint="请输入要添加的内容" android:paddingLeft="5dp" android:textColor="@android:color/black" android:background="#fefefe" /> <View android:layout_width="match_parent" android:layout_height="2dp" android:background="#fb7a6a"/> <LinearLayout android:layout_width="match_parent" android:layout_height="55dp" android:orientation="horizontal"> <ImageView android:id="@+id/delete" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:src="@drawable/delete" android:paddingBottom="15dp" android:paddingTop="9dp"/> <ImageView android:id="@+id/note_save" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:src="@drawable/save_note" android:paddingBottom="15dp" android:paddingTop="9dp"/> </LinearLayout> </LinearLayout>
package com.example.mynote; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.ImageView; import android.widget.ListView; import android.widget.Toast; import java.util.List; public class MainActivity extends AppCompatActivity{ private ListView listView; private List<Bean> notelist; private DAO notepadDAO; NoteAdapter adapter; //在onCreate ()方法中为 ListView 控件设置适配器,适配器的数据源来自数据库表的查询结果 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //用于显示便签的列表 listView = (ListView) findViewById(R.id.listview); notepadDAO = new DAO(this); //创建 NotepadDAO 对象 notepadDAO.initData(); //下面的if判断可删,就像int n=0,n=3可直接写成int n=3 if (notelist!=null) { notelist.clear(); } //从数据库中查询数据(保存的所有便签) notelist = notepadDAO.query();//第一次调用,创建数据库 adapter = new NoteAdapter(this, notelist); //adapter把数据放进去 listView.setAdapter(adapter); // 为“添加按钮”设置监听器,添加一条备忘录 ImageView add = (ImageView) findViewById(R.id.add); add.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this,Record.class); // 给需要传回数据的页面取id startActivityForResult(intent, 1); } }); //单击:打开“修改便签”页面 /*为“添加按钮”通过 setOnClickListener()方法设置监听器,当点击该按钮时,跳转到添加便签的界面。当 添加或修改记录后,记事本首页的列表需要更新显示,因此需要调用 startActivityForResult()根据返回结果决 定是否需要更新列表显示。*/ listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent,View view,int position,long id){ Bean notepadBean = notelist.get(position); Intent intent = new Intent(MainActivity.this, Record.class); intent.putExtra("id", notepadBean.getId()); intent.putExtra("time", notepadBean.getNotepadTime()); //便签的时间 intent.putExtra("content", notepadBean.getNotepadContent()); //便签的内容 MainActivity.this.startActivityForResult(intent, 1);//修改备忘录 } }); //长按:打开对话框 listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) { DialogInterface.OnClickListener listener=new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int pi) { Bean notepadBean = notelist.get(position); //根据id删除 notepadDAO.deleteData(notepadBean.getId()); notelist.remove(position); //刷新 adapter.notifyDataSetChanged(); Toast.makeText(MainActivity.this,"删除成功",Toast.LENGTH_SHORT).show(); } }; AlertDialog.Builder builder = new AlertDialog.Builder( MainActivity.this); builder.setTitle("是否删除此备忘录?"); builder.setPositiveButton("确定", listener); builder.setNegativeButton("取消", null); builder.show(); return true; } }); } /*当添加或修改返回后:需要刷新首页的 ListView 的显示。可以根据 resultCode 重新设置列表的 Adapter, 刷新显示。*/ @Override protected void onActivityResult(int requestCode,int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); //都为1表示执行跳转活动且保存数据成功 if (requestCode==1 && resultCode==1) { //添加或者更改了备忘录,需要更新显示 //showQueryData(); if (notelist!=null) { //清除列表 notelist.clear(); } //重新查询 notelist = notepadDAO.query(); adapter = new NoteAdapter(this, notelist); //adapter把数据放进去才会更新,所以上面的if (notelist!=null)……可以不要,重新更新会覆盖以前的 listView.setAdapter(adapter); } } /*初始化显示:可以往数据库(表)中填入一些测试数据,这样在第一次打开 APP 时就可以看到备忘录列 表,初始化显示。方法是:在 NotepadDAO 可以提供 insertData()方法往记事本数据表 Note 中插入若干条 备忘录记录,然后在 MainActivity 中初始化 NotepadDAO 后调用该方法。*/ private void initData(){ notepadDAO.insertData("1今天是五一劳动节",notepadDAO.getTime()); notepadDAO.insertData("2今天心情很美丽",notepadDAO.getTime()); notepadDAO.insertData("3今天要带小乌龟去学校",notepadDAO.getTime()); Log.e("SQLiteHelper","initData func"); } }
便签记录存放的数据库及表是何时创建的?
DAO层调用helper类
notelist = notepadDAO.query();//第一次调用,创建数据库
public DAO(Context context) { //创建DBSQLiteHelper对象 dbOpenHelper = new DBSQLiteHelper(context); //dbOpenHelper.getWritableDatabase(); //创建数据库,可调用,否则在第一次查询时调用 }
//建表语句 public static final String CREATE_NOTE = "create table Note (" + "id integer primary key autoincrement, " + "content text, " + "notetime text)";
public DBSQLiteHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_NOTE); }
打开APP时首页面是如何显示所有的便签的?
//从数据库中查询数据(保存的所有便签) notelist = notepadDAO.query();//第一次调用,创建数据库 adapter = new NoteAdapter(this, notelist); //adapter把数据放进去 listView.setAdapter(adapter);
“添加”和“修改”打开活动时有什么不同,是如何处理的?
//根据来源决定顶部显示"添加便签"还是"修改便签" //如果是长按打开显示"修改便签",否则显示"添加便签" protected void initData() { noteName.setText("添加便签"); Intent intent = getIntent(); //看intent是否传回数据 if(intent!= null) { id = intent.getStringExtra("id"); if (id != null) { //"修改便签",显示原便签内容 noteName.setText("修改便签"); content.setText(intent.getStringExtra("content")); note_time.setText(intent.getStringExtra("time")); //修改显示时间可见,新增不可见 note_time.setVisibility(View.VISIBLE); } } }
如何实现添加便签和修改便签后刷新主页面的显示?
/*当添加或修改返回后:需要刷新首页的 ListView 的显示。可以根据 resultCode 重新设置列表的 Adapter, 刷新显示。*/ @Override protected void onActivityResult(int requestCode,int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); //都为1表示执行跳转活动且保存数据成功 if (requestCode==1 && resultCode==1) { //添加或者更改了备忘录,需要更新显示 //showQueryData(); if (notelist!=null) { //清除列表 notelist.clear(); } //重新查询 notelist = notepadDAO.query(); adapter = new NoteAdapter(this, notelist); //adapter把数据放进去才会更新,所以上面的if (notelist!=null)……可以不要,重新更新会覆盖以前的 listView.setAdapter(adapter); } }