Android实践——密码本SecretBook

看了几天的东西,特别是看完数据库SQLite之后(第一行代码),想着无非还是CRUD之类的,也是该练练手了。做个什么呢,要简单一点的,实用点的,于是想好了——密码本,记录自己用到的各种账号密码。


这几天又看了点《代码大全2》,想着这东西要运用一下啊,于是结合作者软件构建的思维加Android的技术来练练手呗~虽然说系统有大有小,大系统大架构大考虑,小系统不需考虑那么多。


开发过程中遇到了各种问题,看书时觉得挺简单的东西,写起来就会出各种bug,开发工具又不是太会用,解决个问题要费老大的劲啊,真是抓狂!做完了现在记录下下~有的问题解决了,有的问题还是不知道怎么回事……(′д` )…彡…彡


按照软件开发过程,开始前的准备工作三部曲:问题定义、需求分析、软件架构。


Android实践——密码本SecretBook - hh-csq - HA HA

 

Android实践——密码本SecretBook - hh-csq - HA HA

 

一、问题定义

从客户的角度来看问题,用客户的语言来描述问题:开发一个个人密码管理工具


二、需求分析

通过口令(密码)进入密码本;

可以新增账号,保存到数据库;

可以查看全部账号密码信息,全部展示出来,就在一个页面,类似记事本;

可以修改账号信息,CRUD(增删改查);

安全:暂时不做要求


三、系统架构

  1. 程序组织:密码本是用来管理账户密码的(这就是概述)         构造快:界面、数据库操作、业务逻辑……只能想到这三个~(@_@;)             通信规则:Activity调用xml显示界面,调用DB类操作数据库;外部通信:暂时作为本地服务,不与其他应用交互
  2. 主要类:MainActivity:登录界面;ChooseOperationActivity:操作选择;AddActivity:新增;DisplayAllActivity:查看全部信息;MyDataBaseHelper:数据库操作
  3. 数据库设计:一张表:secretbook;字段:id、site、account、password、note
  4. 界面设计:见需求分析,Login——》Select——》Edit——》ViewAll
  5. 安全性:暂时不考虑安全性能,因为对SQLite数据库不了解,对Android系统管理文件的情况也不清楚,也不知道加密规则
  6. 可扩展性:要考虑以后会增加到多张表,增加新功能
  7. 可行性:100%,完全是个人实践之作,项目很小,就不多花时间准备了,第一次做,肯定会遇到问题,那就边做边解决问题吧
  8. ……不多说了,动手吧!<( ̄︶ ̄)>

编程语言:肯定是Java啊,Android的界面是用xml写

下面问题出现了:
首先考虑登录界面activity_main.xml:Android中有四种布局LinearLayout(线性布局)、RelativeLayout(相对布局)、FrameLayout(帧布局)、TableLayout(表格布局),到底用哪种呢?纠结了……一个输入框、一个登录按钮而已,我想把他们一起放在屏幕中间位置,那用RelativeLayout是最方便的呢,因为他可以用 android :layout_alignParentTop= "true" 在子控件里, 这个属性让本控件相对父级控件水平垂直方向上都居中,外面用 < RelativeLayout > 里面用一个 < TableLayout >就可以了,我刚开始把 android :layout_width和 android :layout_height 设置成了 "match_parent", 在手机上显示时密码输入框和按钮就位于最左上角,且占了整个屏幕宽度,不好看,于是改成了 "wrap_content" ,才显示在了屏幕中间位置,可是在我输入时,由于输入法的高度挡住了按钮,于是又将TableLayout往上拖了一点,这就是所谓的用户体验了吧,要时时刻刻考虑使用上的方便性,

登录时的密码问题我写死在了程序里面,由于没有设置对应的数据库来管理,暂时就这样吧……

然后是操作选择界面 < LinearLayout> 里面嵌 < LinearLayout> 吧。暂时还好,没出问题,可是按返回键时,密码还留在上一个Activity的输入框里,这是不对滴~我也不知道怎么做好,只有让它在通过密码验证之后清除数据了: editText .setText( "" );但是这样写效果很不好,会有个明显的清除过程后才会跳转,让人不舒服,可是我目前也不知道怎么办,就先这样吧……

接着新增数据,可以,操作数据库 MyDataBaseHelper 就得了。
package com.thsware.secretbook;

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

/**
 * Created by 世祥 on 2015/9/4.
 */
public class MyDataBaseHelper extends SQLiteOpenHelper {

    private static final String CREATE_SECRETBOOK="create table secretbook("
            +"id integer primary key autoincrement,"
            +"site text,"
            +"account text,"
            +"password text,"
            +"note text,"
            +"deleteFlag integer"
            +")";

    private Context mContext;

    public MyDataBaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        mContext=context;
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL(CREATE_SECRETBOOK);
        Toast.makeText(mContext,"secretbook数据表创建成功~",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
        switch (oldVersion){
            case 1:
                sqLiteDatabase.execSQL("alter table secretbook add column deleteFlag integer");
            default:
        }
    }
}


但是如果这里要退出app我得按三次返回键啊????难受不难受!得考虑在工具栏上面加个退出app的按钮,于是做一个 ActivityCollector类来管理每次新建的Activity,这就涉及到设计模式的问题了,让每个Activity在 onCreate() 方法中将自己交给 ActivityCollector 管理,当点击退出按钮时就调用 ActivityCollector 的方法一次性来结束所有的Activity,
package com.thsware.secretbook;

import android.app.Activity;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by 世祥 on 2015/9/4.
 */
public class ActivityCollector {

    private static List<Activity> activities=new ArrayList<Activity>();

    public static void addActivity(Activity activity){
        activities.add(activity);
    }

    public static void removeActivity(Activity activity){
        activities.remove(activity);
    }

    public static void finishAll(){
        for (Activity ac : activities){
            if (!ac.isFinishing()){
                ac.finish();
            }
        }
    }
}

再就是查看全部数据了,问题又来了:怎么展示出来,又得考虑UI了,用 < ListView>, 里面就用默认的 android .R.layout. simple_list_item_1 吧,适配器就用String数组好了,将数据库中查到的每一条数据组装成我想要的格式放到数据列表中,这也算是结束了,可是问题就是这时出现的:我声明了一个全局变量 private  List<String> dataList; 可是忘记初始化了,我想着尽量迟一点初始化,等到用时再初始化,可是运行时始终崩溃。这个Android Studio工具不知道怎么调试的,没显示错误的原因啊,像Eclipse中就会明明白白写出是什么问题并显示错误链抛出的栈信息,可是这AS调试就什么都让人看不懂,在这里纠结了好久,,可能是我不会用吧……但我还是觉得AS设计的不好…… (〃` 3′〃)

再考虑ListView中每个子项的点击事件吧,根据点击的位置将信息带到新增页面上去(当时就不应该叫AddActivity的,这里明显是修改的功能嘛,所以设计时就要考虑好这个类是干嘛用的,这里就看出设计的重要性了,改动的成本是很大的,幸好我只是在自己练习),可是每当我点击时总崩溃,,又一次出错了不会调试……真难受啊……都不知道从哪里抛出了什么错误……哎╮(╯▽╰)╭慢慢试,,发现点击新增页面时也会崩溃,那么就是AddActivity有问题了,可是找了好久还是不知道怎么回事,google……也没找到怎么回事, 于是没办法了,最傻的方法来吧,一点点的改回去,边改边测试,看看是什么问题,我退啊退,,终于发现了问题所在,我将全局变量初始化时出的问题,如下:
private MyDataBaseHelper dbHelper=new MyDataBaseHelper(AddActivity.this, DATABASE_NAME, null, 2);
private SQLiteDatabase db= dbHelper.getWritableDatabase();
我还是不知道为什么,我想可能是startActivity(intent)出的问题吧,也可能是类加载的机制问题,看来我又忘了Java类加载的机制问题了吧~要找时间将没看完的《Thinking in Java》再好好学学了,,当时还明明白白的,现在好久没弄就忘了,,,,衰( ⊙ o ⊙ )啊!

于是改成了在onCreate()方法中再初始化dbHelper,这样就可以了,但是问题是永远不会结束的,永远解决不完的……接着出现的问题是intent带过来的数据问题,后来弄清楚了若某intent没有携带相应的数据,则获取到的是null,最后onCreate方法如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_add);
    ActivityCollector.addActivity(this);

    siteEdit= (EditText) findViewById(R.id.site);
    accountEdit= (EditText) findViewById(R.id.account);
    passwordEdit= (EditText) findViewById(R.id.password);
    noteEdit= (EditText) findViewById(R.id.note);
    saveButton= (Button) findViewById(R.id.save_button);
    dbHelper=new MyDataBaseHelper(AddActivity.this, DATABASE_NAME, null, 2);
    db = dbHelper.getWritableDatabase();

    Intent intent=getIntent();
    //未检测intent是否为空,此处id无数据时为null
    id=intent.getStringExtra("id");
    if (id!=null && !id.equals("")){
        Cursor cursor=db.query(SECRETBOOK_TABLE, null, "id=?", new String[]{id}, null, null, null);
        if (cursor.moveToFirst()){
            String site=cursor.getString(cursor.getColumnIndex("site"));
            String account=cursor.getString(cursor.getColumnIndex("account"));
            String password=cursor.getString(cursor.getColumnIndex("password"));
            String note=cursor.getString(cursor.getColumnIndex("note"));

            siteEdit.setText(site);
            accountEdit.setText(account);
            passwordEdit.setText(password);
            noteEdit.setText(note);
        }
    }

    //保存数据
    saveButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            String site = siteEdit.getText().toString().trim();
            if (site.equals("")) {
                Toast.makeText(AddActivity.this, R.string.sitename + "必须填写", Toast.LENGTH_SHORT).show();
                return;
            }
            ContentValues values = new ContentValues();
            values.put("site", site);
            values.put("account", accountEdit.getText().toString());
            values.put("password", passwordEdit.getText().toString());
            values.put("note", noteEdit.getText().toString());

            //如果id为空,则是新增数据
            if (id==null || id.equals("")){
                values.put("deleteFlag", 0);
                db.insert(SECRETBOOK_TABLE, null, values);
            }else{
                db.update(SECRETBOOK_TABLE,values,"id=?",new String[]{id});
            }

            //未做判断,就提示成功了
            Toast.makeText(AddActivity.this, "保存成功!", Toast.LENGTH_SHORT).show();
        }
    });
}
肯定是不好的,但是目前我也只能写成这样了,以后再慢慢优化吧!

数据库也出了问题,创建时没考虑删除的问题,后来想到删除时,就直接将数据给删除了,这是不好的,于是设置了一个deleteFlag删除标记,0就是正常的,1就是删除了的,本来只需要一位做标记就可以了的,可是查资料,SQLite中没有bit或者Boolean类的数据,于是选择了integer,但是数据库改变了,版本升级的问题也出现了,最后照着作者给的方案解决了。


本以为是一个小实践,可是前前后后也出了好多问题。也算是学到了好多吧!这次是将前前后后各章的内容都结合起来用到了一遍!还有很多问题遗留,以待解决

所以说读万卷书不如行万里路啊~实践才是检验真理的唯一标准~纸上得来终觉浅~……

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
1.点击该日志app后,进入欢迎activity中,然后欢迎activity调用欢迎页面并显示该页面,欢迎页面设计为2000ms自动消失,跳转到登录功能中。 2.由欢迎页面自动跳转到登录activity中,登录activity调动login页面,并展示该页面,如果有账号可以直接登录,没账号需要先注册,登陆的时候做了后端的验证,在登录activite中进行验证,包括密码账号是否为空,密码账号是否与数据库中存的一致等,点击登录可以进入到主页面,同时会在屏幕下方显示登陆成功字样。登录界面还有一个记录密码功能,可以在下次登录的时候不用输入账号密码,直接点击登录即可。3.登录界面上点击注册,跳转到注册activity中,注册页面一共包含三个输入框,手机号,密码,确认密码,如果注册的时候没有输入手机号,或者密码都会显示密码账号不能为空,注册失败字样,如果注册的时候密码和确认密码不一致也会注册失败,并提示两次输入密码不一致,注册的时候手机后不够十一位,或者输入的手机号与数据库中有一样的手机号,则显示该账号已经被注册,提示注册失败。如果上述要求都符合,注册的信息通过对数据库进行操作,把信息存到数据库中,然后跳转到登录界面。 4.登陆成功后进入到主界面mainactivity,主界面调用mainActivity.layout,主界面包含元素,功能栏按钮,增加文字日志,增加视频日志,以及显示已经存在的日志,首先主界面显示的已经存在的日志是通过cell.xml格式来罗列的,每一条日志信息都存在数据库中,可以点击日志信息然后对其进行增删改查。主界面中增加文字日志与增加视频日志点击后进入对应界面,然后添加对应的日志信息到数据库中。主界面中的功能栏按钮在左上方,点击可以在左边出现一个显示框,显示框中含有各种功能,包括修改密码,注销,退出等信息。 5.点击增加文字日志或者视频日志,进入到增加页面,文字可以直接通过layout页面直接写,然后接收到activity中,之后存到数据库中并在主页面进行展示,增加视频的话采取流方式,把视频转换为字节流,然后存入到数据库中,(增加视频也可以采取存入链接地址,通过链接地址直接查看)。增加完日志信息可以直接点击保存,保存按钮触发事件,存数据到数据库中。 6.在主界面中点击对应的日志,可以进入到日志中进行基本的查看,和删除操作,点击删除按钮,通过日志信息查找库中对应的日志信息,并对其进行删除。主页面中不再有该日志信息,实时删除,实时显示。 7.点击修改密码按钮,转入到修改密码activity中,修改密码界面主要有两个输入框,包括输入旧密码,输入新密码,当输入的旧密码不对,会显示修改失败并提示修改旧密码不对,如果旧密码或者新密码为空,则提示信息密码不能为空,如果新密码与旧密码一致,那么也会显示修改密码失败,直到信息符合,显示修改密码成功,并更新数据库中对应的手机号的密码。 8.点击注销,返回到登录界面,可以重修输入不同的账号信息,然后登陆,也可以重新注册账号登录。 9.点击退出,程序直接中断,然后退出app到手机主界面。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值