Financial assistant APP based on Android native development

1, Experimental topic

Personal Finance Assistant

2, Experimental purpose

  1. Master SQLite database and its use.
  2. Master layout and common controls Button, ListView, EditText, TextView, etc.

3, Overall design

(including background knowledge or basic principles and algorithms, or module introduction, design steps, etc.)

3.1 background knowledge

The financial assistant app based on Android adopts an incremental software development model. It mainly applies Android native controls such as listView, button, editText, textView, spinner, dialog, CalendarView and menu, as well as custom View controls shanview (sector chart) and circleprogressbar (circular progress bar); It adopts a hierarchical MVC like structure, which is divided into Activity(View), JavaBean(Model), Service (Control), and Util package (tool class, including string processing class, time format conversion class, database operation class, etc.). In order to achieve the design goal of reducing coupling and improving cohesion at the module level.

3.2 overall design

3.3 module introduction

3.31 login registration module

(1) Login module: mainly the realization of user login function, with the form of filling in user name, password and selecting role (user / administrator). And a jump button to log in. In terms of login, the password is filled in the password box and attached with an icon button (isSelected Implementation). You can click to display / hide the password. For non initial login, when the user fills in the user name, the password will be filled in automatically (implemented by shared preferences). When the focus of the user name text box changes, the circular avatar above will automatically rotate for one circle (animation Implementation). Involving the query operation of database user table, the statement is "select password from user where name = '+ name +"' "; The page picture is figure 1.
(2) Registration module: mainly the realization of user registration function. Ui interface uses the login module and has the function of judging whether the user has been registered. User name and password cannot be empty. Query insertion operation involving database user table. In terms of administrator, an administrator account will be automatically created, and the sql statement is "insert into user (name,password,role) values ('admin ',' admin ',' administrator ')"; The page picture is figure 1.

3.32 data display module

(1) Seasonal income display module: use the circular progress bar (circular progress bar) to realize seasonal statistics of income amount. It is divided into four seasons: spring (March, April and may), summer (June, July and August), autumn (September, October and November) and winter (December, January and February). The page picture is figure 6.

(2) Seasonal expenditure display module: similar to the seasonal income display module, the revenue amount can be counted by season by using the circular progress bar. It is divided into four seasons: spring (March, April and may), summer (June, July and August), autumn (September, October and November) and winter (December, January and February). The page picture is 5.

(3) This month's income display module: obtain the current month, classify (express, part-time, salary, allowance) and count the income sources, and use the custom sector chart control shanView. The statement involving the database is "select sum(income.money) as money from income where name = '" + loginactivity Name + "'and date like"% "+ year+"-"+month +" -% ", the idea is to sum the query by month, and then sum the seasons. The page picture is figure 11.

(4) This month's expenditure display module: similar to this month's income display module, obtain the current month, classify (catering, transportation, entertainment, shopping) and count the expenditure direction, use the custom sector chart control shanView, and the statement involving the database is "select sum(outcome.money) as money from outcome where name = '" + loginactivity Name + "'and date like%" + year+"-"+month + "-%", the idea is to sum and query by month, and then calculate the sum of seasons. The page picture is figure 11.

3.33 data management module

Note management module: it is divided into two pages, one for adding notes and one for querying notes. Among them, adding notes is relatively simple. Querying notes is a fuzzy query based on the content of notes. Use the database query statement keyword like. For example, select * from tips where info like '% today%'; By detecting whether the content of the text box has changed, if so, execute a fuzzy query and display the results in the text box below. The page pictures are Figure 10 and Figure 12.

Revenue and expenditure management module: it is composed of adding revenue and expenditure records, deleting revenue and expenditure records, statistical revenue and expenditure (3.32 data display module) and querying revenue and expenditure records. Adding revenue and expenditure is relatively simple. Query and deletion are written together. The specific implementation idea is to query all records, display them with lisetview, and use setOnItemClickListener() to monitor to select rows (records), and then pop up a dialog box to choose whether to delete this record. The page picture is figure 3.

The specific codes are as follows

dialog = new AlertDialog.Builder(MyIncomeActivity.this).setTitle("System prompt")
 .setMessage("Delete this record?")
 .setIcon(R.mipmap.ic_launcher)
 .setPositiveButton("determine", new DialogInterface.OnClickListener() {
   @Override
   public void onClick(DialogInterface dialog, int which) {
	 // Delete a record
   String sql = "delete from income where _id="+id_selected;
   System.out.println(sql);
   dbprocess2.execSql(sql);
Toast.makeText(MyIncomeActivity.this,"Delete succeeded, please refresh the page to view",Toast.LENGTH_SHORT).show();

    }
   })
.setNegativeButton("cancel",null)
                .create();

Data export module: the exported data is a txt file. Although it is somewhat outdated and does not take the form of new functions, such as sending e-mail, it also realizes the classic file storage function and consolidates the foundation. The idea is to query all records, store them in arraylist (array queue), and then take them out in the file output stream with getXX() method and store them in the file.
The specific implementation code is as follows

private void exportIncomeToTxt() {
        SQLiteDatabase db=helper.getWritableDatabase();
        String sql = "select * from income";
        Cursor cursor = db.rawQuery(sql, null);
        List<Income> list = new ArrayList<>();
        while(cursor.moveToNext()){
            Income income = new Income();
            income.set_id(cursor.getString(0));
            income.setMoney(cursor.getString(2));
            income.setDate(cursor.getString(3));
            income.setClasses(cursor.getString(4));
            income.setPayer(cursor.getString(5));
            income.setComment(cursor.getString(6));
            list.add(income);
            System.out.println((income.get_id()+","+income.getMoney()+","+income.getDate()+","+income.getClasses()+","+income.getPayer()+","+income.getComment()+"\r\n"));
        }
        cursor.close();
        db.close();

        StringBuffer buffer = new StringBuffer();
        buffer.append("id,amount of money,time,category,Payer ,remarks\r\n");
        for(Income income:list){
            buffer.append(income.get_id()+","+income.getMoney()+","+income.getDate()+","+income.getClasses()+","+income.getPayer()+","+income.getComment()+"\r\n");
        }


            String data = buffer.toString();
           
            String filename = "Revenue bill_"+CurrentTime.getCurrentTime()+".txt";
            FileOutputStream fos;
            try {
                fos = openFileOutput(filename,MODE_PRIVATE);
                fos.write(data.getBytes());
                fos.close();
            } catch (Exception e) {
            e.printStackTrace();
        }
    }

3.34 system setting module

The system setting module is mainly composed of modifying password and wallpaper. They are relatively simple, so I won't repeat them one by one here. To make a long story short, modifying wallpaper mainly uses sharereferences to store the current wallpaper, and then the wallpaper will be set as soon as the onCreate() method is called in the main menu.

4, Detailed design (including main data structure, program flow chart, key code, etc.)

4.1 database design

4.11 entity design: E-R diagram

Entity category: user, income statement, expenditure statement, revenue and expenditure memo

4.12Sql statement:

CREATE TABLE income(_id integer primary key autoincrement,name varchar(20) not null,money varchar(20) not null,date varchar(20) not null,class varchar(20) not null,payer varchar(20) not null,comment varchar(50) not null);

CREATE TABLE outcome(_id integer primary key autoincrement,name varchar(20) not null,money varchar(20) not null,date varchar(20) not null,class varchar(20) not null,location varchar(20) not null,comment varchar(50) not null);

CREATE TABLE tips(_id integer primary key autoincrement,name varchar(20) not null,info varchar(50) not null);

CREATE TABLE user(name varchar(20) primary key not null,password varchar(20) not null,role varchar(20) not null);

4.2 activity diagram design

4.3 use case diagram design

4.4 key codes

4.41 database:

package com.example.myapplication5.Utils;
/* Originally intended to be defined as a static tool class, it is not set in this way because there is an incoming parameter helper */
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import static java.lang.Integer.parseInt;

public class dbProcess2 {
    //    Startup class
    private MyHelper helper;
    //    database
    private SQLiteDatabase db;

    public dbProcess2(MyHelper helper) {
        this.helper = helper;

    }

    //    The database object must be retrieved every time
//    Addition, deletion and modification
    public void execSql(String sql) {
        //  Get database
        db = helper.getWritableDatabase();
        db.execSQL(sql);
        db.close();
    }

    //    Query revenue and expenditure records
    public void query(String sql, TextView mTvShow, Context context) {
        //  Get database
        db = helper.getWritableDatabase();
        Cursor cursor = db.rawQuery(sql, null);
        int number = cursor.getCount();
        if (cursor.getCount() == 0) {
            mTvShow.setText("");
            Toast.makeText(context, "no data", Toast.LENGTH_SHORT).show();
        } else {
            cursor.moveToFirst();
//            Subscript starts at 0
            mTvShow.append("\n------------------------------");
            mTvShow.setText("\n" + cursor.getString(2) + "element," + cursor.getString(3) + "," + cursor.getString(4) + "," + cursor.getString(5) + "," + cursor.getString(6));
            mTvShow.append("\n------------------------------");
        }
        while (cursor.moveToNext()) {
            mTvShow.append("\n" + cursor.getString(2) + "element," + cursor.getString(3) + "," + cursor.getString(4) + "," + cursor.getString(5) + "," + cursor.getString(6) );
            mTvShow.append("\n------------------------------");
        }
        cursor.close();
        db.close();
    }

    //    Query revenue and expenditure notes
    public void queryTips(String sql, TextView mTvShow, Context context) {
        //  Get database
        db = helper.getWritableDatabase();
        Cursor cursor = db.rawQuery(sql, null);
        int number = cursor.getCount();
        System.out.println(number+"------");
        if (cursor.getCount() == 0) {
            mTvShow.setText("");
            System.out.println(1111);
            Toast.makeText(context, "no data", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(context,"Found"+number+"Data bar",Toast.LENGTH_SHORT).show();
            cursor.moveToFirst();
//            Subscript starts at 0
//            setText-->append
            System.out.println(cursor.getString(0)+cursor.getString(2));
            mTvShow.setText(cursor.getString(0) + "," + cursor.getString(2) + ";");
        }
        while (cursor.moveToNext()) {
            System.out.println(cursor.getString(0)+cursor.getString(2));
            mTvShow.append("\n" + cursor.getString(0) + "," + cursor.getString(2) + ";");
        }
        cursor.close();
        db.close();
    }

    //  Query password or authority according to user name
    public String queryOne(String sql) {
        //  Get database
        db = helper.getWritableDatabase();
        Cursor cursor = db.rawQuery(sql, null);
        if (cursor.getCount() == 0) {
            return "user does not exist";
        } else {
            cursor.moveToFirst();
            /* Why is the index 0 here? Answer: because what you get here is a single column -- select password/role */
            return cursor.getString(0);
        }
    }

    //    Query revenue / expenditure table by user name and revenue and expenditure table by month
    public int queryMoney(String sql) {
        int count = 0;
        //  Get database
        db = helper.getWritableDatabase();
        Cursor cursor = db.rawQuery(sql, null);
        System.out.println("Number of records queried"+cursor.getCount());
        if (cursor.getCount() == 0) {
            return 0;
        } else {
            cursor.moveToFirst();
            String num = cursor.getString(0);
            if (StringUtils.isBlank(num)){
//                You need to add a judgment here to determine whether it is empty. Why do you always find a record???
                return 0;
            }
            count = parseInt(num);
            System.out.println("-----" + num + "-----");
        }
        cursor.close();
        db.close();
        return count;
    }

}

4.5 screenshot of operation effect


Figure 1 login registration

Figure 2 background management page

Figure 3 my revenue page

Figure 4 data management page


Figure 5-6 data visualization page

Figure 7 main menu interface

Figure 8 new revenue page

Figure 9 system setting page

Figure 10 adding notes

Figure 11 income / expenditure of this month

Figure 12 query notes

5, Experimental results and analysis

This course design realizes login and registration, new income, new expenditure, query all income, query all expenditure, delete income records by id, delete expenditure records by id, count and display the amount and proportion of seasonal income in the current year, count and display the amount and proportion of seasonal expenditure in the current year, count the source of income in the current month, and count the destination of expenditure in the current month (fan chart) Change wallpaper, change password, export data (txt file), add revenue and expenditure notes, query revenue and expenditure notes (fuzzy query like by content), etc. In general, it meets the design requirements in the guidance. There are some innovations, such as more controls that have not been touched in the use of controls, such as CalendarView in the time selection of revenue and expenditure records, Spinner in the revenue and expenditure category, menu in the function selection of data management page, custom ring progress bar in the proportion of seasonal revenue and expenditure, and dynamic drawing function, Enriched the user experience. Also learn from the custom fan chart control of the boss on csdn.

6, Summary and experience

The course design lasted two weeks, and I felt a lot and gained a lot. It can be regarded as the first mature project independently designed by myself. It applies database technology, mvc architecture idea, hierarchical idea, android interface design and component design. This project has a large amount of code and more than 30 classes, so code redundancy is also a major disadvantage. In fact, some function functions can be separated into a single class, but I am a little overwhelmed about the interface design level after separation. For example, the encapsulated database operation class dbprocess2 Class, it realizes the general function in addition, deletion, modification and query, but the query and display on some pages need personalized requirements, so we have to rewrite a similar method, otherwise we have to change the original method in order to be general. This involves an individual's choice in cohesive coupling. I try to achieve "low coupling and high cohesion"
In the code design, I try to adhere to the principle of standardization. Each module has written comments, which is not only convenient for others to understand, but also clear for myself to find and modify bug s. In the design, I also use the test class junit, which is better for page driven method calls such as android. Test the function of a module and a function separately, and then add the original program after testing.
In terms of topic selection, I pay more attention to business logic than ui design, so I chose a small financial assistant with a simpler interface. The ui design of other topics is more complex, and it will be more time-consuming to complete the development. However, it will also appropriately add new controls to beautify the page, so as to expand on the basis of mastering the learned knowledge. Based on the foundation, incremental design.
This course design is completed by myself. At the moment of making the finished product, I feel that all the hard work is worth it. I feel full of sense of achievement. Each work, like my own children, records the footprints of my growth.
I also thank the teacher for his comments, suggestions and affirmation in the final acceptance link. I will try my best to correct it. For example, in the design of flow chart, I will be more standardized and adopt engineering uml design to standardize myself. Try to form good habits. I did a lot of recording work in the process of this course design. I wrote a concise log and summarized the problems I encountered every day, and then thought more about generally determining the design objectives of the next day, which modules to add, and so on. In this way, I also have a clear goal and a sense of direction. In the process of typing the code, it doesn't seem easy, but I'm relatively resilient. I don't give up easily in case of problems. I try to learn from other people's experience and search a large number of blogs. Some people write better. I adopted it. This makes it possible to do it in the end.

Keywords: Android app

Added by rubing on Fri, 28 Jan 2022 12:29:46 +0200