国内最全IT社区平台 联系我们 | 收藏本站
华晨云阿里云优惠2
您当前位置:首页 > php开源 > 综合技术 > [置顶] 生活管家app

[置顶] 生活管家app

来源:程序员人生   发布时间:2016-06-08 13:47:38 阅读次数:2351次

这篇文章给大家带来的是1款android的生活管家app实现。
主要实现功能及其要求:
1、个人收入支出的管理。主要完成收入管理、支出管理、种别管理、收入查询、支出查询、统计信息等功能。
2、实现每次进入利用需要进行密码输入,增强安全性。
3、其他功能可根据个人自己的想法添加。
4、系统界面美观,操作方便。
好了,根据这样的要求,您会想到开发1个怎样的app呢?快发挥您的想象能力和动手能力吧!
接下来,来看看博主的实现,先来看看实现的效果展现吧。。。
进入主界面密码主界面类别管理收入查询收入管理查询结果用户信息用户信息修改
应当还可以吧,不算太丑。其中的统计和辅助工具就没有实现了,太耽误时间了,如果读者有兴趣,可自行完成。

项目源码下载地址:`点击下载地址
**作者:**IT_faquir
博客地址:http://blog.csdn.net/IT_faquir/article/details/51534408
重点内容
java代码块和布局文件目录结构:
java代码块文件 布局文件
重点来了,那就是实现它。来随着博主1起来看看是怎样实现的吧。(只讲授1些重点部份)。
主函数,作为程序的入口,直接上代码:

public class MainActivity extends Activity { private SharedPreferences sp; private DatabaseUtils dbUtils; MyDialog mDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sp = getSharedPreferences("firstInit", Context.MODE_PRIVATE); getActionBar().hide(); mDialog = new MyDialog(this); initDatabase(); } //作为第1次使用,将会初始化数据库 private void initDatabase() { // Boolean isFirst = sp.getBoolean("isFirst", true);// 用于得到是不是为第1次使用此程序 if (sp.getBoolean("isFirst", true)) {// 第1次使用初始化数据库 String sql1 = "create table userInfo(id INTEGER PRIMARY KEY,name,age,phone,birth,address,password)"; String sql2 = "create table income(id INTEGER PRIMARY KEY,date,type,money MONEY,remark)"; String sql3 = "create table outlay(id INTEGER PRIMARY KEY,date,type,money MONEY,remark)"; String sql4 = "create table incomeType(id INTEGER PRIMARY KEY,type)"; String sql5 = "create table outlayType(id INTEGER PRIMARY KEY,type)"; dbUtils = new DatabaseUtils(this); dbUtils.openDatabase(); dbUtils.create(sql1); dbUtils.create(sql2); dbUtils.create(sql3); dbUtils.create(sql4); dbUtils.create(sql5); dbUtils.insert("insert into userInfo(id) values(1)"); dbUtils.insert("insert into incomeType(type) values('工资')"); dbUtils.insert("insert into incomeType(type) values('股票')"); dbUtils.insert("insert into outlayType(type) values('消费')"); dbUtils.closeDB(); sp.edit().putBoolean("isFirst", false).commit(); mDialog.showSetPswDialog(); } else { mDialog.showLoginDialog(null).setCancelable(false); dbUtils = new DatabaseUtils(this); dbUtils.openDatabase(); Cursor curson1 = dbUtils.query("select type from incomeType"); String[] s1 = new String[curson1.getCount()]; int count1 = 0; while (curson1.moveToNext()) { s1[count1] = curson1.getString(0); count1++; } curson1.close(); LifeButlerUtils.incomeType = s1; Cursor curson2 = dbUtils.query("select type from outlayType"); String[] s2 = new String[curson2.getCount()]; int count2 = 0; while (curson2.moveToNext()) { String s = curson2.getString(0); System.out.println("xiao:" + s); s2[count2] = s; count2++; } curson2.close(); dbUtils.closeDB(); LifeButlerUtils.outlayType = s2; } } public void incomeManagement(View v) { startActivity(MainActivity.this, IncomeManActivity.class); } public void outlayManagement(View v) { startActivity(MainActivity.this, OutlayManActivity.class); } //其他的按钮启动界面就不在重复展现了。 ... public void exitSys(View v) { this.finish(); System.exit(0); } //封装下启动界面的1个方法,以简化代码 private void startActivity(Context context, Class c) { Intent intent = new Intent(context, c); startActivity(intent); } }

从主函数中可以看出,此程序用到了sqlite本地数据库。同时SharedPreference也在程序中得到应用,用于寄存1些简单的本地数据,作为是不是为第1次使用利用程序的根据。还有就是启动activity方法的奇妙封装,这样可以大大减少代码量。
从代码中同时看到的,楼主用到了1个关于数据的操作的1个工具类DatabaseUtils。
看看DatabaseUtils这工具类的代码:

public class DatabaseUtils { public static final String DBNAME = "mydb.db"; private Context context; private SQLiteDatabase db; public DatabaseUtils(Context context) { this.context = context; } public void openDatabase() { db = context.openOrCreateDatabase(DBNAME, context.MODE_PRIVATE, null); } public void create(String sql) { db.beginTransaction(); db.execSQL(sql); db.setTransactionSuccessful(); db.endTransaction(); } public void insert(String sql) { db.beginTransaction(); db.execSQL(sql); db.setTransactionSuccessful(); db.endTransaction(); } //修改很删除也类似进行封装。 ... public Cursor query(String sql) { db.beginTransaction(); Cursor cursor = db.rawQuery(sql, null); db.setTransactionSuccessful(); db.endTransaction(); return cursor; } // 判断数据表是不是存在 public boolean isExsit(String tableName) { boolean result = false; if (tableName == null) { return false; } Cursor cursor = null; try { String sql = "select count(*) as c from sqlite_master where type ='table' and name ='" + tableName.trim() + "' "; cursor = db.rawQuery(sql, null); if (cursor.moveToNext()) { int count = cursor.getInt(0); if (count > 0) { result = true; } } } catch (Exception e) { e.printStackTrace(); } return result; } //要记得使用完数据库要关闭它。 public void closeDB() { db.close(); } }

这个数据库工具类很简单,就是对1些增删改查操作的封装。主要传入sql语句进行履行。因此需要读者,有1点的sql语句基础。
再回到主类,会发现有个Dialog,用于进入利用时输入密码使用。
我们来看看吧:
MyDialog实现:

public Dialog showLoginDialog(final Intent intent) { View li = LayoutInflater.from(context).inflate(R.layout.dialog_layout, null); final Dialog dialog = new AlertDialog.Builder(context).create(); // dialog.setTitle("给自己起个名字吧!"); dialog.show(); dialog.getWindow().setContentView(li); // dialog.setCancelable(false);// 是对话框不能按返回键取消 dialog.setCanceledOnTouchOutside(false);// 使对话框不能按旁边取消 dialog.getWindow().clearFlags( WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); et = (EditText) li.findViewById(R.id.login_psw); li.findViewById(R.id.dialog_bn_ok).setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { String psw = null; String myPsw = et.getText().toString().trim(); dbUtils.openDatabase(); Cursor c = dbUtils .query("select password from userInfo where id = 1"); while (c.moveToNext()) { psw = c.getString(0).trim(); } dbUtils.closeDB(); if (!psw.equals(myPsw)) { Toast.makeText(context, "密码毛病", 500).show(); } else { if (intent != null) { context.startActivity(intent); } else { dialog.cancel(); } } } }); return dialog; }

对话框的实现,是否是和我们再那些书上看到的对话框不1样能,这里楼主用到了自定义对话框,对对话框布局进行填充。

LayoutInflater.from(context).inflate(R.layout.dialog_layout,null); dialog.getWindow().setContentView(li);

这样实现出来的效果既美观,又可以更好的自我把控。
看到效果图就知道;
InComeManActivity:
用于收入管理类用于输入的录入

public class IncomeManActivity extends BaseActivity { private EditText et_date, et_money, et_remark; private Spinner sp_source; private boolean haveDate = false; private DatabaseUtils dbUtils; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.incomeman_layout); dbUtils = new DatabaseUtils(this); init(); } private void init() { et_date = (EditText) findViewById(R.id.income_date); sp_source = (Spinner) findViewById(R.id.income_source); et_money = (EditText) findViewById(R.id.income_money); et_remark = (EditText) findViewById(R.id.income_remark); dbUtils.openDatabase(); Cursor c = dbUtils.query("select type from incomeType"); String types[] = new String[c.getCount()]; int count = 0; while(c.moveToNext()){ types[count] = c.getString(0); count++; } dbUtils.closeDB(); LifeButlerUtils.incomeType = types; ArrayAdapter<String> aAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, types); sp_source.setAdapter(aAdapter); et_date.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { showDialog(); } }); } public void hand(View v) { String date = et_date.getText().toString().trim(); String type = sp_source.getSelectedItem().toString(); String money = et_money.getText().toString().trim(); String remark = et_remark.getText().toString().trim(); if (chackContent(money, remark) && haveDate) { System.out.println(date + type + money + remark); dbUtils.openDatabase(); dbUtils.insert("insert into income(date,type,money,remark) values('" + date + "','" + type + "','" + money + "','" + remark + "')"); dbUtils.closeDB(); toast("添加成功。"); } else { toast("请填写完全信息!"); } } public void back(View v) { this.finish(); } private boolean chackContent(String money, String remark) { if (money.length() > 0 && remark.length() > 0) return true; return false; } private void showDialog() { Dialog dialog = null; Calendar c = Calendar.getInstance(); dialog = new DatePickerDialog(this, new DatePickerDialog.OnDateSetListener() { public void onDateSet(DatePicker dp, int year, int month, int dayOfMonth) { haveDate = true; String mon = String.valueOf(month+1); if(mon.length() == 1){ mon = "0"+mon; } String day = String.valueOf(dayOfMonth); if(day.length() == 1){ day = "0"+day; } et_date.setText(year + "-" + mon + "-" + day); } }, c.get(Calendar.YEAR), // 传入年份 c.get(Calendar.MONTH), // 传入月份 c.get(Calendar.DAY_OF_MONTH) // 传入天数 ); dialog.show(); } }

工作流程:在界面录入信息后,点击按键保存,检查所填的信息是不是完全,如果完全则保存信息到本地的sqlite数据库,否则不保存。我想,您看完代码应当就懂了。
还有个是支出的录入,基本上和这的实现,没甚么区分,主要就是sql语句有所变化,就不在继续贴出了。
查询的实现:
再来看看查询吧,这里以收入的查询为例:
或许难度就在于那些勾选查询,如何才能很好的实现,代码量少,又灵活的代码呢?如果有几10个勾选的条件,那代码量想一想便可怕。因此楼主做了1些奇妙的处理:

public class IncomeQueryActivity extends BaseActivity { private EditText et_dateS, et_dateE, et_moneyMin, et_moneyMax; private Spinner sp_source; private CheckBox check_type, check_date, check_money; private DatabaseUtils dbUtils; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.incomequery_layout); dbUtils = new DatabaseUtils(this); init(); } private void init() { check_type = (CheckBox) findViewById(R.id.check_income_source); check_date = (CheckBox) findViewById(R.id.check_income_date); check_money = (CheckBox) findViewById(R.id.check_income_money); sp_source = (Spinner) findViewById(R.id.income_query_source); et_dateS = (EditText) findViewById(R.id.income_query_time1); et_dateE = (EditText) findViewById(R.id.income_query_time2); et_moneyMin = (EditText) findViewById(R.id.income_query_money1); et_moneyMax = (EditText) findViewById(R.id.income_query_money2); et_dateS.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { showDialog(et_dateS); } }); et_dateE.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { showDialog(et_dateE); } }); ArrayAdapter<String> aAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, LifeButlerUtils.incomeType); sp_source.setAdapter(aAdapter); } public void query(View v) { Map<String, Boolean> map = new HashMap<String, Boolean>(); boolean have_type = check_type.isChecked(); boolean have_date = check_date.isChecked(); boolean have_money = check_money.isChecked(); map.put("type", have_type); map.put("date", have_date); map.put("money", have_money); String source = sp_source.getSelectedItem().toString(); String date1 = et_dateS.getText().toString().trim(); String date2 = et_dateE.getText().toString().trim(); String money1 = et_moneyMin.getText().toString().trim(); String money2 = et_moneyMax.getText().toString().trim(); StringBuilder sb = new StringBuilder(); boolean isFirst = true;// 是不是为第1个where boolean haveWhere = false;// 处理是不是有where 语句 boolean isOk = true;// 处理是不是信息完全性 if (have_type == true) { sb.append("type = '" + source + "'"); isFirst = false; haveWhere = true; } if (have_date == true) { if (date1.length() > 0 && date2.length() > 0) { if (!isFirst) { sb.append(" and "); } sb.append("date >= '" + date1 + "'and date <= '" + date2 + "'"); } else { toast("请选择日期。"); isOk = false; } haveWhere = true; } if (have_money == true) { if (!isFirst) { sb.append(" and "); } sb.append("money >= '" + money1 + "' and date <= '" + money2 + "'"); haveWhere = true; } // 处理结果 if (isOk) { String sql = null; if (haveWhere) sql = "select * from income where " + sb.toString().trim(); else sql = "select * from income"; dbUtils.openDatabase(); Cursor c = dbUtils.query(sql); int cCount = c.getColumnCount(); StringBuilder data = new StringBuilder(); while (c.moveToNext()) { for (int i = 0; i < cCount; i++) { data.append(c.getString(i).trim() + " "); } data.append("\n"); } dbUtils.closeDB(); Intent intent = new Intent(IncomeQueryActivity.this, QueryResultActivity.class); intent.putExtra("data", data.toString()); intent.putExtra("operate", "income"); startActivity(intent); System.out.println(sql); } } public void back(View v) { this.finish(); } private void showDialog(final EditText et) { //日期对话框,和上相同 } }

由因而进行sql语句查询因此,需要生成1条满足条件的sql语句,有没找到那代码:

if (have_type == true) { sb.append("type = '" + source + "'"); isFirst = false; haveWhere = true; } if (have_date == true) { if (date1.length() > 0 && date2.length() > 0) { if (!isFirst) { sb.append(" and "); } sb.append("date >= '" + date1 + "'and date <= '" + date2 + "'"); } else { toast("请选择日期。"); isOk = false; } haveWhere = true; } if (have_money == true) { if (!isFirst) { sb.append(" and "); } sb.append("money >= '" + money1 + "' and date <= '" + money2 + "'"); haveWhere = true; }

没错就是块代码,if语句配合StringBuilder,实现了sql语句的动态生成。
outlay的查询与此类似,不在叙述。
因此楼主总结出了1句话:我们要灵活的应对每件事,这样能有时能到达事半功倍的效果。
再来看看种别的管理
在对种别管理的实现中,楼主用到了ViewPager+ListView和PopMenu

public class CategoryActivity extends BaseActivity implements OnCheckedChangeListener, OnPageChangeListener { private ViewPager viewPager; private ArrayList<View> listView; private DatabaseUtils dbUtils; private ArrayAdapter<String> mAdapter1; private ArrayAdapter<String> mAdapter2; private RadioGroup radioGroup; private RadioButton rb1; private RadioButton rb2; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.category_layout); getActionBar().hide(); dbUtils = new DatabaseUtils(this); init(); } private void init() { dbUtils.openDatabase(); radioGroup = (RadioGroup) findViewById(R.id.novelty_rg); radioGroup.setOnCheckedChangeListener(this); rb1 = (RadioButton) findViewById(R.id.rb_income); rb2 = (RadioButton) findViewById(R.id.rb_outlay);; viewPager = (ViewPager) findViewById(R.id.cate_viewPager); viewPager.setOnPageChangeListener(this); listView = new ArrayList<View>(); View v1 = getLayoutInflater().inflate(R.layout.cate_tab_01, null); View v2 = getLayoutInflater().inflate(R.layout.cate_tab_02, null); initV1(v1); initV2(v2); listView.add(v1); listView.add(v2); viewPager.setCurrentItem(0); viewPager.setAdapter(new MyPagerAdapter()); } private void initV1(View v1) { final String type = "incomeType"; ListView list = (ListView) v1.findViewById(R.id.cate_list1); Button bn = (Button) v1.findViewById(R.id.addOne); final List<String> types = new ArrayList<String>(); Cursor c1 = dbUtils.query("select type from incomeType"); while (c1.moveToNext()) { String t = c1.getString(0); types.add(t); } mAdapter1 = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, types); list.setAdapter(mAdapter1); list.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { myPopMenu(view, types, "incomeType", position); return true; } }); bn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { new MyDialog(CategoryActivity.this).showAddDialog(type, types, handler); } }); } private void initV2(View v2) { final String type = "outlayType"; ListView list = (ListView) v2.findViewById(R.id.cate_list2); Button bn = (Button) v2.findViewById(R.id.addOne); final List<String> types = new ArrayList<String>(); Cursor c1 = dbUtils.query("select type from outlayType"); while (c1.moveToNext()) { String t = c1.getString(0); types.add(t); } mAdapter2 = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, types); list.setAdapter(mAdapter2); list.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { myPopMenu(view, types, "outlayType", position); return true; } }); bn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { new MyDialog(CategoryActivity.this).showAddDialog(type, types, handler); } }); } public void myPopMenu(View v, final List<String> types, final String tableName, final int position) { PopupMenu p = new PopupMenu(this, v); p.getMenuInflater().inflate(R.menu.menu, p.getMenu()); p.setOnMenuItemClickListener(new OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { int id = item.getItemId(); switch (id) { case R.id.del: dbUtils.openDatabase(); dbUtils.delete("delete from " + tableName + " where type = '" + types.get(position) + "'"); types.remove(position); if (tableName.equals("incomeType")) { handler.sendEmptyMessage(0x1); types.toArray(LifeButlerUtils.incomeType); } else { types.toArray(LifeButlerUtils.outlayType); handler.sendEmptyMessage(0x2); } dbUtils.closeDB(); break; } return true; } }); p.show(); } Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == 0x1) { mAdapter1.notifyDataSetChanged(); } else if (msg.what == 0x2) { mAdapter2.notifyDataSetChanged(); } } }; class MyPagerAdapter extends PagerAdapter { @Override public int getCount() { return listView.size(); } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(listView.get(position)); } @Override public boolean isViewFromObject(View view, Object arg1) { return view == arg1; } @Override public Object instantiateItem(ViewGroup container, int position) { // position; container.addView(listView.get(position)); return listView.get(position); } } @Override public void finish() { // TODO Auto-generated method stub super.finish(); dbUtils.closeDB(); } @Override public void onCheckedChanged(RadioGroup group, int checkedId) { switch (checkedId) { case R.id.rb_income:// 选择校内 // setTabSelect(0);//显示校内资讯 viewPager.setCurrentItem(0);// 显示校内资讯 break; case R.id.rb_outlay:// 选择校外 // setTabSelect(1);//显示校外资讯 viewPager.setCurrentItem(1);// 显示校外资讯 break; default: break; } } @Override public void onPageScrollStateChanged(int arg0) { } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { } @Override public void onPageSelected(int arg0) { switch (arg0) { case 0:// 第1页 rb1.setChecked(true); break; case 1:// 第2页 rb2.setChecked(true); break; default: break; } } }

这块代码相对有点多,是1个完全的代码。主要就是自定义的1个ListView的适配器MyAdapter,将从数据库中查询出来的数据展现出来,利用ViewPager分别显示了输入的种别管理和支出的种别管理。在每一个list上可以长按进行删除,和在最下角可以添加种别操作。

好了这利用大体的主要代码都给出了,有些功能自己看看源代码吧,不再给出。谢谢您的围观,源码的下载地址在文章的开头。

生活不易,码农辛苦
如果您觉得本网站对您的学习有所帮助,可以手机扫描二维码进行捐赠
程序员人生
------分隔线----------------------------
分享到:
------分隔线----------------------------
关闭
程序员人生