I. 引言
本文将首要完成笔记的点击修改功用:
用户能够点击笔记列表中的项,进入修改页面,修改该笔记的内容。
II. 前情回忆
轻松上手:<Android Studio笔记使用开发>(一)入门与笔记使用浅开发
轻松上手:<Android Studio笔记使用开发>(二)笔记可显现Part1:完成逻辑与textView
轻松上手:<Android Studio笔记使用开发>(二)笔记可显现Part2:界说笔记的数据结构类型
轻松上手:<Android Studio笔记使用开发>(二)笔记可显现Part3:适配器
轻松上手:<Android Studio笔记使用开发>(二)功德圆满!增加新笔记!
为了创立一个简单的Android笔记使用,前文已经成功完成了以下首要功用:
-
笔记的展现: 主活动(
MainActivity
)中经过一个列表视图(ListView
)展现了一切笔记的内容和创立时刻。 -
笔记的增加: 用户经过悬浮按钮(
FloatingActionButton
)能够增加新的笔记,进入修改页面(EditActivity
),并在该页面输入笔记内容后保存。 -
笔记的保存和显现: 新增加的笔记会保存在 SQLite 数据库中,主活动在每次发动时从数据库读取笔记列表,并经过适配器(
NoteAdapter
)将笔记显现在列表视图中。
III. 修改活动类 (EditActivity) 的更新
1. 修改活动的设计和布局
-
布局设计: 采用垂直方向的线性布局,包括一个
EditText
用于用户输入笔记内容。
<?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">
<EditText
android:id="@+id/et"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="top">
</EditText>
</LinearLayout>
-
发动 EditActivity:
- 经过点击悬浮按钮 (
FloatingActionButton
) 打开并修改新笔记; - 经过点击列表中的笔记项更新旧笔记。
- 经过点击悬浮按钮 (
2. 加载现有笔记数据的办法 loadNoteData
修改功用需求加载现有笔记数据以便进行修改。
点击列表中的现有笔记时,跳转到修改活动界面,并展现该笔记的原有数据。
-
加载逻辑:
- 经过传递的
note_id
判别是新建笔记仍是修改现有笔记。
- 经过传递的
-
note_id
-
note_id
是干啥用的?note_id
用于在修改活动 (EditActivity
) 中标识要修改的笔记。经过传递note_id
,咱们能够从数据库中获取相应笔记的数据,并在修改界面中显现原有内容。 -
note_id
如何标识要修改的笔记(如有)?note_id
是经过在目的(Intent)中附加额定信息的办法传递的。在发动修改活动时,经过点击悬浮按钮或点击列表项触发的事情,咱们会创立一个目的 (Intent
) 并附加note_id
作为额定的信息。在修改活动中,经过getIntent().getLongExtra("note_id", -1)
获取传递的note_id
,默许值为 -1 表明没有传递有用的note_id
。
-
// 从 EditActivity 获取传递的 note_id 额定信息,默以为 -1
long noteId = getIntent().getLongExtra("note_id", -1);
if (noteId != -1) {
// 加载现有笔记数据以便修改
loadNoteData(noteId);
}
-
数据库操作: 经过数据库操作类 (
CRUD
) 获取指定note_id
的笔记数据,并将其展现在修改界面上。
CRUD op = new CRUD(this);
op.open();
Note existingNote = op.getNoteById(noteId);
op.close();
et.setText(existingNote.getContent());
-
注意:
Note getNoteById(long noteId)
现在尚未完成。
3. 判别新建仍是更新笔记
-
经过
note_id
判别是新建仍是更新笔记: 经过传递的note_id
是否为默许值(-1)来判别是新建笔记仍是修改现有笔记。
long noteId = getIntent().getLongExtra("note_id", -1);
if (noteId == -1L) {
// 假如是新笔记,直接传递数据
setResult(RESULT_OK, intent);
} else {
// 假如是现有笔记,传递 ID
intent.putExtra("note_id", noteId);
setResult(RESULT_OK, intent);
}
经过以上步骤,修改活动类得以引进,并且能够依据传递的 note_id
区分新建笔记和修改现有笔记,为后续修改功用的完成奠定了基础。
4. 修改活动类 (EditActivity) 更新后的代码
package com.example.my_notes_record;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import android.widget.EditText;
import androidx.appcompat.app.AppCompatActivity;
import java.text.SimpleDateFormat;
import java.util.Date;
public class EditActivity extends AppCompatActivity{
private String content; // 声明用于存储笔记内容的变量
private String time; // 声明用于存储笔记时刻的变量
EditText et; // 声明文本修改框
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.edit_layout); // 设置视图为 "edit_layout"
et = findViewById(R.id.et); // 从布局文件中获取文本修改框
// 检查是否存在note_id额定信息
long noteId = getIntent().getLongExtra("note_id", -1);
if (noteId != -1) {
// 加载现有笔记数据以便修改
loadNoteData(noteId);
}
}
// 办法用于加载现有笔记数据
private void loadNoteData(long noteId) {
// 使用CRUD或其他办法依据noteId检索现有笔记数据
CRUD op = new CRUD(this);
op.open();
Note existingNote = op.getNoteById(noteId);
op.close();
// 用现有笔记内容填充EditText
et.setText(existingNote.getContent());
}
// 处理按键事情
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_HOME) {
return true; // 假如按下 HOME 键,回来 true,表明事情已处理
} else if (keyCode == KeyEvent.KEYCODE_BACK) {
Intent intent = new Intent(); // 创立一个新目的
intent.putExtra("content", et.getText().toString()); // 将修改框中的文本内容放入目的中
intent.putExtra("time", dateToString()); // 将当时时刻放入目的中
// 获取传递的note_id额定信息,默以为-1
long noteId = getIntent().getLongExtra("note_id", -1L);
if (noteId == -1L) {
// 关于新笔记,直接传递数据
setResult(RESULT_OK, intent);
} else {
// 关于现有笔记,传递ID
intent.putExtra("note_id", noteId);
setResult(RESULT_OK, intent);
}
finish(); // 结束当时活动
return true; // 回来 true,表明事情已处理
}
return super.onKeyDown(keyCode, event); // 假如按键不是 HOME 或 BACK,使用默许处理
}
// 将当时时刻格局化为字符串
public String dateToString(){
Date date = new Date(); // 获取当时日期和时刻
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 创立日期格局化器
return simpleDateFormat.format(date); // 格局化日期并回来字符串
}
}
IV. 适配器的改善
1. 引进笔记项点击的回调接口 OnNoteItemClickListener
在原来的代码里,适配器(
NoteAdapter
)首要担任将数据与列表项的视图绑定,但没有处理列表项的点击事情。为了支撑修改功用,咱们需求在适配器中引进一个回调接口,用于处理笔记项的点击事情。
2. 增加 OnNoteItemClickListener
接口
- 在
NoteAdapter
类中增加一个接口OnNoteItemClickListener
,界说笔记项点击的回调办法。
public interface OnNoteItemClickListener {
void onNoteItemClick(long noteId);
}
3. 注册点击事情监听器
- 在
NoteAdapter
中增加一个成员变量用于存储回调接口的实例,并在getView
办法中注册点击事情监听器。
private OnNoteItemClickListener onNoteItemClickListener;
public NoteAdapter(Context context, List<Note> noteList, OnNoteItemClickListener onNoteItemClickListener) {
this.context = context;
this.noteList = noteList;
this.onNoteItemClickListener = onNoteItemClickListener;
}
4. 在 getView
中触发回调
- 在
getView
办法中,当笔记项被点击时,触发回调接口的办法,将点击事情传递给主活动类处理。
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 触发笔记项点击事情
if (onNoteItemClickListener != null) {
onNoteItemClickListener.onNoteItemClick(noteList.get(position).getId());
}
}
});
5. 适配器改善后的代码
package com.example.my_notes_record;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.List;
public class NoteAdapter extends BaseAdapter {
public interface OnNoteItemClickListener {
void onNoteItemClick(long noteId);
}
private Context context;
private List<Note> noteList;
private OnNoteItemClickListener onNoteItemClickListener;
// 默许结构函数
public NoteAdapter(){
}
// 带参数的结构函数,承受上下文和笔记列表
public NoteAdapter(Context Context,List<Note> noteList){
this.context=Context;
this.noteList=noteList;
}
public NoteAdapter(Context context, List<Note> noteList, OnNoteItemClickListener onNoteItemClickListener) {
this.context = context;
this.noteList = noteList;
this.onNoteItemClickListener = onNoteItemClickListener;
}
// 获取列表项数量
@Override
public int getCount() {
return noteList.size();
}
// 获取指定方位的笔记目标
@Override
public Object getItem(int position){
return noteList.get(position);
}
// 获取指定方位的笔记ID
@Override
public long getItemId(int position){
return position;
}
// 创立并回来每个列表项的视图
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 从XML布局文件实例化视图
View view = View.inflate(context, R.layout.note_list_item, null);
// 获取布局中的TextView控件
TextView tv_content = (TextView) view.findViewById(R.id.tv_content);
TextView tv_time = (TextView) view.findViewById(R.id.tv_time);
// 从笔记目标中获取内容和时刻信息
String allText = noteList.get(position).getContent();
// 设置TextView的文本内容
tv_content.setText(allText.split("n")[0]);
tv_time.setText(noteList.get(position).getTime());
// 将笔记ID作为视图的标签
view.setTag(noteList.get(position).getId());
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 触发笔记项点击事情
if (onNoteItemClickListener != null) {
onNoteItemClickListener.onNoteItemClick(noteList.get(position).getId());
}
}
});
return view;
}
}
V. 主活动的更新
1. 完成接口 NoteAdapter.OnNoteItemClickListener
在主活动类中完成 NoteAdapter.OnNoteItemClickListener
接口,以处理笔记项的点击事情。
public class MainActivity extends AppCompatActivity implements NoteAdapter.OnNoteItemClickListener {
2. 适配器初始化
在主活动的 onCreate
办法中初始化适配器时,将当时主活动实例传递给适配器。
adapter = new NoteAdapter(getApplicationContext(), noteList , this);
3. 完成接口办法
完成接口中的办法 onNoteItemClick
,该办法在用户点击笔记项时被调用,担任处理点击事情。
@Override
public void onNoteItemClick(long noteId) {
// 处理项点击,发动 EditActivity 并传递选定笔记以进行修改
Intent intent = new Intent(MainActivity.this, EditActivity.class);
intent.putExtra("note_id", noteId);
someActivityResultLauncher.launch(intent);
}
4. 处理修改活动回来的数据
在主活动的 someActivityResultLauncher
中,获取从修改活动回来的数据,包括修改框中的文本内容、时刻以及笔记的ID。
long noteId = data.getLongExtra("note_id", -1);
// 检查是否是新笔记仍是更新现有笔记
if (noteId == -1L) {
// 假如是新笔记,调用增加新笔记的办法
if (!content.isEmpty()) addNewNote(content, time);
} else {
// 假如是现有笔记,调用更新现有笔记的办法
updateExistingNote(noteId, content, time);
}
5. 增加新笔记和更新现有笔记的办法
完成增加新笔记和更新现有笔记的办法,经过数据库操作类(CRUD
)进行相应的操作。
// 增加新笔记
private void addNewNote(String content, String time) {
CRUD op = new CRUD(this);
op.open();
Note newNote = new Note(content, time);
op.addNote(newNote);
op.close();
}
// 更新现有笔记
private void updateExistingNote(long noteId, String content, String time) {
CRUD op = new CRUD(this);
op.open();
Note updatedNote = new Note(content, time);
updatedNote.setId(noteId);
op.updateNote(updatedNote);
op.close();
}
6. 主活动类 (MainActivity)更新后的代码
package com.example.my_notes_record;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.ArrayList;
import java.util.List;
// 创立名为 "MainActivity" 的主活动类
public class MainActivity extends AppCompatActivity implements NoteAdapter.OnNoteItemClickListener {
private Context context = this; // 上下文目标,用于数据库操作
private NoteDatabase dbHelper; // 数据库帮助类
private NoteAdapter adapter; // 笔记适配器
private List<Note> noteList = new ArrayList<>(); // 笔记列表
private FloatingActionButton btn; // 悬浮按钮
private ListView lv; // 列表视图
// 界说一个 ActivityResultLauncher,用于处理其他活动的成果
private ActivityResultLauncher<Intent> someActivityResultLauncher;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//调用父类的 onCreate 办法,用于履行一些初始化操作
//savedInstanceState 参数用于恢复之前的状况
setContentView(R.layout.activity_main);//设置当时 Activity 的布局
btn = findViewById(R.id.floatingActionButton); // 悬浮按钮
lv = findViewById(R.id.lv); // 列表视图,用于显现数据列表
adapter = new NoteAdapter(getApplicationContext(), noteList , this);//初始化一个笔记适配器,并将使用的上下文目标和笔记列表传递给适配器
refreshListView(); // 改写笔记列表
lv.setAdapter(adapter); // 将适配器与列表视图关联,然后显现笔记列表中的数据在界面上
// 初始化 ActivityResultLauncher,用于处理发动其他活动的成果
someActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK) {
Intent data = result.getData();
if (data != null) {
// 从 EditActivity 回来的内容和时刻
String content = data.getStringExtra("content");
String time = data.getStringExtra("time");
long noteId = data.getLongExtra("note_id", -1);
// 检查是否是新笔记仍是更新现有笔记
if (noteId == -1L) {
// 假如是新笔记,调用增加新笔记的办法
if(!content.isEmpty()) addNewNote(content, time);
} else {
// 假如是现有笔记,调用更新现有笔记的办法
updateExistingNote(noteId, content, time);
}
refreshListView(); // 改写笔记列表
}
}
}
);
// 设置悬浮按钮的点击事情监听器
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 发动 EditActivity 并等候成果
Intent intent = new Intent(MainActivity.this, EditActivity.class);
someActivityResultLauncher.launch(intent);
}
});
}
// 改写笔记列表
public void refreshListView() {
// 创立数据库操作目标,打开数据库衔接
CRUD op = new CRUD(context);
op.open();
if (noteList.size() > 0) noteList.clear(); // 清空笔记列表
noteList.addAll(op.getAllNotes()); // 获取数据库中一切笔记
op.close(); // 封闭数据库衔接
adapter.notifyDataSetChanged(); // 告诉适配器数据已更改,改写列表视图
}
@Override
public void onNoteItemClick(long noteId) {
// 处理项点击,发动 EditActivity 并传递选定笔记以进行修改
Intent intent = new Intent(MainActivity.this, EditActivity.class);
intent.putExtra("note_id", noteId);
someActivityResultLauncher.launch(intent);
}
// 增加新笔记
private void addNewNote(String content, String time) {
CRUD op = new CRUD(this);
op.open();
Note newNote = new Note(content, time);
op.addNote(newNote);
op.close();
}
// 更新现有笔记
private void updateExistingNote(long noteId, String content, String time) {
CRUD op = new CRUD(this);
op.open();
Note updatedNote = new Note(content, time);
updatedNote.setId(noteId);
op.updateNote(updatedNote);
op.close();
}
}
VI. 数据库操作的扩展
1. 完成依据 ID 获取笔记的办法
为了支撑修改功用,咱们需求在数据库操作类(CRUD
)中增加一个办法,依据笔记的ID获取笔记的详细信息。
// 依据笔记ID获取笔记详细信息
public Note getNoteById(long noteId) {
String[] columns = {NoteDatabase.ID, NoteDatabase.CONTENT, NoteDatabase.TIME};
Cursor cursor = database.query(
NoteDatabase.TABLE_NAME,
columns,
NoteDatabase.ID + " = ?",
new String[]{String.valueOf(noteId)},
null,
null,
null
);
if (cursor != null) {
cursor.moveToFirst();
Note note = cursorToNote(cursor);
cursor.close();
return note;
} else {
return null;
}
}
2. 增加更新笔记的办法
为了在修改活动中更新现有笔记,咱们需求在数据库操作类中增加一个更新笔记的办法。
// 更新现有笔记
public void updateNote(Note note) {
ContentValues values = new ContentValues();
values.put(NoteDatabase.CONTENT, note.getContent());
values.put(NoteDatabase.TIME, note.getTime());
return database.update(
NoteDatabase.TABLE_NAME,
values,
NoteDatabase.ID + " = ?",
new String[]{String.valueOf(note.getId())}
);
}
3. 数据库操作类 (CRUD) 扩展后的代码
package com.example.my_notes_record;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import java.util.ArrayList;
import java.util.List;
public class CRUD {
SQLiteOpenHelper dbHandler; // SQLiteOpenHelper 实例用于处理数据库衔接
SQLiteDatabase db; // SQLiteDatabase 实例用于履行数据库操作
// 界说数据库表的列名
private static final String[] columns = {
NoteDatabase.ID,
NoteDatabase.CONTENT,
NoteDatabase.TIME
};
// 结构办法,承受上下文参数
public CRUD(Context context) {
dbHandler = new NoteDatabase(context); // 初始化数据库处理器
}
// 打开数据库衔接
public void open() {
db = dbHandler.getWritableDatabase(); // 获取可写的数据库衔接
}
// 封闭数据库衔接
public void close() {
dbHandler.close(); // 封闭数据库处理器
}
// 增加一条笔记记载
public Note addNote(Note note) {
ContentValues contentValues = new ContentValues(); // 创立一个用于存储数据的 ContentValues 目标
contentValues.put(NoteDatabase.CONTENT, note.getContent()); // 增加内容
contentValues.put(NoteDatabase.TIME, note.getTime()); // 增加时刻
long insertId = db.insert(NoteDatabase.TABLE_NAME, null, contentValues); // 将数据插入数据库
note.setId(insertId); // 将插入后的 ID 设置到笔记目标中
return note; // 回来包括新数据的笔记目标
}
public List<Note> getAllNotes() {
Cursor cursor = db.query(
NoteDatabase.TABLE_NAME, // 表名
columns, // 要查询的列(在这里是ID、内容、时刻)
null, // 查询条件(null表明无特殊条件)
null, // 查询条件参数(null表明无特殊条件)
null, // 分组办法(null表明不分组)
null, // 过滤办法(null表明不过滤)
null // 排序办法(null表明不排序)
);
List<Note> notes = new ArrayList<>(); // 创立一个笔记列表用于存储查询成果
if (cursor.getCount() > 0) {
while (cursor.moveToNext()) {
Note note = new Note(); // 创立笔记目标
note.setId(cursor.getLong(cursor.getColumnIndex(NoteDatabase.ID))); // 设置 ID
note.setContent(cursor.getString(cursor.getColumnIndex(NoteDatabase.CONTENT))); // 设置内容
note.setTime(cursor.getString(cursor.getColumnIndex(NoteDatabase.TIME))); // 设置时刻
notes.add(note); // 将笔记目标增加到列表中
}
}
cursor.close(); // 封闭游标
return notes; // 回来包括一切笔记记载的列表
}
// 依据 ID 获取笔记
public Note getNoteById(long noteId) {
// 查询数据库,获取指定 ID 的笔记记载
Cursor cursor = db.query(
NoteDatabase.TABLE_NAME, // 表名
columns, // 要查询的列(在这里是ID、内容、时刻)
NoteDatabase.ID + "=?", // 查询条件(经过 ID 进行查询)
new String[]{String.valueOf(noteId)}, // 查询条件参数(指定要查询的 ID 值)
null, // 分组办法(null表明不分组)
null, // 过滤办法(null表明不过滤)
null // 排序办法(null表明不排序)
);
Note note = null;
if (cursor.moveToFirst()) {
// 假如查询到成果,则创立新的笔记目标并设置其特点
note = new Note();
note.setId(cursor.getLong(cursor.getColumnIndex(NoteDatabase.ID))); // 设置 ID
note.setContent(cursor.getString(cursor.getColumnIndex(NoteDatabase.CONTENT))); // 设置内容
note.setTime(cursor.getString(cursor.getColumnIndex(NoteDatabase.TIME))); // 设置时刻
}
cursor.close(); // 封闭游标,释放资源
return note; // 回来获取到的笔记目标,假如未找到则回来 null
}
// 更新笔记
public void updateNote(Note note) {
// 创立一个 ContentValues 目标,用于存储要更新的数据
ContentValues values = new ContentValues();
values.put(NoteDatabase.CONTENT, note.getContent());
values.put(NoteDatabase.TIME, note.getTime());
// 履行数据库更新操作
db.update(
NoteDatabase.TABLE_NAME, // 表名
values, // 更新的内容值
NoteDatabase.ID + "=?", // 更新条件(经过 ID 进行更新)
//`"=?"` 是一个占位符,它表明在 SQL 查询中使用参数。这是一种防止 SQL 注入进犯的办法。在这里,它表明将在这个方位上填入详细的数值。
new String[]{String.valueOf(note.getId())} // 更新条件参数(指定要更新的 ID 值)
//创立一个字符串数组,数组中包括了要替代占位符 `"=?"` 的详细数值。在这里,它包括了笔记目标的 ID。
);
}
}
VII. 结语
在本文中,咱们深入探讨了从初始代码到完成修改功用的全过程。经过介绍修改活动、适配器的改善、主活动的更新以及数据库操作的扩展,咱们建立了一个功用进一步完善的Android笔记使用。经过不懈的努力和不断的学习,咱们能够打造出愈加强壮、高效的移动使用。继续热爱编程,不断挑战自我,开发更出色的使用吧!