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


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


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


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


一、问题定义

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


二、需求分析

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

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

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

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

安全:暂时不做要求


三、系统架构

  1. 程序组织:密码本是用来管理账户密码的(这就是概述) 构造快:界面、数据库操作、业务逻辑……只能想到这三个~(@[email protected];) 通信规则: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方法如下:
@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,但是数据库改变了,版本升级的问题也出现了,最后照着作者给的方案解决了。

本以为是一个小实践,可是前前后后也出了好多问题。也算是学到了好多吧!这次是将前前后后各章的内容都结合起来用到了一遍!还有很多问题遗留,以待解决
所以说读万卷书不如行万里路啊~实践才是检验真理的唯一标准~纸上得来终觉浅~……

更多相关文章

  1. 一句话锁定MySQL数据占用元凶
  2. android上传图片并附带上传数据,文件流
  3. [置顶] Android即时通信软件设计(一)(网络通信)
  4. Serializable 都这么牛逼了,Parcelable 还要你何用?
  5. 对Android中的Cursor一些浅显见解
  6. 视频日志之android的总结与思考
  7. Android应用开发笔记(4):再探Android多应用间数据共享机制,自定义C
  8. Android(安卓)onUpdate
  9. android 用SharedPreferences作为数据存储

随机推荐

  1. android 经纬度 double类型 转换成 度分
  2. android之短信发不出去,短信空指针,smsMana
  3. Android SmartRefreshLayout的使用
  4. Android 状态栏背景颜色修改与状态栏字体
  5. AndroidStudio导入ViewPagerIndicator以
  6. 【Android】简单理解View的绘制流程
  7. Android 自定义SurfaceView实现加载GIF动
  8. Unity打包报错Ignoring InnerClasses att
  9. Android[中级教程]第七章 XML解析之Dom解
  10. Android监听事件