Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 生活管家app

生活管家app

編輯:關於Android編程

這篇文章給大家帶來的是一款android的生活管家app實現。
主要實現功能及其要求:
1、個人收入支出的管理。主要完成收入管理、支出管理、類別管理、收入查詢、支出查詢、統計信息等功能。
2、實現每次進入應用需要進行密碼輸入,增強安全性。
3、其他功能可根據個人自己的想法添加。
4、系統界面美觀,操作方便。
好了,根據這樣的要求,您會想到開發一個怎樣的app呢?快發揮您的想象能力和動手能力吧!
接下來,來看看博主的實現,先來看看實現的效果展示吧。。。
進入主界面密碼主界面類別管理收入查詢收入管理查詢結果用戶信息用戶信息修改
應該還可以吧,不算太丑。其中的統計和輔助工具就沒有實現了,太耽誤時間了,如果讀者有興趣,可自行完成。

重點內容
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 aAdapter = new ArrayAdapter(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 aAdapter = new ArrayAdapter(this,
                android.R.layout.simple_list_item_1, LifeButlerUtils.incomeType);
        sp_source.setAdapter(aAdapter);

    }

    public void query(View v) {
        Map map = new HashMap();
        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 listView;
    private DatabaseUtils dbUtils;
    private ArrayAdapter mAdapter1;
    private ArrayAdapter 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 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 types = new ArrayList();
        Cursor c1 = dbUtils.query("select type from incomeType");
        while (c1.moveToNext()) {
            String t = c1.getString(0);
            types.add(t);
        }

        mAdapter1 = new ArrayAdapter(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 types = new ArrayList();
        Cursor c1 = dbUtils.query("select type from outlayType");
        while (c1.moveToNext()) {
            String t = c1.getString(0);
            types.add(t);
        }

        mAdapter2 = new ArrayAdapter(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 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上可以長按進行刪除,以及在最下角可以添加類別操作。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved