Android实践——密码本SecretBook
16lz
2021-01-26
看了几天的东西,特别是看完数据库SQLite之后(第一行代码),想着无非还是CRUD之类的,也是该练练手了。做个什么呢,要简单一点的,实用点的,于是想好了——密码本,记录自己用到的各种账号密码。
编程语言:肯定是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 就得了。
但是如果这里要退出app我得按三次返回键啊????难受不难受!得考虑在工具栏上面加个退出app的按钮,于是做一个 ActivityCollector类来管理每次新建的Activity,这就涉及到设计模式的问题了,让每个Activity在 onCreate() 方法中将自己交给 ActivityCollector 管理,当点击退出按钮时就调用 ActivityCollector 的方法一次性来结束所有的Activity,
再就是查看全部数据了,问题又来了:怎么展示出来,又得考虑UI了,用 < ListView>, 里面就用默认的 android .R.layout. simple_list_item_1 吧,适配器就用String数组好了,将数据库中查到的每一条数据组装成我想要的格式放到数据列表中,这也算是结束了,可是问题就是这时出现的:我声明了一个全局变量 private List<String> dataList; 可是忘记初始化了,我想着尽量迟一点初始化,等到用时再初始化,可是运行时始终崩溃。这个Android Studio工具不知道怎么调试的,没显示错误的原因啊,像Eclipse中就会明明白白写出是什么问题并显示错误链抛出的栈信息,可是这AS调试就什么都让人看不懂,在这里纠结了好久,,可能是我不会用吧……但我还是觉得AS设计的不好…… (〃` 3′〃)
再考虑ListView中每个子项的点击事件吧,根据点击的位置将信息带到新增页面上去(当时就不应该叫AddActivity的,这里明显是修改的功能嘛,所以设计时就要考虑好这个类是干嘛用的,这里就看出设计的重要性了,改动的成本是很大的,幸好我只是在自己练习),可是每当我点击时总崩溃,,又一次出错了不会调试……真难受啊……都不知道从哪里抛出了什么错误……哎╮(╯▽╰)╭慢慢试,,发现点击新增页面时也会崩溃,那么就是AddActivity有问题了,可是找了好久还是不知道怎么回事,google……也没找到怎么回事, 于是没办法了,最傻的方法来吧,一点点的改回去,边改边测试,看看是什么问题,我退啊退,,终于发现了问题所在,我将全局变量初始化时出的问题,如下:
于是改成了在onCreate()方法中再初始化dbHelper,这样就可以了,但是问题是永远不会结束的,永远解决不完的……接着出现的问题是intent带过来的数据问题,后来弄清楚了若某intent没有携带相应的数据,则获取到的是null,最后onCreate方法如下:
数据库也出了问题,创建时没考虑删除的问题,后来想到删除时,就直接将数据给删除了,这是不好的,于是设置了一个deleteFlag删除标记,0就是正常的,1就是删除了的,本来只需要一位做标记就可以了的,可是查资料,SQLite中没有bit或者Boolean类的数据,于是选择了integer,但是数据库改变了,版本升级的问题也出现了,最后照着作者给的方案解决了。
本以为是一个小实践,可是前前后后也出了好多问题。也算是学到了好多吧!这次是将前前后后各章的内容都结合起来用到了一遍!还有很多问题遗留,以待解决
所以说读万卷书不如行万里路啊~实践才是检验真理的唯一标准~纸上得来终觉浅~……
这几天又看了点《代码大全2》,想着这东西要运用一下啊,于是结合作者软件构建的思维加Android的技术来练练手呗~虽然说系统有大有小,大系统大架构大考虑,小系统不需考虑那么多。
开发过程中遇到了各种问题,看书时觉得挺简单的东西,写起来就会出各种bug,开发工具又不是太会用,解决个问题要费老大的劲啊,真是抓狂!做完了现在记录下下~有的问题解决了,有的问题还是不知道怎么回事……(′д` )…彡…彡
按照软件开发过程,开始前的准备工作三部曲:问题定义、需求分析、软件架构。
一、问题定义
从客户的角度来看问题,用客户的语言来描述问题:开发一个个人密码管理工具
二、需求分析
通过口令(密码)进入密码本;
可以新增账号,保存到数据库;
可以查看全部账号密码信息,全部展示出来,就在一个页面,类似记事本;
可以修改账号信息,CRUD(增删改查);
安全:暂时不做要求
三、系统架构
- 程序组织:密码本是用来管理账户密码的(这就是概述) 构造快:界面、数据库操作、业务逻辑……只能想到这三个~(@[email protected];) 通信规则:Activity调用xml显示界面,调用DB类操作数据库;外部通信:暂时作为本地服务,不与其他应用交互
- 主要类:MainActivity:登录界面;ChooseOperationActivity:操作选择;AddActivity:新增;DisplayAllActivity:查看全部信息;MyDataBaseHelper:数据库操作
- 数据库设计:一张表:secretbook;字段:id、site、account、password、note
- 界面设计:见需求分析,Login——》Select——》Edit——》ViewAll
- 安全性:暂时不考虑安全性能,因为对SQLite数据库不了解,对Android系统管理文件的情况也不清楚,也不知道加密规则
- 可扩展性:要考虑以后会增加到多张表,增加新功能
- 可行性:100%,完全是个人实践之作,项目很小,就不多花时间准备了,第一次做,肯定会遇到问题,那就边做边解决问题吧
- ……不多说了,动手吧!<( ̄︶ ̄)>
编程语言:肯定是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……也没找到怎么回事, 于是没办法了,最傻的方法来吧,一点点的改回去,边改边测试,看看是什么问题,我退啊退,,终于发现了问题所在,我将全局变量初始化时出的问题,如下:
我还是不知道为什么,我想可能是startActivity(intent)出的问题吧,也可能是类加载的机制问题,看来我又忘了Java类加载的机制问题了吧~要找时间将没看完的《Thinking in Java》再好好学学了,,当时还明明白白的,现在好久没弄就忘了,,,,衰( ⊙ o ⊙ )啊!private MyDataBaseHelper dbHelper=new MyDataBaseHelper(AddActivity.this, DATABASE_NAME, null, 2);private SQLiteDatabase db= dbHelper.getWritableDatabase();
于是改成了在onCreate()方法中再初始化dbHelper,这样就可以了,但是问题是永远不会结束的,永远解决不完的……接着出现的问题是intent带过来的数据问题,后来弄清楚了若某intent没有携带相应的数据,则获取到的是null,最后onCreate方法如下:
肯定是不好的,但是目前我也只能写成这样了,以后再慢慢优化吧!@Overrideprotected 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,但是数据库改变了,版本升级的问题也出现了,最后照着作者给的方案解决了。
本以为是一个小实践,可是前前后后也出了好多问题。也算是学到了好多吧!这次是将前前后后各章的内容都结合起来用到了一遍!还有很多问题遗留,以待解决
所以说读万卷书不如行万里路啊~实践才是检验真理的唯一标准~纸上得来终觉浅~……
更多相关文章
- 一句话锁定MySQL数据占用元凶
- android上传图片并附带上传数据,文件流
- [置顶] Android即时通信软件设计(一)(网络通信)
- Serializable 都这么牛逼了,Parcelable 还要你何用?
- 对Android中的Cursor一些浅显见解
- 视频日志之android的总结与思考
- Android应用开发笔记(4):再探Android多应用间数据共享机制,自定义C
- Android(安卓)onUpdate
- android 用SharedPreferences作为数据存储