jjzjj

Android备忘录项目总结

henu_GM 2023-03-28 原文

项目要求:

Android 端备忘录项目
        需求描述:我希望有一个 Android 端的 App,能让我随时随地记录一件事情,并且它能自动
帮我记下我写这段文字的时间和地点,另外,我希望它不仅能输入文字,必要时也要能插入图
片。此外,有一些内容我不希望别人能看到,当点开这条内容时最好有一个身份验证过程。
        功能分析:
        1、 用户输入文字、插入图片或拍照。
        2、 每条内容存储到本地。
        3、 获取用户当前位置信息并显示在每条记录的合适位置。
        4、 用户新建一条记录时可选择是否把该条记录设置为私密,选择“是”,则每次打开时进行
身份验证(身份验证机制用户自己决定)。

 

项目完成情况:

  • 主功能实现:笔记的展示与全体笔记的删除。
​ 主页面

 

​ 标题
​ 查看已经标记为私密的记录要输入暗号
  • 分支功能实现:笔记的添加单个笔记的删除与加密,最重要的是可以获取手机本地相册和授权相机进行拍照
​ edit编辑页面
​ 相机拍照功能
​ 本地图片选取

 

​ 点击雨伞,改变保密状态

 

​ edit页面删除单个记录
  • 分支功能实现:弹出菜单实现点击设置按钮修改密码功能

 

​ 弹出菜单

 

​ 更改密码界面

 注:地理位置将在007note2.0中由小灰灰实现。


 功能实现详解:

         我在三人小组中参与了主页面添加笔记功能的构建,单独完成了主页面的全部删除功能以及edit页面的单独删除功能,在之后添加了加密功能,完成弹出菜单以及修改密码操作。

        重点讲讲我单独做出那几个功能。

删除功能:

        首先是设置在主页的全部删除功能

    @Override
    public boolean onOptionsItemSelected(MenuItem item){
        switch (item.getItemId()){
            case R.id.menu_clear:
                final EditText et = new EditText(this);
                new AlertDialog.Builder(MainActivity.this)
                        .setMessage("要删除全部记录要密码哦,你要删吗,赶紧输入我们的暗号")
                        .setIcon(android.R.drawable.sym_def_app_icon)
                        .setView(et)
                        .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                if(et.getText().toString().equals(code)){
                                    dbHelper =new NoteDatabase(context);
                                    SQLiteDatabase db =dbHelper.getWritableDatabase();
                                    db.delete("notes",null,null);
                                    refreshListView();
                                }
                                else{
                                    fail();
                                }
                            }
                        }).setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                }).create().show();
                break;
        }
        return super.onOptionsItemSelected(item);
    }

        在上述代码中,我利用菜单的响应事件,根据菜单中的item的id来判定响应事件,利用switch的优势,判断触发的事件是不是全局删除。如果是,代码继续执行。

        定义一个文本类型变量et保存需要输入的暗号密码,输入暗号后,点击OK进入判断,如果暗号符合,则进行数据库数据删除操作,暗号不符合则执行fail方法,提示密码错误,然后再关闭对话框。

        再者,是edit页面的单独删除功能:

case R.id.delete:
                new AlertDialog.Builder(EditActivity.this)
                        .setMessage("真的要删除吗,呜呜呜")
                        .setPositiveButton(android.R.string.yes,new DialogInterface.OnClickListener(){
                            @Override
                            public void onClick(DialogInterface dialog,int which){
                                    intent.putExtra("mode",2);
                                    intent.putExtra("id",id);
                                    setResult(RESULT_OK,intent);
                                finish();
                            }
                        }).setNegativeButton(android.R.string.no,new DialogInterface.OnClickListener(){
                    @Override
                    public void onClick(DialogInterface dialog,int which){
                        dialog.dismiss();
                    }
                }).create().show();
                break;

        在EditActivity中,我仍然是用菜单的响应事件,根据菜单中的item的id来判定响应事件,利用switch判断触发的事件是不是单个记录的删除。

        确定要删除这条记录时,传mode=2和这条记录的id到MainAcitivty中的接收方法onActivityResult中去。

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data){
        int returnMode;
        long note_id;
        returnMode = data.getExtras().getInt("mode",-1);/*mode,默认是-1,代表什么都不用做*/
        note_id = data.getExtras().getLong("id", 0);/*默认值的意思就是,没找到就是默认值*/

        /*根据返回mode判断,-2代表什么都不做,0代建表新,1或者-1代表修改*/
        if(returnMode == 1 || returnMode == -1) {
            String content = data.getExtras().getString("content");
            String time = data.getExtras().getString("time");
            int tag = data.getExtras().getInt("tag", 1);
            int flag = data.getExtras().getInt("flag");
            String path = data.getExtras().getString("path");

            Note newNote = new Note(content, time, tag, path, flag);
            newNote.setId(note_id);
            CRUD op = new CRUD(context);
            op.open();
            op.updateNote(newNote);  /*修改表中记录*/
            op.close();
        } else if (returnMode == 0) {
            String content = data.getExtras().getString("content");
            String time = data.getExtras().getString("time");
            int tag = data.getExtras().getInt("tag", 1);
            String path = data.getExtras().getString("path");/*没有图片,接收到的是"null"*/
            int flag = data.getExtras().getInt("flag");

            Note newNote = new Note(content, time, tag, path, flag);
            CRUD op = new CRUD(context);
            op.open();
            op.addNote(newNote);     /*添加到表中*/
            op.close();
        }else if(returnMode==2){
            Note curNote=new Note();
            curNote.setId(note_id);
            CRUD op=new CRUD(context);
            op.open();
            op.removeNote(curNote);
            op.close();
        }
        refreshListView();
        super.onActivityResult(requestCode, resultCode, data);/*调用基类的方法*/
    }

        那么MainActivity就对returnmode==2的情况进行操作,对已传回id的那条记录进行数据删除操作。

加密功能实现:

        加密功能的思路:首先我们确定一下加密需要应用到哪个地方,第一,在首页点开加密记录的时候需要一个密码验证;第二,在首页全部删除功能应用的时候应该进行密码验证;第三,在修改密码的时候会验证一下旧密码。

        然后考虑这个功能具体怎么实现,一开始,我想创建两个独立的数据库,创建两个主页面存放两个独立的列表,在主列表里面放不需要加密的记录,在保密界面列表存放需要加密的记录,然后在两个页面的menu上面放一个转换页面的按钮,点击按钮就会跳转页面,在从主页面往保密页面跳转的时候利用一个dialog进行密码输入和判断。但是最后这个想法在我始终捋不清两个数据库和活动的发射之后破产,历时两天挣扎。

        思路更改:我就在edit编辑页面的menu上面设置一个保密状态转换的按钮,就是那个伞型的按钮,点一下就会将正在编辑的记录转为保密状态,在想要点开这条记录的时候就需要在弹出的dialog中输入正确的密码。

        那么我就想到在每条记录中多加入一个属性,用来判断这条记录的保密状态,于是,我定义了一个flag变量,如下面代码所示: 

package com.example.biji;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class NoteDatabase extends SQLiteOpenHelper {

    public static final String TABLE_NAME = "notes";
    public static final String CONTENT = "content";
    public static final String ID = "_id";
    public static final String TIME = "time";
    public static final String MODE = "mode";
    public static final String PATH = "path";
    public static final String FLAG = "flag";

    public NoteDatabase(Context context){
        super(context, TABLE_NAME, null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) { 
        db.execSQL("CREATE TABLE " + TABLE_NAME
                + "("
                + ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
                + CONTENT + " TEXT NOT NULL,"
                + TIME + " TEXT NOT NULL,"
                + PATH + " TEXT NOT NULL,"
                + MODE + " INTEGER DEFAULT 1,"
                + FLAG + " INTEGER NOT NULL);"
        );
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

        其实这里flag应该设置为布尔值的,但是搞成数值也不大错,,,没有默认值。

        来看看具体实现的代码:

@Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        switch (parent.getId()) {   /*第几个记录被点击,对应id,然后对应该记录*/
            case R.id.lv:
                Note curNote = (Note) parent.getItemAtPosition((position));
                if(curNote.getFlag()==0){
                    Intent intent = new Intent(MainActivity.this, EditActivity.class);
                    intent.putExtra("content", curNote.getContent());
                    intent.putExtra("id", curNote.getId());
                    intent.putExtra("time", curNote.getTime());
                    intent.putExtra("mode", 3);            /*代表已经点击过了,与EditActivity接受对应*/
                    intent.putExtra("tag", curNote.getTag());
                    intent.putExtra("path", curNote.getPath());
                    intent.putExtra("flag", 0);
                    startActivityForResult(intent, 1);     /*开始跳转*/
                }
                else if(curNote.getFlag() == 1) {
                    final EditText et = new EditText(this);
                    new AlertDialog.Builder(MainActivity.this)
                            .setMessage("这是个私密记录哦,你要查看吗,赶紧输入我们的暗号")
                            .setIcon(android.R.drawable.sym_def_app_icon)
                            .setView(et)
                            .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    if(et.getText().toString().equals(code)){
                                        Intent intent = new Intent(MainActivity.this, EditActivity.class);
                                        intent.putExtra("content", curNote.getContent());
                                        intent.putExtra("id", curNote.getId());
                                        intent.putExtra("time", curNote.getTime());
                                        intent.putExtra("mode", 3);            //代表已经点击过了,与EditActivity接受对应*/
                                        intent.putExtra("tag", curNote.getTag());
                                        intent.putExtra("path", curNote.getPath());
                                        intent.putExtra("flag",1);
                                        startActivityForResult(intent, 1);     //开始跳转
                                    }
                                    else{
                                        new AlertDialog.Builder(MainActivity.this)
                                        .setMessage("你的暗号不对呦。");
                                    }
                                }
                            }).setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {dialog.dismiss();}
                    }).create().show();
                }
                break;
        }
    }

        这里我用了onItemClick点击事件来判断点击的是第几条记录,然后获取这条记录的flag值,如果flag值为零,那么就用intent.putExtra先EditActivity传值,重要的是mode值为3,表示这次是已经创建过了的记录的再次打开,且flag仍为0,进行跳转到edit页面。

        如果这条记录已经为改变成保密状态了,那么flag==1,验证输入密码的正确性,如果正确,就进行传值与跳转,但是flag传过去的值就为1。如果密码错误,就弹出一个dialog提醒一下密码错误。

case R.id.secret:
                new AlertDialog.Builder(EditActivity.this)
                        .setMessage("每点一下会改变这条笔记的保密状态哦!")
                        .setPositiveButton(android.R.string.yes,new DialogInterface.OnClickListener(){
                            @Override
                            public void onClick(DialogInterface dialog,int which){
                                if(old_Flag == 1) {
                                    old_Flag = 0;
                                }
                                else {
                                    old_Flag = 1;
                                }
                            }
                        }).setNegativeButton(android.R.string.no,new DialogInterface.OnClickListener(){
                    @Override
                    public void onClick(DialogInterface dialog,int which){
                        dialog.dismiss();
                    }
                }).create().show();
                break;

        这一段就是在edit页面完成的一个保密状态的转换,没有太过优化,主要就是改变一下这条记录的flag值,是1就变0,是0就变1。没什么值得说的。

        加密差不多主要就是这些了,下一个。

弹出菜单

        首先在MainActivity里面声明了很多组件工具,参考了别人的代码结构。

//弹出菜单
    private PopupWindow popupWindow;
    private PopupWindow popupCover;
    private ViewGroup customView;
    private RelativeLayout main;
    private ViewGroup coverView;
    private LayoutInflater layoutInflater;
    private WindowManager wm;
    private DisplayMetrics metrics;

        然后是一大堆我看不懂的渲染代码,

//渲染
    private void initPopUpView(){
        layoutInflater=(LayoutInflater)MainActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        customView=(ViewGroup)layoutInflater.inflate(R.layout.setting_layout,null);
        coverView=(ViewGroup)layoutInflater.inflate(R.layout.setting_cover,null);
        main=findViewById(R.id.main_layout);
        wm=getWindowManager();
        metrics=new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(metrics);
    }

        这里要注意,一共是有两层layout弹出了一个customView,一个coverView,第一层就是我们需要的弹出的菜单,第二层是一个衬托第一层的蒙版。

​ customView

 

​ coverView蒙版

         再来一个经典的showPopUpView将主弹窗的宽度设置为屏幕的70%,营造弹窗的效果,让主弹窗在蒙版的上面防止蒙版遮挡,将id为setting_img和setting_text的组件设置点击事件,调用我设置的dialog方法。

    public void showPopUpView(){
        int width=metrics.widthPixels;
        int height=metrics.heightPixels;
        popupCover =new PopupWindow(coverView,width,height,false);
        popupWindow=new PopupWindow(customView,(int)(width*0.7),height,true );
        popupWindow.setBackgroundDrawable(new ColorDrawable(Color.WHITE));
                //在主界面加载成功后,显示弹出
        findViewById(R.id.main_layout).post((new Runnable() {
            @Override
            public void run() {
                popupCover.showAtLocation(main, Gravity.NO_GRAVITY,0,0);
                popupWindow.showAtLocation(main,Gravity.NO_GRAVITY,0,0);
                codeset = customView.findViewById(R.id.setting_img);
                setting_text=customView.findViewById(R.id.setting_text);
                codeset.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        dialog();
                    }
                });
                setting_text.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        dialog();
                    }
                });
                coverView.setOnTouchListener(new View.OnTouchListener(){
                    @Override
                    public boolean onTouch(View v, MotionEvent event){
                        popupWindow.dismiss();
                        return true;
                    }
                });
                popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
                    @Override
                    public void onDismiss() {
                        popupCover.dismiss();
                    }
                });
            }
        }));
    }

         这个dialog方法就是用来更改密码的,可以输入old_code和new_code,如果旧密码验证正确,那么就改变code,调用success方法来提醒修改成功,验证失败会调用fail方法提醒密码错误。

private void dialog(){
        LayoutInflater factory = LayoutInflater.from(this);
        final View textEntryView = factory.inflate(R.layout.dialog_code, null);
        final EditText old_code = (EditText) textEntryView.findViewById(R.id.old_code);
        final EditText new_code = (EditText)textEntryView.findViewById(R.id.new_code);
        AlertDialog.Builder ad1 = new AlertDialog.Builder(MainActivity.this);
        ad1.setTitle("更改密码,初始密码是0000哦");
        ad1.setIcon(android.R.drawable.ic_dialog_info);
        ad1.setView(textEntryView);
        ad1.setPositiveButton("是", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                if(old_code.getText().toString().equals(code)){
                    code=new_code.getText().toString();
                    success();
                }
                else{
                    fail();
                }
            }
        }).setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        }).create().show();
    }

 


         好了都说完了,总结一下,这个考核项目我们小组除去地理位置获取(那个授权出了问题,还在解决)一共用时5天完成要求的功能,其余时间都用来学JavaScript,,,简简单单,也都是从零开始学安卓,靠着一点Java基础,一点点吃透别人的代码,转化成自己的代码。

        完结撒花。

有关Android备忘录项目总结的更多相关文章

  1. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  2. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  3. ruby-on-rails - 新 Rails 项目 : 'bundle install' can't install rails in gemfile - 2

    我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="

  4. Ruby 从大范围中获取第 n 个项目 - 2

    假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit

  5. SPI接收数据异常问题总结 - 2

    SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手

  6. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  7. ruby - 如何在 Ruby 字符串中插入项目符号字符? - 2

    我正在尝试创建一个带有项目符号字符的Ruby1.9.3字符串。str="•"+"helloworld"但是,当我输入它时,我收到有关非ASCII字符的语法错误。我该怎么做? 最佳答案 你可以把Unicode字符放在那里。str="\u2022"+"helloworld" 关于ruby-如何在Ruby字符串中插入项目符号字符?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1195

  8. ruby - 在 Rails 项目中测试本地版本的 gem - 2

    我的Rails站点使用了一个确实不是很好的gem。每次我需要做一些新的事情时,我最终不得不花费与向实际Rails项目添加代码一样多的时间来为gem添加功能。但我不介意,我将我的Gemfile设置为指向我的gem的GitHub分支(我尝试提交PR,但维护者似乎已经下台)。问题是我真的没有找到一种合理的方法来测试我添加到gem的新东西。在railsc中测试它会特别好,但我能想到的唯一方法是a)更改~/.rvm/gems/.../foo。rb,这看起来不对或者b)升级版本,推送到Github,然后运行​​bundleup,这除了耗时之外显然是一场灾难,因为我不确定我所做的promise是否正

  9. ruby - 合并 nanoc 中的项目 - 2

    我一直在尝试使用nanoc用于生成静态网站。我需要组织一个复杂的排列页面,我想让我的内容保持干燥。包含或合并的概念在nanoc系统中如何运作?我已阅读文档,但似乎找不到我想要的内容。例如:我如何获取两个部分内容项并将它们合并到一个新的内容项中。在staticmatic您可以在您的页面中执行以下操作。=partial('partials/shared/navigation')类似的约定在nanoc中如何运作? 最佳答案 这里是nanoc的作者。在nanoc中,部分是布局。因此,您可以拥有layouts/partials/shared/

  10. Ruby 和指南针路径与 yeoman 项目 - 2

    我安装了ruby​​、yeoman,当我运行我的项目时,出现了这个错误:Warning:Running"compass:dist"(compass)taskWarning:YouneedtohaveRubyandCompassinstalledthistasktowork.Moreinfo:https://github.com/gruUse--forcetocontinue.Use--forcetocontinue.我有进入可变session目标的路径,但它不起作用。谁能帮帮我? 最佳答案 我必须运行这个:geminstallcom

随机推荐