项目介绍:
小哈记账是一款用于记账APP,基于Android Studio开发工具,采用Java语言进行开发,同时使用litepal和阿里云数据库进行数据的增删查改,以图标的形式在App的界面上显示。App可以清晰显示收支情况,并以图表的形式展示每月收支情况;同时可以记录消费用途,项目能够精确到每一个款项的收入支出时间、结余并且可以设置每月的预算。超出预算提醒,并且有每周,每月及每年的账单统计,较为清晰明确帮助用户分析自己当前的支出和收入。同时拥有用户登录、注册、修改头像等功能。
本项目中使用到的技术:LitePal数据库,阿里云RDS数据库,MPAndroidChart图表库,部分自定义控件等。
支持Android5.0以上版本。
本文将介绍小哈记账的登录页面制作以及本地数据库的创建。
效果图:
源代码:
首先,介绍一下本地数据库的搭建。 目前阶段,我们需要实现注册(文章2中进行了介绍)和登录功能,所以我们只需要建立一个users数据表。下面就来介绍一下建立本地数据库的过程。(Android Studio中建立LitePal数据库的过程见文章配置LitePal详细过程)
本地数据库搭建
第一步:建立实体类Users.java
package com.example.xiaohaaccounting.Entity_class;
import org.litepal.crud.LitePalSupport;
public class Users extends LitePalSupport {
private int id;
private String user_name;
private String user_phone;
private String user_password;
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setUser_name(String user_name) {
this.user_name = user_name;
}
public String getUser_name() {
return user_name;
}
public void setUser_phone(String user_phone) {
this.user_phone = user_phone;
}
public String getUser_phone() {
return user_phone;
}
public void setUser_password(String user_password) {
this.user_password = user_password;
}
public String getUser_password() {
return user_password;
}
}
第二步:在litepal.xml中添加建立的类
<?xml version="1.0" encoding="utf-8"?>
<litepal>
<dbname value="Users"></dbname>
<version value="1"></version>
<list>
<mapping class="com.example.xiaohaaccounting.Entity_class.Users"></mapping>
</list>
</litepal>
这样本地数据库就建立完毕了。(基于本地数据库的注册功能已经可以实现)
登录功能的实现
当用户输入用户名完毕后查询账号密码(即添加一个失焦事件在数据库中进行查找)
这里仍然提供了本地数据库和云数据库两种方法的代码。
/*查询账号*/
private void select_account(boolean hasFocus){
if(!hasFocus){
/*阿里云数据库*/
new Thread(new Runnable() {
@Override
public void run() {
try {
account = accountEdit.getText().toString();
myname_phone();
password = Database_Sql.querySelect_x("user_password",account);//调用插入数据库语句
} catch (SQLException e) {
e.printStackTrace();
}
}
}).start();
/*本地数据库
account = accountEdit.getText().toString();
List<Users> users = LitePal.findAll(Users.class);
for (Users user : users) {
if (user.getUser_phone().equals(account) || user.getUser_name().equals(account)) {
password = user.getUser_password();
}
}*/
}
}
下次打开app自动填充账号及自动登录功能的实现
由于后续退出登录功能的限制,此处代码有些冗余,大家可自行优化。
当自动登录复选框未选中时isAuto为false,将自动储存用户名,否则储存用户名和密码。
/*自动登录*/
boolean isAuto = pref.getBoolean("auto_login",false);
if(isAuto){
if(auto){
isauto_login = true;
} else {
isauto_login = false;
login_auto.setChecked(false);
auto_data_save();
}
if(isauto_login){
String pass = pref.getString("password","");
passwordEdit.setText(pass);
login_auto.setChecked(true);
select_account(false);
password_in = passwordEdit.getText().toString();
if(!password_in.isEmpty()){
acc_id = account;
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
}
}
}
/*保存自动登录所需信息*/
private void auto_data_save(){
String acc = accountEdit.getText().toString();
String pass = passwordEdit.getText().toString();
if(login_auto.isChecked()){
editor.putBoolean("auto_login",true);
editor.putString("account",acc);
editor.putString("password",pass);
} else {
editor.clear();
editor.putBoolean("auto_login",false);
editor.putString("account",acc);
}
editor.commit();
}
下面附上LoginActivity.java的完整代码
package com.example.xiaohaaccounting.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.text.InputType;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.example.xiaohaaccounting.Entity_class.Users;
import com.example.xiaohaaccounting.R;
import com.example.xiaohaaccounting.Utils_class.Database_Sql;
import com.example.xiaohaaccounting.Utils_class.MyAppCompatActivity;
import org.litepal.LitePal;
import java.sql.SQLException;
import java.util.List;
public class LoginActivity extends MyAppCompatActivity {
private SharedPreferences pref;
private SharedPreferences.Editor editor;
private TextView login_register;
//private TextView login_retrieve;
private TextView login_code_password;
private EditText accountEdit;
private EditText passwordEdit;
private RelativeLayout code_login;
private LinearLayout pass_login;
private CheckBox login_auto;
private ImageView login_button;
private ImageView login_eye;
private String account;
private String password;
private String password_in;
private String code;
private boolean isauto_login;
public static String acc_id;//用户唯一识别码
public static String mname = "", mpriture = "";
public static String mphone;
public static int mid;
public static boolean auto = true;//用于判断是否进行自动登录
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= 21) {//21表示5.0
Window window = getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
} else if (Build.VERSION.SDK_INT >= 19) {//19表示4.4
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
//虚拟键盘也透明
//getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
setContentView(R.layout.activity_login);
initView();//初始化控件
pref = getSharedPreferences("auto_data",MODE_PRIVATE);
editor = pref.edit();
login_auto = (CheckBox) findViewById(R.id.login_auto);
/*自动填充上次登录账号*/
String acc = pref.getString("account","");
if(!acc.isEmpty()){
accountEdit.setText(acc);
login_auto.setChecked(false);
select_account(false);
}
/*自动登录*/
boolean isAuto = pref.getBoolean("auto_login",false);
if(isAuto){
if(auto){
isauto_login = true;
} else {
isauto_login = false;
login_auto.setChecked(false);
auto_data_save();
}
if(isauto_login){
String pass = pref.getString("password","");
passwordEdit.setText(pass);
login_auto.setChecked(true);
select_account(false);
password_in = passwordEdit.getText().toString();
if(!password_in.isEmpty()){
acc_id = account;
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
}
}
}
/*显示或隐藏密码*/
login_eye.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(passwordEdit.getInputType() == 129){
login_eye.setBackground(getDrawable(R.drawable.eye));
passwordEdit.setInputType(InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
} else{
login_eye.setBackground(getDrawable(R.drawable.eye_none));
passwordEdit.setInputType(129);
}
}
});
/*切换登录方式*/
login_code_password.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
code_pass();
}
});
/*查询账号*/
accountEdit.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean hasFocus) {
select_account(hasFocus);
}
});
/*登录*/
login_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
password_in = passwordEdit.getText().toString();
if(password_in.equals(password)){
auto_data_save();//保存自动登录所需信息
acc_id = account;
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
} else{
Toast.makeText(getApplicationContext(),"账号或密码错误",Toast.LENGTH_SHORT).show();
}
}
});
/*跳转到新用户注册页面*/
login_register.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(LoginActivity.this, RegisterActivity.class);
startActivity(intent);
}
});
/*找回密码*//*
login_retrieve.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(LoginActivity.this, RetrieveActivity.class);
startActivity(intent);
}
});*/
}
/*初始化控件*/
private void initView(){
accountEdit = (EditText) findViewById(R.id.login_account);
passwordEdit = (EditText) findViewById(R.id.login_password);
login_code_password = (TextView) findViewById(R.id.login_code_passwrod);
login_button = (ImageView) findViewById(R.id.login_button);
login_register = (TextView) findViewById(R.id.login_register);
//login_retrieve = (TextView) findViewById(R.id.login_retrieve);
login_eye = (ImageView) findViewById(R.id.login_eye);
}
/*切换登录方式*/
private void code_pass(){
code_login = (RelativeLayout) findViewById(R.id.login_codebox);
pass_login = (LinearLayout) findViewById(R.id.login_passbox);
if(code_login.getVisibility() == View.INVISIBLE){
code_login.setVisibility(View.VISIBLE);
pass_login.setVisibility(View.INVISIBLE);
login_code_password.setText(" 密码登录 ");
} else {
pass_login.setVisibility(View.VISIBLE);
code_login.setVisibility(View.INVISIBLE);
login_code_password.setText("验证码登录");
}
}
/*查询账号*/
private void select_account(boolean hasFocus){
if(!hasFocus){
/*阿里云数据库*/
new Thread(new Runnable() {
@Override
public void run() {
try {
account = accountEdit.getText().toString();
myname_phone();
password = Database_Sql.querySelect_x("user_password",account);//调用插入数据库语句
} catch (SQLException e) {
e.printStackTrace();
}
}
}).start();
/*本地数据库
account = accountEdit.getText().toString();
List<Users> users = LitePal.findAll(Users.class);
for (Users user : users) {
if (user.getUser_phone().equals(account) || user.getUser_name().equals(account)) {
password = user.getUser_password();
}
}*/
}
}
/*保存自动登录所需信息*/
private void auto_data_save(){
String acc = accountEdit.getText().toString();
String pass = passwordEdit.getText().toString();
if(login_auto.isChecked()){
editor.putBoolean("auto_login",true);
editor.putString("account",acc);
editor.putString("password",pass);
} else {
editor.clear();
editor.putBoolean("auto_login",false);
editor.putString("account",acc);
}
editor.commit();
}
/*获取当前账号基本信息*/
private void myname_phone(){
mname = "";
List<Users> users = LitePal.select("user_name","user_phone")
.where("user_name = ? or user_phone = ?",account,account)
.find(Users.class);
for(Users user : users){
mname = user.getUser_name();
mphone = user.getUser_phone();
Log.d("Rui", "myname_phone: "+mname);
}
if(mname.isEmpty()){
new Thread(new Runnable() {
@Override
public void run() {
try {
mname = Database_Sql.querySelect_x("user_name", account);
mphone = Database_Sql.querySelect_x("user_phone", account);
mpriture = Database_Sql.querySelect_x("user_priture", account);
mid = Integer.parseInt(Database_Sql.querySelect_x("id",account));
Log.d("Rui", "myname_phone1: "+mname);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}).start();
} else {
new Thread(new Runnable() {
@Override
public void run() {
try {
mpriture = Database_Sql.querySelect_x("user_priture", account);
mid = Integer.parseInt(Database_Sql.querySelect_x("id",account));
Log.d("Rui", "myname_phone2: "+mid);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}).start();
}
}
}
actyvity_login.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<!--Logo-->
<ImageView
android:layout_width="320dp"
android:layout_height="100dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="80dp"
android:src="@drawable/login_logo2" />
<!--账号输入框-->
<LinearLayout
style="@style/InputBoxStyle"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="220dp"
android:orientation="horizontal">
<View
android:layout_width="20dp"
android:layout_height="20dp" />
<EditText
android:id="@+id/login_account"
style="@style/EditTextStyle"
android:layout_width="200dp"
android:layout_height="30dp"
android:layout_centerHorizontal="true"
android:gravity="center"
android:hint="请输入用户名或手机号"
android:maxLength="20"
android:singleLine="true"
tools:ignore="TouchTargetSizeCheck" />
<View
android:layout_width="20dp"
android:layout_height="20dp" />
</LinearLayout>
<!--密码输入框-->
<LinearLayout
android:id="@+id/login_passbox"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="290dp"
android:orientation="horizontal"
android:visibility="visible"
style="@style/InputBoxStyle">
<View
android:layout_width="20dp"
android:layout_height="20dp" />
<EditText
android:id="@+id/login_password"
style="@style/EditTextStyle"
android:layout_width="200dp"
android:layout_height="30dp"
android:layout_centerHorizontal="true"
android:gravity="center"
android:hint="请输入密码"
android:inputType="textPassword"
android:singleLine="true"
android:maxLength="16"
tools:ignore="TouchTargetSizeCheck" />
<!--密码隐藏与显示-->
<ImageView
android:id="@+id/login_eye"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="@drawable/eye_none"/>
</LinearLayout>
<!--验证码输入框-->
<RelativeLayout
android:id="@+id/login_codebox"
android:layout_width="336dp"
android:layout_height="54dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="290dp"
android:visibility="invisible">
<LinearLayout
style="@style/InputBoxStyle"
android:layout_width="200dp"
android:layout_height="54dp"
android:layout_alignParentLeft="true"
android:orientation="vertical">
<EditText
android:id="@+id/login_code"
style="@style/EditTextStyle"
android:layout_width="180dp"
android:layout_height="30dp"
android:layout_centerHorizontal="true"
android:gravity="center"
android:hint="请输入验证码"
android:singleLine="true" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="54dp"
android:layout_alignParentRight="true"
android:orientation="vertical"
style="@style/InputBoxStyleCode">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="获取验证码"
android:textSize="14sp"
android:textColor="#ffffff" />
</LinearLayout>
</RelativeLayout>
<!--自动登录 验证码登录-->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="354dp"
android:layout_centerHorizontal="true">
<CheckBox
android:id="@+id/login_auto"
style="@style/Widget.AppCompat.CompoundButton.RadioButton"
android:layout_width="36dp"
android:layout_height="wrap_content"
android:theme="@style/My_CheckBox"
tools:ignore="TouchTargetSizeCheck,TouchTargetSizeCheck" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="自动登录"
android:textColor="@color/grey_3"/>
<!--<View
android:layout_width="36dp"
android:layout_height="30dp"/>-->
<TextView
android:id="@+id/login_code_passwrod"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="验证码登录"
android:textColor="@color/grey_3"
android:visibility="gone"/>
</LinearLayout>
<!--登录按钮-->
<ImageView
android:id="@+id/login_button"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="430dp"
android:background="@drawable/login_login_button" />
<!--底部-->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_alignParentBottom="true"
android:layout_marginBottom="20dp"
android:layout_centerHorizontal="true">
<!--<TextView
android:id="@+id/login_retrieve"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="找回密码"
android:textSize="16sp"
android:textColor="@color/grey_3" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" | "
android:textSize="18sp"
android:textColor="@color/grey_3" />-->
<TextView
android:id="@+id/login_register"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="新用户注册"
android:textSize="16sp"
android:textColor="@color/grey_3" />
</LinearLayout>
</RelativeLayout>
自定义输入框样式代码(添加至styles.xml中)
<!--自定义输入框-->
<style name="EditTextStyle">
<item name="android:layout_marginTop">5sp</item>
<item name="android:layout_marginRight">10sp</item>
<item name="android:layout_marginBottom">5sp</item>
<item name="android:layout_marginLeft">10sp</item>
<item name="android:background">@null</item>
</style>
<!--自定义输入框-->
<style name="EditTextStyleId">
<item name="android:layout_marginTop">5sp</item>
<item name="android:layout_marginRight">20sp</item>
<item name="android:layout_marginBottom">5sp</item>
<item name="android:layout_marginLeft">30sp</item>
<item name="android:background">@null</item>
</style>
<!--无下划线输入框-->
<style name="EditTextStyleAcc">
<item name="android:background">@null</item>
</style>
<!--自定义复选框-->
<style name="My_CheckBox" parent="Theme.AppCompat.Light">
<item name="android:colorControlActivated">@color/xiaoha</item>//激活后
<item name="android:colorControlNormal">@color/xiaoha</item>//激活前
</style>