从无到有,一步一步实现记事本APP(一)
俺的碎碎念:写了个简单的记事本APP 复习了下SQLite的使用以及各种边角知识,希望能对各位带来一定的启发。
功能简介:本项目实现了记事本的基本功能,支持创建笔记,编辑笔记,长按删除笔记等功能;后续新增功能也会同步更新到博客和公众号。
主要功能演示:
创建新笔记:
编辑笔记:
删除笔记:
本项目的笔记APP核心的存储逻辑是基于SQLite数据库开发的,说白了就是增删改查的简单封装和使用。
思路也比较简单,RecycleView负责展示对应的笔记列表,而实际的存储是依靠SQLite。
废话不多说来看下关键代码。
SQLite数据库代码讲解
DBUtils工具类代码如下:
//工具类的存在主要是为了创建Helper文件时 引用的数据库参数更加便捷,使逻辑更清楚。
public class DBUtils {public static final String SQL_NAME = "Notepad.db";//数据库名public static final String SQL_TABLE = "notemane";//表名public static final int DATABASE_VERSION = 1;//数据库版本//数据库表中的列名public static final String NOTEPAD_ID = "id";public static final String NOTEPAD_CONTENT = "content";//item内容public static final String NOTEPAD_TIME = "time";//item的修改时间public static final String NOTEPAD_TITLE = "title";//标题//获取时间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);}}
Android 提供了抽象类SQLiteOpenHelper来帮助我们使用SQLite数据库,如果我们想要使用SQLite数据库,那么就必须新建一个Helper类来继承SQLiteOpenHelper这个抽象类。
SQLiteHelper代码如下:
public class SQLiteHelper extends SQLiteOpenHelper {SQLiteDatabase mSQLiteDatabase;public SQLiteHelper(Context context) {super(context, DBUtils.SQL_NAME, null, DBUtils.DATABASE_VERSION);mSQLiteDatabase = this.getWritableDatabase();//在数据库创建时即允许写入}/*** 构造函数** @param context* @param name* @param factory* @param version* @param errorHandler*/public SQLiteHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version, DatabaseErrorHandler errorHandler) {super(context, name, factory, version, errorHandler);}public SQLiteHelper(Context context, String name, int version, @NonNull SQLiteDatabase.OpenParams openParams) {super(context, name, version, openParams);}@Overridepublic void onCreate(SQLiteDatabase db) {//创建表String sql = "create table notemane(id integer primary key autoincrement,content varchar(20),time varchar(20),title varchar(20))";db.execSQL(sql);}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}//增public boolean insertDate(String userContent, String userTime, String userTitle) {mSQLiteDatabase = this.getWritableDatabase();//允许写入ContentValues values = new ContentValues();values.put(DBUtils.NOTEPAD_CONTENT, userContent);values.put(DBUtils.NOTEPAD_TIME, userTime);values.put(DBUtils.NOTEPAD_TITLE, userTitle);return mSQLiteDatabase.insert(DBUtils.SQL_TABLE, null, values) > 0;}//删public boolean deleteData(String id) {mSQLiteDatabase = this.getWritableDatabase();//允许写入String sql = DBUtils.NOTEPAD_TIME + "=?";//删除是根据时间删除的,也可以根据id删除,但是根据id删除要考虑到recycleView的position会变化String[] contentValues = new String[]{String.valueOf(id)};return mSQLiteDatabase.delete(DBUtils.SQL_TABLE, sql, contentValues) > 0;}//改public boolean updateData(String id, String userTitle, String userContent, String userTime) {mSQLiteDatabase = this.getWritableDatabase();//允许写入ContentValues values = new ContentValues();values.put(DBUtils.NOTEPAD_TITLE, userTitle);values.put(DBUtils.NOTEPAD_CONTENT, userContent);values.put(DBUtils.NOTEPAD_TIME, userTime);String sql = DBUtils.NOTEPAD_ID + "=?";String[] strings = new String[]{id};return mSQLiteDatabase.update(DBUtils.SQL_TABLE, values, sql, strings) > 0;}}
主界面代码讲解
主界面的主要功能是展示笔记列表,列表这里我选用的是RecycleView。
RecycleView的使用流程: 在主布局中引用RecycleView控件 -> 搭建RecycleView中item的布局 -> 搭建RecycleView的适配器 -> 在MainActivity中使用。
RecycleViewAdapter代码如下:
public class RecycleViewAdapter extends RecyclerView.Adapter<RecycleViewAdapter.ViewHolder> {private static final String TAG = "RecycleViewAdapter";Context mContext;private ArrayList<NoteMessageBean> mList;NoteMessageBean mNoteMessageBean = new NoteMessageBean();//笔记的bean类onRecycleItemClickListener monRecycleItemClickListener;onRecycleItemCheckChangeListener mRecycleItemCheckChangeListener;//构造函数,一个参数public RecycleViewAdapter(Context mContext) {this.mContext = mContext;}//构造函数,两个参数public RecycleViewAdapter(Context mContext, ArrayList<NoteMessageBean> mList) {this.mContext = mContext;this.mList = mList;}@Overridepublic RecycleViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycle_item, parent, false);return new ViewHolder(itemView);}@Overridepublic void onBindViewHolder(RecycleViewAdapter.ViewHolder holder, int position) {mNoteMessageBean = (mList.get(position));holder.text.setText(mNoteMessageBean.getContent());//每个item中的简单介绍holder.title.setText(mNoteMessageBean.getTitle());//每个item中的标题holder.time.setText(mNoteMessageBean.getmTime());//每个item中的时间holder.itemView.setOnClickListener(v -> {if (monRecycleItemClickListener != null) {NoteMessageBean messageBean = mList.get(position);Log.d(TAG, "onBindViewHolder-> itemView -> onClick: " + position + messageBean.getTitle() + messageBean.getContent() + messageBean.getmTime());monRecycleItemClickListener.onItemClick(messageBean.getId(), messageBean.getTitle(), messageBean.getContent(), messageBean.getmTime());}});holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {@Overridepublic boolean onLongClick(View v) {if (mRecycleItemCheckChangeListener != null) {holder.mCheckBox.setVisibility(View.VISIBLE);}return true;}});holder.mCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {Log.d(TAG, "onCheckedChanged: !isChecked" + isChecked);if (!isChecked) {buttonView.setChecked(false);//从选中 -> 未选中状态} else {buttonView.setChecked(true);//从未选中 -> 选中状态//当选中CheckBox时 弹出弹窗提示 是否删除Dialog mDialog = new Dialog(mContext, R.style.ThemeOverlay_AppCompat_Dialog);View view = View.inflate(mContext, R.layout.delete_dialog, null);ImageView mImageView = (ImageView) view.findViewById(R.id.delete_item_image);mDialog.setContentView(view);mDialog.setCanceledOnTouchOutside(false);mDialog.show();Window window = mDialog.getWindow();window.setContentView(view);window.setGravity(Gravity.BOTTOM);WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes();lp.width = WindowManager.LayoutParams.MATCH_PARENT; //设置宽度lp.height = WindowManager.LayoutParams.WRAP_CONTENT; //设置宽度mDialog.getWindow().setAttributes(lp);mDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {@Overridepublic void onCancel(DialogInterface dialog) {//如果手势操作返回键 取消了弹窗显示//则 弹窗取消显示时 对 CheckBox进行隐藏holder.mCheckBox.setChecked(false);holder.mCheckBox.setVisibility(View.GONE);}});//点击删除图标mImageView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {NoteMessageBean messageBean = mList.get(position);mRecycleItemCheckChangeListener.onImageViewOnClick((messageBean.getmTime()), position);mDialog.dismiss();holder.mCheckBox.setVisibility(View.GONE);holder.mCheckBox.setChecked(false);notifyDataSetChanged();}});}}});//这里是给不同的item设置不同的颜色//用position的个位数进行约束int mNumber = position % 10;Log.d(TAG, "onBindViewHolder: " + mNumber);switch (mNumber) {case 0:case 6:holder.itemView.setBackgroundResource(R.drawable.shape_rounded_corners);break;case 1:case 7:holder.itemView.setBackgroundResource(R.drawable.itemstyle0);break;case 2:case 8:holder.itemView.setBackgroundResource(R.drawable.itemstyle1);break;case 3:case 9:holder.itemView.setBackgroundResource(R.drawable.itemstyle2);break;case 4:holder.itemView.setBackgroundResource(R.drawable.itemstyle3);break;case 5:holder.itemView.setBackgroundResource(R.drawable.itemstyle4);break;}}@Overridepublic int getItemCount() {return mList.size();//item数量}/*** 为列表设置数据源** @param data*/public void setList(ArrayList<NoteMessageBean> data) {this.mList = data;notifyDataSetChanged();}public class ViewHolder extends RecyclerView.ViewHolder {private TextView title, text, time;private ConstraintLayout mLinearLayout;private CheckBox mCheckBox;public ViewHolder(View itemView) {super(itemView);text = itemView.findViewById(R.id.text_note);title = itemView.findViewById(R.id.title_note);time = itemView.findViewById(R.id.time_note);mLinearLayout = itemView.findViewById(R.id.item_layout);mCheckBox = itemView.findViewById(R.id.radioButton);}}/*** RecycleView的点击回调*/public interface onRecycleItemClickListener {void onItemClick(String id, String Title, String content, String time);}public void setOnItemClickListener(onRecycleItemClickListener listener) {monRecycleItemClickListener = listener;}/*** 删除动作的回调*/public interface onRecycleItemCheckChangeListener {void onImageViewOnClick(String time, int position);}public void setOnItemLongClickListener(onRecycleItemCheckChangeListener listener) {mRecycleItemCheckChangeListener = listener;}}
RecycleView在MainActivity中使用流程如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener, RecycleViewAdapter.onRecycleItemClickListener, RecycleViewAdapter.onRecycleItemCheckChangeListener {private RecycleViewAdapter mAdapter;
private LinearLayoutManager manager;
private RecyclerView mRecyclerView;@Overrideprotected void onCreate(Bundle savedInstanceState) {Log.d(TAG, "onCreate: ");super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();}private void initView() {mRecyclerView = findViewById(R.id.recycler_view);mAdapter = new RecycleViewAdapter(this, mList);mAdapter.setOnItemClickListener(this);mAdapter.setOnItemLongClickListener(this);manager = new LinearLayoutManager(getApplicationContext());mRecyclerView.setLayoutManager(manager);mRecyclerView.setAdapter(mAdapter);}//代码篇幅略长,仅展示RecycleView在MainActivity如何使用}
编辑界面代码讲解
编辑界面的主要功能:1.新建笔记时写入内容标题等。2.打开笔记时对原有笔记进行修改。
其主要的布局为EditText。
编辑界面主要代码如下:
public class EditActivity extends AppCompatActivity implements View.OnClickListener {private static final String TAG = "EditActivity";private ImageView mBack, mCommit;private EditText mTitle, mContent;private TextView mTime;private SQLiteHelper mSQLiteHelper;private Context mContext;private boolean flag;private String id;protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.edit_activity_layout);initView();initData();}private void initView() {mBack = findViewById(R.id.bt_back);mBack.setOnClickListener(this);mCommit = findViewById(R.id.bt_commit);mCommit.setOnClickListener(this);mTitle = findViewById(R.id.edit_title);mContent = findViewById(R.id.edit_text);mTime = findViewById(R.id.time_date);}private void initData() {Log.d(TAG, "initData: ");mSQLiteHelper = new SQLiteHelper(getApplicationContext());mTime.setText(DBUtils.getTime());Intent intent = getIntent();flag = intent.getBooleanExtra("flag", false);//以flag为基准,有且仅有点击item之后才会调用 intent.putExtra("flag", true);if (flag) {id = intent.getStringExtra("id");mTitle.setText(intent.getStringExtra("title"));mContent.setText(intent.getStringExtra("content"));mTime.setText(intent.getStringExtra("time"));}}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.bt_back:Intent intent = new Intent(EditActivity.this, MainActivity.class);startActivity(intent);break;case R.id.bt_commit:if (mContent.length() == 0) {//当内容为空时,提醒一下,不创建新的itemToast.makeText(this.getApplicationContext(), "请输入文本内容后再进行提交操作!", Toast.LENGTH_SHORT).show();} else {if (flag) {//为true表示现在是打开了一个item进行修改编辑 并不是新建笔记mSQLiteHelper.updateData(id, mTitle.getText().toString(), mContent.getText().toString(), mTime.getText().toString());//更新数据后 跳转到MainActivity页面刷新数据Intent mIntent = new Intent(EditActivity.this, MainActivity.class);startActivity(mIntent);} else {//内容不为空则调用对应的数据库插入操作mSQLiteHelper.insertDate(mContent.getText().toString(), DBUtils.getTime(), mTitle.getText().toString());//插入数据之后 跳转到main页面 更新列表视图Intent mIntent = new Intent(EditActivity.this, MainActivity.class);startActivity(mIntent);}}break;}}}
至此,笔记APP的基本功能完成,扩展功能目前的计划加入 手写输入功能,图片插入功能,语音输入功能,搜索功能。
扩展功能以及源码我会逐渐更新在公众号中(二两仙气儿),毕竟我也不能一直摸鱼(狗头)。
从无到有,一步一步实现记事本APP(一)相关推荐
- 从无到有,一步一步实现记事本APP(二)
在上一篇文章中,我们已经实现了记事本APP的基本功能,本篇文章主要介绍如何实现手写板功能,以及手写素材如何保存. 手写板(手写输入/涂鸦)实现的大致思路如下:设置固定颜色的画板 -> 监听Tou ...
- 一步一步教你玩转.NET Framework的配置文件app.config (转载)
一步一步教你玩转.NET Framework的配置文件app.config 在一般的项目中,为了使你的代码更加灵活,更方便调整,减少不必要的hard code,我们都在config中添加许多配置信息, ...
- android一步一步实现视频客户端app(一)
我开发完成了一个完整的视频客户端app,现在,分享出来,供初学者学习参考(大神就不用看了,比较简单,仅供入门),大家相互交流相互学习.项目有些功能,我时间也不是很多,只能时不时更新下.只能大概讲解怎么 ...
- android记事本报告,百度云记事本app交互体验报告
体验设备 体验产品:百度云记事本app 产品版本:Android V 2.1.1 体验机型:三星Note2 操作系统:Android4.3 体验时间:2016.01.25-2016.01.30 整体 ...
- 一步一步教你在 Android 里创建自己的账号系统(一)
大家假设喜欢我的博客,请关注一下我的微博,请点击这里(http://weibo.com/kifile),谢谢 转载请标明出处(http://blog.csdn.net/kifile),再次感谢 大家在 ...
- 一步一步学Silverlight 2系列(18):综合实例之RSS阅读器
概述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, ...
- 手挽手带你学React:四档(上)一步一步学会react-redux (自己写个Redux)
手挽手带你学React入门四档,用人话教你react-redux,理解redux架构,以及运用在react中.学完这一章,你就可以开始自己的react项目了. 之前在思否看到过某个大神的redux搭建 ...
- 一步一步学Silverlight 2系列(9):使用控件模板
版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://terrylee.blog.51cto.com/342737/67243 ...
- 据lovecherry的一步一步学Remoting序列文章学习.net Remoting日记(2)
今天学习了服务器端激活和客户端激活的区别!可还是出现了一点点的差错,经过对比得到正确的调用方法,整理如下: 1.服务器端激活,分为两种方式Singleton和SingleCall方式 Server端A ...
最新文章
- 运行VC++6.0出现error LNK2001: unresolved external symbol _WinMain@16
- python的垃圾回收机制和析构函数__del__
- dump导入oracle需要提前建表吗_数据库dump导入
- OCR-PIL.Image与Base64 String的互相转换
- c语言打印空心等腰梯形乐学,C语言做激光发射
- PHP双码率视频云转码服务网站源码 支持M3u8秒切
- VMware vSphere第三方免费工具介绍之一:RVTools
- Power BI 与 Azure Analysis Services 的数据关联:4、Power BI 连接到Azure Analysis Services 并展示...
- 国内四大炒股软件APP 全面技术解析
- 从零开始制作PPT(母版设计,素材填充,配色等)
- TensorFlow: A System for Large-Scale Machine Learning翻译
- 03、集合之ArrayList
- 【Linux常用服务器配置——Samba服务】
- Unity Metaverse(四)、接入环信IM SDK 实现用户登录注册
- 占带宽测试软件,铁通网速测试
- scrapy实现链家二手房的数据获取并进行持久化存储
- 2022-2028年中国银行保险市场投资分析及前景预测报告
- PHP反序列化与SESSION
- 宅急送项目第三天笔记!(SVN插件和反编译插件)
- 从XData大数据一体机看曙光转型