明天就开学了,前一天晚上姑且把APP的初稿做了出来,这个寒假除了阅读任务之外,我大部分时间都在玩(反省)。下面进行展示:
一,数据库:
DBUser.java
1 package com.example.vacation; 2 3 import android.content.ContentValues; 4 import android.content.Context; 5 import android.database.sqlite.SQLiteDatabase; 6 import android.database.sqlite.SQLiteOpenHelper; 7 8 //继承SQLiteOpenHelper,用于创建数据库 9 public class DBUser extends SQLiteOpenHelper { 10 public DBUser(Context context, String name, SQLiteDatabase.CursorFactory factory, int version){ 11 super(context, name, factory, version); 12 } 13 14 //重写onCreate方法 15 @Override 16 public void onCreate(SQLiteDatabase db) { 17 //该数据库创建user,message两个表 18 String sql="create table user(id integer primary key autoincrement,username varchar(20),password varchar(20))"; 19 String sql2="create table message(mid integer primary key autoincrement,musername varchar(20),name varchar(20),money varchar(20),date varchar(20),inout varchar(20))"; 20 db.execSQL(sql); 21 db.execSQL(sql2); 22 } 23 24 //此方法用于注册账号时将账号密码录入user表 25 public void addData(SQLiteDatabase sd,String username,String password){ 26 ContentValues values=new ContentValues(); 27 values.put("username",username); 28 values.put("password",password); 29 sd.insert("user",null,values); 30 } 31 32 @Override 33 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 34 35 } 36 }
创建SQLite数据表的方法就是创建一个java类,继承SQLiteOpenHelper,随后对onCreate方法进行重写,正常也要对下面的onUpgrade方法也要进行重写,这个跟数据库的更新有关。在onCreate方法中我们要设定表的相关信息,代码所示我创建了user和message两个表,前面用于记录用户的账号密码,后面则是记录用户的收入支出数据。判定用户数据的标准是musername项,这里存储的是用户的账号,在查询是会遍历该表,以账号作为查询标准。其他信息也可以作为标准,但因为时间缘故没有完成,后续可能会进行完善。
二,起始界面:
MainActivity.java(后台)
1
package com.example.vacation;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
//声明控件
private Button create;
private Button login;
private EditText user;
private EditText pass;
private DBUser dbuser;
private SharedPreferences.Editor editor;
private SQLiteDatabase sqLiteDatabase;
private SharedPreferences sp;
//调用方法
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
login=(Button)findViewById(R.id.login);
create=(Button)findViewById(R.id.create);
user=(EditText)findViewById(R.id.user);
pass=(EditText)findViewById(R.id.pass);
login.setOnClickListener(this);
create.setOnClickListener(this);
//创建数据库
dbuser=new DBUser(MainActivity.this,"user_db",null,1);
sqLiteDatabase=dbuser.getWritableDatabase();
//该栏原定用于完成“记住密码”的功能,但该功能未实现
sp=getSharedPreferences("user_mes",MODE_PRIVATE);
editor=sp.edit();
if(sp.getBoolean("flag",false)){
String user_read=sp.getString("user","");
String pass_read=sp.getString("pass","");
user.setText(user_read);
pass.setText(pass_read);
}
}
//设置按钮点击事件
@Override
public void onClick(View view){
//分“登录”和“注册”两个按钮
switch (view.getId()){
//登录
case R.id.login:
//取值
String user_str=user.getText().toString();
String pass_str=pass.getText().toString();
//判定
if(user_str.equals("")||pass_str.equals("")){
Toast.makeText(this,"账号或密码不能为空",Toast.LENGTH_SHORT).show();
}else{
//遍历user表,若账号不存在证明未注册,提示错误信息
Cursor cursor=sqLiteDatabase.query("user",new String[]{"password"},"username=?",new String[]{user_str},null,null,null);
if(cursor.moveToNext()){
String pass_query=cursor.getString(cursor.getColumnIndex("password"));
if(pass_str.equals(pass_query)){
//提示框
Toast.makeText(this,"登录成功",Toast.LENGTH_SHORT).show();
Intent intent=new Intent(MainActivity.this,Work.class);
intent.putExtra("muser",user_str);
startActivity(intent);
}else{
Toast.makeText(this,"账号或密码错误",Toast.LENGTH_SHORT).show();
}
}else{
Toast.makeText(this,"该用户不存在",Toast.LENGTH_SHORT).show();
}
}
break;
//注册,跳转页面
case R.id.create:
Intent intent=new Intent(MainActivity.this,CreateUser.class);
startActivity(intent);
break;
default:
break;
}
}
}
Android中的Java代码大体上跟构建web网页的思想差不多,需要注意的是从界面输入框,按钮等组件抓取值的问题。登录思路就是抓取账号输入框中输入的数据,随后遍历user表,不存在账号即提示错误信息。注册则是跳转页面,其功能之后讨论。
activity_main.xml(界面)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layout_marginTop="150dp" android:layout_marginBottom="50dp" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="记账本" android:textSize="40dp" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="80dp" android:layout_marginBottom="40dp" android:layout_gravity="center_horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="账号:" android:textSize="30dp"></TextView> <EditText android:id="@+id/user" android:layout_width="200dp" android:layout_height="wrap_content" android:hint="请输入账号"></EditText> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_gravity="center_horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="密码:" android:textSize="30dp" ></TextView> <EditText android:id="@+id/pass" android:layout_width="200dp" android:layout_height="wrap_content" android:hint="请输入密码" ></EditText> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="60dp" android:layout_marginBottom="30dp" android:layout_gravity="center_horizontal"> <Button android:id="@+id/login" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="20dp" android:text="登录" ></Button> <Button android:id="@+id/create" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:text="注册" ></Button> </LinearLayout> </LinearLayout>
这是起始界面的xml,全部都是用线性布局完成,使用控件时对位置,字体进行了微调。
三,注册界面:
CreateUser.java(后台)
1 package com.example.vacation; 2 3 import androidx.appcompat.app.AppCompatActivity; 4 5 import android.content.ContentResolver; 6 import android.content.Intent; 7 import android.database.CharArrayBuffer; 8 import android.database.ContentObserver; 9 import android.database.Cursor; 10 import android.database.DataSetObserver; 11 import android.database.sqlite.SQLiteDatabase; 12 import android.net.Uri; 13 import android.os.Bundle; 14 import android.view.View; 15 import android.widget.Button; 16 import android.widget.EditText; 17 import android.widget.Toast; 18 19 public class CreateUser extends AppCompatActivity implements View.OnClickListener { 20 21 private Button ccreate; 22 private EditText cuser; 23 private EditText cpass; 24 private SQLiteDatabase sqLiteDatabase; 25 private DBUser dbuser; 26 27 private String username_str=""; 28 private String password_str=""; 29 30 31 @Override 32 protected void onCreate(Bundle savedInstanceState) { 33 super.onCreate(savedInstanceState); 34 setContentView(R.layout.activity_create_user); 35 36 ccreate=(Button)findViewById(R.id.ccreate); 37 cuser=(EditText)findViewById(R.id.cuser); 38 cpass=(EditText)findViewById(R.id.cpass); 39 dbuser = new DBUser(CreateUser.this,"user_db",null,1); 40 sqLiteDatabase=dbuser.getWritableDatabase(); 41 42 ccreate.setOnClickListener(new View.OnClickListener() { 43 @Override 44 public void onClick(View v) { 45 username_str=cuser.getText().toString(); 46 password_str=cpass.getText().toString(); 47 48 //判定账号是否已注册 49 Cursor cursor=sqLiteDatabase.query("user",new String[]{"username"},"username=?",new String[]{username_str},null,null,null); 50 if(cursor.getCount()!=0){ 51 Toast.makeText(CreateUser.this,"该用户已注册",Toast.LENGTH_SHORT).show(); 52 }else { 53 dbuser.addData(sqLiteDatabase, username_str, password_str); 54 Toast.makeText(CreateUser.this,"注册成功",Toast.LENGTH_SHORT).show(); 55 Intent intent=new Intent(CreateUser.this,MainActivity.class); 56 startActivity(intent); 57 finish(); 58 } 59 } 60 }); 61 } 62 63 @Override 64 public void onClick(View v) { 65 66 } 67 }
注册的Java代码很简答,按钮也只有一个,所以不用像起始界面那样使用switch,数据库操作与检查登录无异。一样是遍历数据库,若存在证明账号存在,提示错误信息。
activity_create_user.xml(界面)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layout_marginTop="100dp" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="注册账号" android:textSize="40dp" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="80dp" android:layout_marginBottom="40dp" android:layout_gravity="center_horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="账号:" android:textSize="30dp"></TextView> <EditText android:id="@+id/cuser" android:layout_width="200dp" android:layout_height="wrap_content" android:hint="请输入账号"></EditText> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_gravity="center_horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="密码:" android:textSize="30dp" ></TextView> <EditText android:id="@+id/cpass" android:layout_width="200dp" android:layout_height="wrap_content" android:hint="请输入密码" ></EditText> </LinearLayout> <Button android:id="@+id/ccreate" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="30dp" android:text="注册" ></Button> </LinearLayout>
注册界面做的比较简陋,只注册账号与密码即可,个人信息的录入可以考虑加入到菜单,不过这是之后的考量了。在这段xml代码中我使用了几个线性布局的嵌套,主布局采用的是垂直分布,子布局均采用水平分布。在位置规划上使用layout_marginTop等语法根据数值进行微调。
四,添加数据界面:
AddMes.java(后台)
1 package com.example.vacation; 2 3 import androidx.appcompat.app.AppCompatActivity; 4 5 import android.content.ContentValues; 6 import android.content.Intent; 7 import android.database.sqlite.SQLiteDatabase; 8 import android.os.Bundle; 9 import android.view.View; 10 import android.view.View.OnClickListener; 11 import android.widget.Button; 12 import android.widget.EditText; 13 import android.widget.RadioButton; 14 import android.widget.RadioGroup; 15 import android.widget.Toast; 16 17 //使用了RadioGroup 18 public class AddMes extends AppCompatActivity implements View.OnClickListener,RadioGroup.OnCheckedChangeListener{ 19 private EditText amuser; 20 private EditText amname; 21 private EditText amoney; 22 private EditText amdate; 23 private RadioGroup aminout; 24 private RadioButton amin; 25 private RadioButton amout; 26 private Button amcreate; 27 private DBUser dbuser; 28 private SQLiteDatabase sqLiteDatabase; 29 30 //loginname存储账号信息,将其提前填在账号框里,可修改 31 private String user_str=""; 32 private String name_str=""; 33 private String money_str=""; 34 private String date_str=""; 35 private String inout_str=""; 36 private static String loginname; 37 38 @Override 39 protected void onCreate(Bundle savedInstanceState) { 40 super.onCreate(savedInstanceState); 41 setContentView(R.layout.activity_add_mes); 42 43 amuser=(EditText)findViewById(R.id.amuser); 44 amname=(EditText)findViewById(R.id.amname); 45 amoney=(EditText)findViewById(R.id.amoney); 46 amdate=(EditText)findViewById(R.id.amdate); 47 aminout=(RadioGroup)findViewById(R.id.aminout); 48 amin=(RadioButton)findViewById(R.id.amin); 49 amout=(RadioButton)findViewById(R.id.amout); 50 amcreate=(Button)findViewById(R.id.amcreate); 51 52 aminout.setOnCheckedChangeListener(this); 53 amcreate.setOnClickListener(this); 54 55 dbuser=new DBUser(AddMes.this,"user_db",null,1); 56 sqLiteDatabase=dbuser.getWritableDatabase(); 57 58 Intent intentdata=getIntent(); 59 String CatchUser=intentdata.getStringExtra("auser"); 60 if(CatchUser!=null){ 61 loginname=CatchUser; 62 amuser.setText(loginname); 63 }else{ 64 amuser.setText(loginname); 65 } 66 67 } 68 69 //向数据表message添加数据 70 @Override 71 public void onClick(View view){ 72 user_str=amuser.getText().toString(); 73 name_str=amname.getText().toString(); 74 money_str=amoney.getText().toString(); 75 date_str=amdate.getText().toString(); 76 77 ContentValues values=new ContentValues(); 78 values.put("musername",user_str); 79 values.put("name",name_str); 80 values.put("money",money_str); 81 values.put("date",date_str); 82 values.put("inout",inout_str); 83 sqLiteDatabase.insert("message",null,values); 84 85 Intent intent=new Intent(AddMes.this,Work.class); 86 intent.putExtra("judgename",user_str); 87 startActivity(intent); 88 finish(); 89 } 90 91 //RadioButton选择并传值 92 @Override 93 public void onCheckedChanged(RadioGroup radioGroup,int checkedID){ 94 RadioButton rb=(RadioButton)findViewById(checkedID); 95 inout_str=rb.getText().toString(); 96 } 97 }
添加数据界面多了一些东西,其中在设定是收入还是支出上,我选择用RadioButton(单选框)来实现,因此在获取RadioButton值的时候需要对主函数进行微调。这里注意账号的信息是从起始界面开始通过intent传值过来的,它先是传到查询界面(工作主界面),又从那里intent传到该界面。一开始写这段的时候曾出现第一次添加数据时账号已事先录入,第二次添加则为空的情况。可能是因为多次页面跳转导致第二次intent传过来的是空值,因此我多设置了static String变量将其保存。
activity_add_mes.xml(界面)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="录入信息" android:textSize="40dp" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="20dp" android:layout_marginLeft="60dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="账号:" android:textSize="30dp"></TextView> <EditText android:id="@+id/amuser" android:layout_width="200dp" android:layout_height="wrap_content" android:hint="请输入账号"></EditText> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginLeft="60dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="名称:" android:textSize="30dp" ></TextView> <EditText android:id="@+id/amname" android:layout_width="200dp" android:layout_height="wrap_content" android:hint="请输入商品名称" ></EditText> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginLeft="60dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="金额:" android:textSize="30dp" ></TextView> <EditText android:id="@+id/amoney" android:layout_width="200dp" android:layout_height="wrap_content" android:hint="请输入金额" ></EditText> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginLeft="60dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="日期:" android:textSize="30dp" ></TextView> <EditText android:id="@+id/amdate" android:layout_width="200dp" android:layout_height="wrap_content" android:hint="例:20200216(年月日)" ></EditText> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginLeft="60dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="选项:" android:textSize="30dp"></TextView> <RadioGroup android:id="@+id/aminout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal"> <RadioButton android:id="@+id/amin" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="收入"></RadioButton> <RadioButton android:id="@+id/amout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="30dp" android:text="支出"></RadioButton> </RadioGroup> </LinearLayout> <Button android:id="@+id/amcreate" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="30dp" android:text="添加" ></Button> </LinearLayout>
这里要注意RadioButton的使用,它需要嵌套在RadioGroup中,复选框使用方法同理。这里还使用提示信息进行规定,需要注意的是日期的录入格式,当初设想的是这么录入在查找时比较好找一些,但影响观看,这里也是完善时需要改进的点。
五,查询界面(工作主界面,其他功能有待完善):
Work.java(后台)
1 package com.example.vacation; 2 3 import androidx.appcompat.app.AppCompatActivity; 4 5 import android.content.Intent; 6 import android.database.Cursor; 7 import android.database.sqlite.SQLiteDatabase; 8 import android.os.Bundle; 9 import android.view.View; 10 import android.widget.Button; 11 import android.widget.EditText; 12 import android.widget.TextView; 13 14 public class Work extends AppCompatActivity implements View.OnClickListener { 15 private Button addmes; 16 private Button seemes; 17 private TextView result; 18 private EditText searchuser; 19 private DBUser dbuser; 20 private SQLiteDatabase sqLiteDatabase; 21 22 @Override 23 protected void onCreate(Bundle savedInstanceState) { 24 super.onCreate(savedInstanceState); 25 setContentView(R.layout.activity_work); 26 27 addmes=(Button)findViewById(R.id.addmes); 28 seemes=(Button)findViewById(R.id.seemes); 29 result=(TextView)findViewById(R.id.result); 30 searchuser=(EditText)findViewById(R.id.searchuser); 31 addmes.setOnClickListener(this); 32 seemes.setOnClickListener(this); 33 34 dbuser=new DBUser(Work.this,"user_db",null,1); 35 sqLiteDatabase=dbuser.getWritableDatabase(); 36 } 37 38 @Override 39 public void onClick(View v) { 40 Intent intentdata=getIntent(); 41 String catchuser=intentdata.getStringExtra("muser"); 42 switch ((v.getId())){ 43 //跳转到添加数据界面 44 case R.id.addmes: 45 Intent intent=new Intent(Work.this,AddMes.class); 46 intent.putExtra("auser",catchuser); 47 startActivity(intent); 48 break; 49 case R.id.seemes: 50 //遍历输出 51 String judge=searchuser.getText().toString(); 52 String sql="select * from message where musername=?"; 53 Cursor cursor=sqLiteDatabase.rawQuery(sql,new String[]{judge}); 54 StringBuilder sbm = new StringBuilder(); 55 while(cursor.moveToNext()){ 56 String name="名称:"+cursor.getString(cursor.getColumnIndex("name")); 57 String money="金额:"+cursor.getString(cursor.getColumnIndex("money")); 58 String date="日期:"+cursor.getString(cursor.getColumnIndex("date")); 59 String inout=cursor.getString(cursor.getColumnIndex("inout")); 60 sbm.append(name).append(" "); 61 sbm.append(money).append(" "); 62 sbm.append(date).append(" "); 63 sbm.append(inout).append("\n"); 64 } 65 result.setText(sbm.toString()); 66 break; 67 default: 68 break; 69 } 70 } 71 72 }
这里注意遍历数据库并输出即可。一开始在使用intent传账号值的时候我的设想是传到这里直接抓来用,再传到添加数据界面继续用,结果在添加数据之后回到此界面时报错。经过一段时间的查找终于发现问题,是因为从添加界面回来之后原intent值已经没了,变成null了,解决方法就是从添加数据界面重新抓取,使用intent传回。此外,最开始完成的时候,这个界面的查询功能默认按照添加时录入的账号进行查找(intent传回来的值),很麻烦,所以临时在界面上添加了EditText控件用于输入查询账号。
activity_work.xml(界面)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_gravity="center_horizontal" android:layout_marginTop="50dp" > <Button android:id="@+id/addmes" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="20dp" android:text="添加数据" ></Button> <Button android:id="@+id/seemes" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:text="查看数据" ></Button> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="25dp" android:layout_marginLeft="60dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="查询账号:" android:textSize="15dp" ></TextView> <EditText android:id="@+id/searchuser" android:layout_width="200dp" android:layout_height="wrap_content" android:hint="请输入要查询的账号" ></EditText> </LinearLayout> <TextView android:id="@+id/result" android:layout_width="match_parent" android:layout_height="500dp" android:layout_marginVertical="30dp" android:layout_marginLeft="20dp" android:layout_marginRight="20dp" android:hint="查询内容为空" android:textColorHint="#CCCCCC" android:textColor="#6666FF" android:textSize="15dp"/> </LinearLayout>
显示界面调整了一下字体颜色,其他地方的构造方式与上述xml文件相同。
总结
虽然这个APP做的十分简陋,是个未完成的作品,但这是我第一次独立制作APP,一开始因为接触新的知识感到头疼,学习Android的时候翻阅了大量的博客,也尝试去github找找攻略,最后几天尝试找了些网课,最后交上这么一个作品。相比于其他同学的作品我的可能是最简单的一个,这也是因为假期我并没有全身心在学习,整体上十分放松。这个APP是我对假期的一个交代,也是新的开始,我需要斩掉自己的惰性,在新学期努力学习。