联系我们
简单又实用的WordPress网站制作教学
当前位置:网站首页 > 程序开发学习 > 正文

轻松上手:(三)笔记可再编辑

作者:访客发布时间:2024-02-14分类:程序开发学习浏览:180


导读:我。引言点击查看该项目GitHub地址本文将主要实现笔记的点击编辑功能:用户可以点击笔记列表中的项,进入编辑页面,编辑该笔记的内容.二、前情回顾轻松上手:(一)入门与笔记应用浅开...

我。引言

点击查看该项目GitHub地址

本文将主要实现笔记的点击编辑功能: 用户可以点击笔记列表中的项,进入编辑页面,编辑该笔记的内容.

二、前情回顾

轻松上手:(一)入门与笔记应用浅开发

轻松上手:(二)笔记可显示第1部分:实现逻辑与TextView

轻松上手:(二)笔记可显示第2部分:定义笔记的数据结构类型

轻松上手:(二)笔记可显示第3部分:适配器

轻松上手:(二)大功告成!添加新笔记!

为了创建一个简单的安卓笔记应用,前文已经成功实现了以下主要功能:

  1. 笔记的展示:主活动(MainActivity)中通过一个列表视图(ListView)展示了所有笔记的内容和创建时间.

  2. 笔记的添加:用户通过悬浮按钮(FloatingActionButton)可以添加新的笔记,进入编辑页面(EditActivity)、并在该页面输入笔记内容后保存.

  3. 笔记的保存和显示:新添加的笔记会保存在SQLite数据库中,主活动在每次启动时从数据库读取笔记列表,并通过适配器(NoteAdapter)将笔记显示在列表视图中.

三.编辑活动类(编辑活动)的更新

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>
  • 启动编辑活动:
    • 通过点击悬浮按钮(FloatingActionButton)打开并编辑新笔记;
    • 通过点击列表中的笔记项更新旧笔记.

2.加载现有笔记数据的方法loadNoteData

编辑功能需要加载现有笔记数据以便进行编辑. 点击列表中的现有笔记时,跳转到编辑活动界面,并展示该笔记的原有数据.

  • 加载逻辑:
    • 通过传递的note_id判断是新建笔记还是编辑现有笔记.
  • 备注_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.编辑活动类(编辑活动)更新后的代码

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); // 格式化日期并返回字符串
    }
}

四、适配器的改进

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;
    }
}

五.主活动的更新

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.主活动类(主要活动)更新后的代码

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();
    }
}

六、六、数据库操作的扩展

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。
        );
    }
}

七、结语

在本文中,我们深入探讨了从初始代码到实现编辑功能的全过程.通过介绍编辑活动、适配器的改进、主活动的更新以及数据库操作的扩展,我们建立了一个功能进一步完善的安卓笔记应用。通过不懈的努力和不断的学习,我们可以打造出更加强大、高效的移动应用.继续热爱编程,不断挑战自我,开发更出色的应用吧!🚀

🫡🫡🫡...持续爆肝更新中

👍🩷💕求点赞求关注求转发


标签:笔记上手编辑轻松安卓系统演播室


程序开发学习排行
最近发表
网站分类
标签列表