生活管家app

Posted IT_faquir

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了生活管家app相关的知识,希望对你有一定的参考价值。

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

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

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();
    }
//作为第一次使用,将会初始化数据库。
    private void initDatabase() {
        // Boolean isFirst = sp.getBoolean("isFirst", true);// 用于得到是否为第一次使用此程序

        if (sp.getBoolean("isFirst", true)) {// 第一次使用初始化数据库
            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);
    }
//封装下启动界面的一个方法,以简化代码
    private void startActivity(Context context, Class c) {
        Intent intent = new Intent(context, c);
        startActivity(intent);
    }
}

从主函数中可以看出,此程序用到了sqlite本地数据库。同时SharedPreference也在程序中得到运用,用于存放一些简单的本地数据,作为是否为第一次使用应用程序的依据。还有就是启动activity方法的巧妙封装,这样可以大大减少代码量。
从代码中同时看到的,楼主用到了一个关于数据的操作的一个工具类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();
    }
}

这个数据库工具类很简单,就是对一些增删改查操作的封装。主要传入sql语句进行执行。因此需要读者,有一点的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;
    }

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

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语句有所变化,就不在继续贴出了。
查询的实现:
再来看看查询吧,这里以收入的查询为例:
也许难度就在于那些勾选查询,如何才能很好的实现,代码量少,又灵活的代码呢?如果有几十个勾选的条件,那代码量想想就可怕。因此楼主做了一些巧妙的处理:

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;// 是否为第一个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语句查询因此,需要生成一条满足条件的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的查询与此类似,不在叙述。
因此楼主总结出了一句话:我们要灵活的应对每件事,这样能有时能达到事半功倍的效果。
再来看看类别的管理
在对类别管理的实现中,楼主用到了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:// 第一页
            rb1.setChecked(true);
            break;
        case 1:// 第二页
            rb2.setChecked(true);
            break;
        default:
            break;
        }
    }
}

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

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

以上是关于生活管家app的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段13——Vue的状态大管家

VSCode自定义代码片段13——Vue的状态大管家

处理:APP home后,手机管家清理,导致回到app时,数据丢失

平安金管家app有五个消息提醒

运动健身小管家app下载|运动健身小管家app安卓版下载

##管家婆项目(app层)