一:app介绍
理财小助手是一款利用Android studio软件实现的APP,可以录入每天的消费项目以及消费金额,同时也可以查找消费记录、统计消费总额。我用到的Android studio版本如下:
二、模块设计
下面是我实现的一些模块:
1:进入理财小助手app时会有一个登陆界面,包括邮箱和密码,邮箱和密码都有限制,如邮箱必须带有@符号,而密码必须不少于特定位数。

2:如果没有登录的邮箱或者密码时选择注册账号:

3:进入理财app先进入理财记录的首页:(此时还没有添加一条记录,首页显示为空)

4:添加一条消费记录,消费主体是lunch,消费金额是12,消费感受是good

5:点击左上方的箭头会默认自动保存此记录,如果点击右上方的X,就会删去这条记录,这样,在理财app的主页就会显示添加的消费记录:

6:也可以双击每一条记录,这样就会出现此记录的详细信息,比如我选择了第一条记录:

7:查看第五个步骤可以发现第五个步骤的图像右上方有三个符号,第一个+符号是添加一条记录,第二个符号是查找消息记录,第三个符号是可以统计金钱总额也可以显示出所有的消费记录:
第一个符号:

第二个符号查找记录:

第三符号有两个功能:


(1):统计功能:

比如统计今天记录:2022年1月15日

(2)显示记录的条数:如下,显示了添加的两条记录

三、代码设计
此代码设计分为两个部分,一个为前端的局面分布,一个为后端的java编写。如下:

1:java文件夹里面包含的是后端的代码,其中包含了database和wengxiaoyang.personalfinanceassistant。其中包括的类如下图所示:

2:res文件夹里面包括的是图片和前端代码,包括button或者布局等,是安卓必须掌握的基础知识点。

其中可可爱爱的蜡笔小新就来自与drawable,当然也可以换成其他的图片啦。在这里插入图片描述


layout里面存放的就是整个app的布局:

menu用来控制右上方的三个符号功能:

values用来控制button按钮:

注意:其他没有特别说明就是图片。

四、详细代码
1:先贴入java后端的代码
database中的ManageBaseHelp类

package database;
//数据库的继承类,并重写两种方法
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;import database.ManageDbSchema.ManageTable;
import database.ManageDbSchema.ManageTable2;
//打开数据库
public class ManageBaseHelper extends SQLiteOpenHelper {private static final int VERSION = 1;private static final String DATABASE_NAME = "manageBase.db";
//在此构造方法中用super方法调用父类的构造方法。传入四个参数,上下文对象,数据库名称,null,数据库版本public ManageBaseHelper(Context context) {super(context, DATABASE_NAME, null, VERSION);}//重写子类的onCreate方法@Overridepublic void onCreate(SQLiteDatabase db) {// manage表,暴力名称,金钱,支付方式等db.execSQL("create table " + ManageTable.NAME + "(" +"_id integer primary key autoincrement, " +ManageTable.Cols.UUID + ", " +ManageTable.Cols.TITLE + ", " +ManageTable.Cols.MONEY + ", " +ManageTable.Cols.DATE + ", " +ManageTable.Cols.PAYMETHOD  + ", " +ManageTable.Cols.REMARK + ")");// 账号密码表db.execSQL("create table " + ManageTable2.NAME2 + "(" +"_id integer primary key autoincrement, " +ManageTable2.Cols2.UUID + ", " +ManageTable2.Cols2.ACCOUNT + ", " +ManageTable2.Cols2.PASSWORD + ")");}//重写子类的onUpgrade方法@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
}

ManageCursorWrapper类

package database;
//将用户信息和消费消息写入数据库
import android.database.Cursor;
import android.database.CursorWrapper;import java.util.Date;
import java.util.UUID;import database.ManageDbSchema.ManageTable;
import database.ManageDbSchema.ManageTable2;
import wengxiaoyang.personalfinanceassistant.Login;
import wengxiaoyang.personalfinanceassistant.Manage;
//获得manage和login表格填写时的信息,并把他们放入数据库里面
public class ManageCursorWrapper extends CursorWrapper {public ManageCursorWrapper(Cursor cursor) {super(cursor);}public Manage getManage() {// 获得manage信息String uuidString = getString(getColumnIndex(ManageTable.Cols.UUID));//得到相对应的列索引,并赋值给string对象String title = getString(getColumnIndex(ManageTable.Cols.TITLE));String money = getString(getColumnIndex(ManageTable.Cols.MONEY));Long date = getLong(getColumnIndex(ManageTable.Cols.DATE));int payMethod = getInt(getColumnIndex(ManageTable.Cols.PAYMETHOD));String remark = getString(getColumnIndex(ManageTable.Cols.REMARK));// 将数据写入数据库Manage manage = new Manage(UUID.fromString(uuidString));manage.setTitle(title);manage.setMoney(money);manage.setDate(new Date(date));manage.setPayMethod(payMethod);manage.setRemark(remark);return manage;}public Login getLogin() {// 获得登录信息String uuidString = getString(getColumnIndex(ManageTable2.Cols2.UUID));String account = getString(getColumnIndex(ManageTable2.Cols2.ACCOUNT));String password = getString(getColumnIndex(ManageTable2.Cols2.PASSWORD));// 将登录信息存入数据库Login login = new Login(UUID.fromString(uuidString));login.setAccount(account);login.setPassword(password);return login;}
}

ManageDbSchema类

package database;public class ManageDbSchema {// Manage表,定义常量public static final class ManageTable {public static final String NAME = "manages";public static final class Cols {public static final String UUID = "uuid";public static final String TITLE = "title";public static final String MONEY = "money";public static final String DATE = "date";public static final String PAYMETHOD = "paymethod";public static final String REMARK = "remark";}}// 账号密码表public static final class ManageTable2 {public static final String NAME2 = "login";public static final class Cols2 {public static final String UUID = "uuid";public static final String ACCOUNT = "account";public static final String PASSWORD = "password";}}}

然后开始编写wengxiaoyang.personalfinanceassistant部分
DatePickerFragment类

package wengxiaoyang.personalfinanceassistant;import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.DatePicker;import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
//记录花销的日期(年月日)
public class DatePickerFragment extends DialogFragment {public static final String EXTRA_DATE = "wengxiaoyang.hziee.criminalintent.date";private static final String ARG_DATE = "date";private DatePicker mDatePicker;public static DatePickerFragment newInstance(Date date) {Bundle args = new Bundle();args.putSerializable(ARG_DATE, date);DatePickerFragment fragment = new DatePickerFragment();fragment.setArguments(args);return fragment;}@NonNull@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {Date date = (Date) getArguments().getSerializable(ARG_DATE);Calendar calendar = Calendar.getInstance();calendar.setTime(date);int year = calendar.get(Calendar.YEAR);int month = calendar.get(Calendar.MONTH);int day = calendar.get(Calendar.DAY_OF_MONTH);View v = LayoutInflater.from(getActivity()).inflate(R.layout.dialog_date, null);mDatePicker = v.findViewById(R.id.dialog_date_picker);mDatePicker.init(year, month, day, null);return new AlertDialog.Builder(getActivity()).setView(v).setTitle(R.string.date_picker_title).setPositiveButton(android.R.string.ok,new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {int year = mDatePicker.getYear();int month = mDatePicker.getMonth();int day = mDatePicker.getDayOfMonth();Date date = new GregorianCalendar(year, month, day).getTime();sendResult(Activity.RESULT_OK, date);}}).create();}private void sendResult(int resultCode, Date date) {if (getTargetFragment() == null) {return;}Intent intent = new Intent();intent.putExtra(EXTRA_DATE, date);getTargetFragment().onActivityResult(getTargetRequestCode(), resultCode,intent);}
}

Login

package wengxiaoyang.personalfinanceassistant;
import java.util.UUID;
public class Login {private UUID mId;private String mAccount;private String mPassword;public Login() {this(UUID.randomUUID());}public Login(UUID id) {mId = id;}public UUID getId() {return mId;}public String getAccount() {return mAccount;}public void setAccount(String account) {mAccount = account;}public String getPassword() {return mPassword;}public void setPassword(String password) {mPassword = password;}}

LoginActivity

package wengxiaoyang.personalfinanceassistant;import android.content.Context;
import android.content.Intent;
import android.support.v4.app.Fragment;public class LoginActivity extends SingleFragmentActivity {@Overrideprotected Fragment createFragment() {return new LoginFragment();}public static Intent newIntent(Context packageContext) {Intent intent = new Intent(packageContext, LoginActivity.class);return intent;}}

LoginFragment

package wengxiaoyang.personalfinanceassistant;import android.support.v4.app.Fragment;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.TargetApi;
import android.content.Intent;import android.os.Build;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;public class LoginFragment extends Fragment {// UIprivate AutoCompleteTextView mEmailView;private EditText mPasswordView;private Button mRegisterButton;private View mProgressView;private View mLoginFormView;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);}//onCreateView是创建该fragment的视图,并返回给调用者。public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {View view = inflater.inflate(R.layout.fragment_login, container, false);// 建立视图mEmailView = (AutoCompleteTextView) view.findViewById(R.id.email);mPasswordView = (EditText) view.findViewById(R.id.password);mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {@Overridepublic boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {//输入密码之后监听哪个按钮的触发if (id == EditorInfo.IME_ACTION_DONE || id == EditorInfo.IME_NULL) {//对应“完成”按钮和回车按钮,说明选择的是登录而不是注册attemptLogin();return true;}return false;}});Button mEmailSignInButton = (Button) view.findViewById(R.id.email_sign_in_button);//登录按钮mEmailSignInButton.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View view) {attemptLogin();}});//设置监听,调用attemplogin方法判断邮箱和密码是否正确mRegisterButton = view.findViewById(R.id.register_button);//注册按钮mRegisterButton.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {//跳转到注册界面Intent intent = new Intent(getActivity(), RegisterActivity.class);startActivity(intent);}});mLoginFormView = view.findViewById(R.id.login_form);mProgressView = view.findViewById(R.id.login_progress);return view;}private void attemptLogin() {//判断邮箱和密码是否能和数据库里面的数据匹配// 重置,不能记住密码mEmailView.setError(null);mPasswordView.setError(null);// 获取登录的信息String email = mEmailView.getText().toString();String password = mPasswordView.getText().toString();boolean cancel = false;View focusView = null;// 校验账号和密码if (login(email, password)) {//调用下面的login方法进行邮箱密码比对,比对在loginlab中进行mEmailView.setError(getString(R.string.error_error_acpw));focusView = mEmailView;cancel = true;//比对不成功则提示报错}if (cancel) {// 聚焦到错误发生地focusView.requestFocus();} else {// 成功登录showProgress(true);// 跳转到ManageListActivityIntent intent = ManageListActivity.newIntent(getActivity());startActivity(intent);}}@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)// 动画private void showProgress(final boolean show) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);mLoginFormView.animate().setDuration(shortAnimTime).alpha(show ? 0 : 1).setListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);}});mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);mProgressView.animate().setDuration(shortAnimTime).alpha(show ? 1 : 0).setListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);}});} else {// 若API不支持,则简单显示mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);}}public boolean login(String account, String password) {//验证此账号密码是否正确Login login = LoginLab.get(getActivity()).getAccountAndPassword(account, password);if (login != null) {return false;} elsereturn true;}
}

LoginLab

package wengxiaoyang.personalfinanceassistant;import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;import java.util.ArrayList;
import java.util.List;
import java.util.UUID;import database.ManageDbSchema.ManageTable2;
import database.ManageCursorWrapper;
import database.ManageBaseHelper;public class LoginLab {private static LoginLab sLoginLab;private Context mContext;private SQLiteDatabase mDatabase;// 构造方法private LoginLab(Context context) {mContext = context.getApplicationContext();mDatabase = new ManageBaseHelper(mContext).getWritableDatabase();//获得可读写操作对象}// 注册界面添加账号密码,创建contentvalues对象,调用mdatabase的insert方法将数据插入到数据库里面public void addLogin(Login l) {ContentValues values = getContentValues(l);mDatabase.insert(ManageTable2.NAME2, null, values);}// 在数据库中找到Login表,也就是table2private ManageCursorWrapper queryLogin(String whereClause, String[] whereArgs) {Cursor cursor = mDatabase.query(ManageTable2.NAME2,null,// null selects all columnswhereClause,whereArgs,null,null,null);return new ManageCursorWrapper(cursor);}// 根据返回的参数cursor,在找到的login表里面再根据账号密码查找对应的用户public Login getAccountAndPassword(String account, String password) {ManageCursorWrapper cursor = queryLogin(ManageTable2.Cols2.ACCOUNT + " = ? and " + ManageTable2.Cols2.PASSWORD+ " = ?",new String[] { account, password });try {if (cursor.getCount() == 0) {//此用户不存在return null;}cursor.moveToFirst();//从表的第一个用户开始查找return cursor.getLogin();} finally {cursor.close();}}// 获得Login数据,后一个参数的值赋给前面的一个参数,返回的login的值进行对比private static ContentValues getContentValues(Login login) {ContentValues values = new ContentValues();values.put(ManageTable2.Cols2.UUID, login.getId().toString());values.put(ManageTable2.Cols2.ACCOUNT, login.getAccount());values.put(ManageTable2.Cols2.PASSWORD, login.getPassword());return values;}// 根据上下文获取LoginLabpublic static LoginLab get(Context context) {if (sLoginLab == null) {sLoginLab = new LoginLab(context);}return sLoginLab;}}

Manage

package wengxiaoyang.personalfinanceassistant;import java.util.Date;
import java.util.UUID;public class Manage {private UUID mId;private String mTitle;private String mMoney;private Date mDate;private int mPayMethod;private String mRemark;public Manage() {this(UUID.randomUUID());}public Manage(UUID id) {mId = id;mDate = new Date();}public UUID getId() {return mId;}public String getTitle() {return mTitle;}public void setTitle(String title) {mTitle = title;}public String getMoney() {return mMoney;}public void setMoney(String money) {mMoney = money;}public Date getDate() {return mDate;}public void setDate(Date date) {mDate = date;}public int getPayMethod() {return mPayMethod;}public void setPayMethod(int payMethod) {mPayMethod = payMethod;}public String getRemark() {return mRemark;}public void setRemark(String remark) {mRemark = remark;}public String getPhotoFilename() {return "IMG_" + getId().toString() + ".jpg";}}

ManageFragment

package wengxiaoyang.personalfinanceassistant;import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.ShareCompat;
import android.support.v4.content.FileProvider;
import android.text.Editable;
import android.text.TextWatcher;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.RadioButton;
import android.widget.RadioGroup;import java.io.File;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
//manager的总布局public class ManageFragment extends Fragment {private static final String ARG_MANAGE_ID = "manage_id";private static final String DIALOG_DATE = "dialogDate";private static final String DIALOG_TIME = "dialogTime";private static final String DIALOG_PHOTO = "dialogPhoto";private static final int REQUEST_DATE = 0;private static final int REQUEST_TIME = 0;private static final int REQUEST_PHOTO = 3;private Manage mManage;private File mPhotoFile;private EditText mTitleField;private EditText mMoneyField;private Button mDateButton;private RadioGroup mRadioGroup;private RadioButton mRadioButton_cash;private RadioButton mRadioButton_card;private EditText mRemarkField;private Button mTimeButton;private Button mReportButton;private ImageButton mPhotoButton;private ImageView mPhotoView;//根据ID创建实例public static ManageFragment newInstance(UUID manageId) {Bundle args = new Bundle();args.putSerializable(ARG_MANAGE_ID, manageId);ManageFragment fragment = new ManageFragment();fragment.setArguments(args);return fragment;}// 保存部分数据@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);UUID manageId = (UUID) getArguments().getSerializable(ARG_MANAGE_ID);mManage = ManageLab.get(getActivity()).getManage(manageId);setHasOptionsMenu(true);mPhotoFile = ManageLab.get(getActivity()).getPhotoFile(mManage);}@Overridepublic void onPause() {super.onPause();// 更新数据库数据ManageLab.get(getActivity()).updateManage(mManage);}// UI@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {View v = inflater.inflate(R.layout.fragment_manage, container, false);// 标题mTitleField = v.findViewById(R.id.manage_title);mTitleField.setText(mManage.getTitle());mTitleField.addTextChangedListener(new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {mManage.setTitle(s.toString());}@Overridepublic void afterTextChanged(Editable s) {}});// 金额mMoneyField = v.findViewById(R.id.manage_money);mMoneyField.setText(mManage.getMoney());mMoneyField.addTextChangedListener(new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {mManage.setMoney(s.toString());}@Overridepublic void afterTextChanged(Editable s) {}});// 日期mDateButton = v.findViewById(R.id.manage_date);Date date = mManage.getDate();updateDate();mDateButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {FragmentManager manager = getFragmentManager();DatePickerFragment dialog = DatePickerFragment.newInstance(mManage.getDate());dialog.setTargetFragment(ManageFragment.this, REQUEST_DATE);dialog.show(manager, DIALOG_DATE);}});// 时间mTimeButton = v.findViewById(R.id.manage_time);String dateString2 = (String) DateFormat.format("h:mm a", date);updateTime(dateString2);mTimeButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {FragmentManager manager = getFragmentManager();TimePickerFragment dialog = TimePickerFragment.newInstance(mManage.getDate());dialog.setTargetFragment(ManageFragment.this, REQUEST_TIME);dialog.show(Objects.requireNonNull(manager), DIALOG_TIME);  //第二个参数是tag}});// 支付方式mRadioGroup = v.findViewById(R.id.manage_pay_method);mRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener(){@Overridepublic void onCheckedChanged(RadioGroup group, int checkedId) {Manage manage = new Manage();switch (checkedId) {case R.id.manage_cash:manage.setPayMethod(1);break;case R.id.manage_card:manage.setPayMethod(2);break;default:break;}}});System.out.println(mManage.getPayMethod());mRadioButton_cash = v.findViewById(R.id.manage_cash);mRadioButton_card = v.findViewById(R.id.manage_card);int PayMethod = mManage.getPayMethod();if (PayMethod == 1) {mRadioButton_cash.setChecked(true);} else if (PayMethod == 2) {mRadioButton_card.setChecked(true);}// 备注mRemarkField = v.findViewById(R.id.manage_remark);mRemarkField.setText(mManage.getRemark());mRemarkField.addTextChangedListener(new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {mManage.setRemark(s.toString());}@Overridepublic void afterTextChanged(Editable s) {}});// 发送报告mReportButton = v.findViewById(R.id.manage_report);mReportButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {ShareCompat.IntentBuilder i = ShareCompat.IntentBuilder.from(getActivity());i.setType("text/plain");i.setText(getManageReport());i.setSubject(getString(R.string.manage_report_subject));i.createChooserIntent();i.startChooser();}});PackageManager packageManager = getActivity().getPackageManager();// 拍照mPhotoButton = v.findViewById(R.id.manage_camera);final Intent captureImage = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);// 如果不能拍照就禁用按钮boolean canTakePhoto = mPhotoFile != null &&captureImage.resolveActivity(packageManager) != null;mPhotoButton.setEnabled(canTakePhoto);// 跳转到相机mPhotoButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Uri uri = FileProvider.getUriForFile(getActivity(),"wengxiaoyang.personalfinanceassistant.fileprovider", mPhotoFile);captureImage.putExtra(MediaStore.EXTRA_OUTPUT, uri);List<ResolveInfo> cameraActivities = getActivity().getPackageManager().queryIntentActivities(captureImage, PackageManager.MATCH_DEFAULT_ONLY);for (ResolveInfo activity : cameraActivities) {getActivity().grantUriPermission(activity.activityInfo.packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);}startActivityForResult(captureImage, REQUEST_PHOTO);}});// 显示照片mPhotoView = v.findViewById(R.id.manage_photo);mPhotoView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (mPhotoFile == null || !mPhotoFile.exists()) {mPhotoView.setImageDrawable(null);} else {FragmentManager manager = getFragmentManager();PhotoDetailFragment dialog = PhotoDetailFragment.newInstance(mPhotoFile);dialog.setTargetFragment(ManageFragment.this, REQUEST_PHOTO);dialog.show(manager, DIALOG_PHOTO);}}});ViewTreeObserver mPhotoObserver = mPhotoView.getViewTreeObserver();mPhotoObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {@Overridepublic void onGlobalLayout() {updatePhotoView(mPhotoView.getWidth(), mPhotoView.getHeight());}});return v;}// 根据需求更新视图@Overridepublic void onActivityResult(int requestCode, int resultCode, Intent data) {if (resultCode != Activity.RESULT_OK) {return;}if (requestCode == REQUEST_DATE) {Date date = (Date) data.getSerializableExtra(DatePickerFragment.EXTRA_DATE);mManage.setDate(date);updateDate();}if (requestCode == REQUEST_TIME) {Date date = mManage.getDate();String dateString2 = (String) DateFormat.format("h:mm a", date);updateTime(dateString2);}else if (requestCode == REQUEST_PHOTO) {Uri uri = FileProvider.getUriForFile(getActivity(),"wengxiaoyang.personalfinanceassistant.fileprovider", mPhotoFile);getActivity().revokeUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);updatePhotoView(mPhotoView.getWidth(), mPhotoView.getHeight());}}// 创建菜单@Overridepublic void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {super.onCreateOptionsMenu(menu, inflater);inflater.inflate(R.menu.fragment_manage, menu);}// 根据选择响应@Overridepublic boolean onOptionsItemSelected(MenuItem item) {switch (item.getItemId()) {case R.id.delete_manage:ManageLab.get(getActivity()).removeManage(mManage);getActivity().finish();return true;case android.R.id.home:     //向上导航时保证子标题可见状态getActivity().finish();return true;default:return super.onOptionsItemSelected(item);}}private void updateDate() {mDateButton.setText(mManage.getDate().toString());}private void updateTime(String s) {mTimeButton.setText(s);}// 发送报告private String getManageReport() {String payString = null;if (mManage.getPayMethod() == 1) {payString = getString(R.string.manage_report_cash);} else if (mManage.getPayMethod() == 2){payString = getString(R.string.manage_report_card);}String dateString = (String) DateFormat.format("EEE, MMM dd, yyyy", mManage.getDate());String report = getString(R.string.manage_report,mManage.getTitle(), dateString, payString, mManage.getRemark());return report;}// 更新照片视图private void updatePhotoView(int width, int height) {if (mPhotoFile == null || !mPhotoFile.exists()) {mPhotoView.setImageDrawable(null);} else {Bitmap bitmap = PictureUtils.getScaledBitmap(mPhotoFile.getPath(), width, height);mPhotoView.setImageBitmap(bitmap);}}}

ManageLab

package wengxiaoyang.personalfinanceassistant;import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;import database.ManageDbSchema.ManageTable;
import database.ManageCursorWrapper;
import database.ManageBaseHelper;
//对每一条记录的操作:增加、删除、修改、查找
public class ManageLab {private static ManageLab sManageLab;private Context mContext;private SQLiteDatabase mDatabase;private ManageLab(Context context) {mContext = context.getApplicationContext();mDatabase = new ManageBaseHelper(mContext).getWritableDatabase();}// 添加记录public void addManage(Manage m) {ContentValues values = getContentValues(m);mDatabase.insert(ManageTable.NAME, null, values);}// 删除记录public void removeManage(Manage c) {String uuidString = c.getId().toString();mDatabase.delete(ManageTable.NAME, ManageTable.Cols.UUID + " = ?", new String[]{uuidString});}// 得到照片public File getPhotoFile(Manage manage) {File filesDir = mContext.getFilesDir();return new File(filesDir, manage.getPhotoFilename());}// 更新记录public void updateManage(Manage manage) {String uuidString = manage.getId().toString();ContentValues values = getContentValues(manage);mDatabase.update(ManageTable.NAME, values, ManageTable.Cols.UUID + " = ?", new String[]{uuidString});}// 查找记录private ManageCursorWrapper queryManages(String whereClause, String[] whereArgs) {Cursor cursor = mDatabase.query(ManageTable.NAME,null,// null selects all columnswhereClause,whereArgs,null,null,null);return new ManageCursorWrapper(cursor);}// 得到Manages集合public List<Manage> getManages() {List<Manage> manages = new ArrayList<>();ManageCursorWrapper cursor = queryManages(null,null);try {cursor.moveToFirst();while (!cursor.isAfterLast()) {manages.add(cursor.getManage());cursor.moveToNext();}}finally {cursor.close();}return manages;}// 根据ID获取Managepublic Manage getManage(UUID id) {ManageCursorWrapper cursor = queryManages(ManageTable.Cols.UUID + " = ?",new String[] { id.toString() });try {if (cursor.getCount() == 0) {return null;}cursor.moveToFirst();return cursor.getManage();} finally {cursor.close();}}// 获得数据库数据private static ContentValues getContentValues(Manage manage) {ContentValues values = new ContentValues();values.put(ManageTable.Cols.UUID, manage.getId().toString());values.put(ManageTable.Cols.TITLE, manage.getTitle());values.put(ManageTable.Cols.MONEY, manage.getMoney());values.put(ManageTable.Cols.DATE, manage.getDate().getTime());values.put(ManageTable.Cols.PAYMETHOD, manage.getPayMethod());values.put(ManageTable.Cols.REMARK, manage.getRemark());return values;}public static ManageLab get(Context context) {if (sManageLab == null) {sManageLab = new ManageLab(context);}return sManageLab;}}

ManageListActivity

package wengxiaoyang.personalfinanceassistant;import android.content.Context;
import android.content.Intent;
import android.support.v4.app.Fragment;public class ManageListActivity extends SingleFragmentActivity {@Overrideprotected Fragment createFragment() {return new ManageListFragment();}public static Intent newIntent(Context packageContext) {Intent intent = new Intent(packageContext, ManageListActivity.class);return intent;}
}

ManageFragment

package wengxiaoyang.personalfinanceassistant;import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
//显示消费记录public class ManageListFragment extends Fragment {private RecyclerView mManageRecyclerView;private ManageAdapter mAdapter;private static int mManageIndex;private boolean mSubtitleVisible;private TextView mNullManageListTextView;private Button mAddManageButton;private static final String SAVED_SUBTITLE_VISIBLE = "subtitle";@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setHasOptionsMenu(true);}// UI@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {View view = inflater.inflate(R.layout.fragment_manage_list, container, false);mManageRecyclerView =  view.findViewById(R.id.manage_recycler_view);mManageRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));mNullManageListTextView = view.findViewById(R.id.null_manage_list);mAddManageButton = view.findViewById(R.id.add_manage);mAddManageButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Manage manage = new Manage();ManageLab.get(getActivity()).addManage(manage);//下面的两个按钮Intent intent = ManagePagerActivity.newIntent(getActivity(), manage.getId());startActivity(intent);}});// 保持记录条数可见if (savedInstanceState != null) {mSubtitleVisible = savedInstanceState.getBoolean(SAVED_SUBTITLE_VISIBLE);}updateUI();return view;}@Overridepublic void onResume() {super.onResume();updateUI();}@Overridepublic void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);outState.putBoolean(SAVED_SUBTITLE_VISIBLE, mSubtitleVisible);}// 创建菜单@Overridepublic void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {super.onCreateOptionsMenu(menu, inflater);inflater.inflate(R.menu.fragment_manage_list, menu);MenuItem subtitleItem = menu.findItem(R.id.show_subtitle);if (mSubtitleVisible) {subtitleItem.setTitle(R.string.hide_subtitle);} else {subtitleItem.setTitle(R.string.show_subtitle);}}// 响应菜单点击@Overridepublic boolean onOptionsItemSelected(MenuItem item) {switch (item.getItemId()) {case R.id.new_manage:   // 创建新记录Manage manage = new Manage();ManageLab.get(getActivity()).addManage(manage);Intent intent = ManagePagerActivity.newIntent(getActivity(), manage.getId());startActivity(intent);return true;case R.id.search_manage:    //搜索intent = SearchActivity.newIntent(getActivity());startActivity(intent);return true;case R.id.statistic_manage: //统计intent = new Intent(getActivity(), StatisticActivity.class);startActivity(intent);return true;case R.id.show_subtitle:    //显示记录条数mSubtitleVisible = !mSubtitleVisible;getActivity().invalidateOptionsMenu();updateSubtitle();return true;default:return super.onOptionsItemSelected(item);}}// 更新记录条数private void updateSubtitle() {ManageLab manageLab = ManageLab.get(getActivity());int manageCount = manageLab.getManages().size();String subtitle = getString(R.string.subtitle_format, manageCount);if (!mSubtitleVisible) {subtitle = null;}AppCompatActivity activity = (AppCompatActivity) getActivity();activity.getSupportActionBar().setSubtitle(subtitle);}// 更新UI界面private void updateUI() {ManageLab manageLab = ManageLab.get(getActivity());List<Manage> manages = manageLab.getManages();if (mAdapter == null) {mAdapter = new ManageAdapter(manages);mManageRecyclerView.setAdapter(mAdapter);} else {//重绘当前可见区域//mAdapter.notifyDataSetChanged();//部分重绘mAdapter.setManages(manages);mAdapter.notifyItemChanged(mManageIndex);}if (manages.size() != 0) {mNullManageListTextView.setVisibility(View.INVISIBLE);mAddManageButton.setVisibility(View.INVISIBLE);} else {mNullManageListTextView.setVisibility(View.VISIBLE);mAddManageButton.setVisibility(View.VISIBLE);}updateSubtitle();}private class ManageHolder extends RecyclerView.ViewHolder implements View.OnClickListener {private TextView mTitleTextView;private TextView mDateTextView;private Manage mManage;public ManageHolder(LayoutInflater inflater, ViewGroup parent) {super(inflater.inflate(R.layout.list_item_manage, parent, false));itemView.setOnClickListener(this);mTitleTextView = itemView.findViewById(R.id.manage_title);mDateTextView = itemView.findViewById(R.id.manage_date);}public void bind(Manage manage) {mManage = manage;mTitleTextView.setText(mManage.getTitle());Date date = manage.getDate();mDateTextView.setText(date.toString());}@Overridepublic void onClick(View view) {Intent intent = ManagePagerActivity.newIntent(getActivity(), mManage.getId());mManageIndex = getAdapterPosition();     //返回数据在adapter中的位置startActivity(intent);}}private class ManageAdapter extends RecyclerView.Adapter {private List<Manage> mManages;public ManageAdapter(List<Manage> manages) {mManages = manages;}//视图类别功能@NonNull@Overridepublic RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {//先建立LayoutInflaterLayoutInflater layoutInflater = LayoutInflater.from(getActivity());return new ManageHolder(layoutInflater, parent);}@Overridepublic void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {Manage manage = mManages.get(position);((ManageHolder)holder).bind(manage);}@Overridepublic int getItemCount() {return mManages.size();}public void setManages(List<Manage> manages) {mManages = manages;}}}

ManagePagerActivity

package wengxiaoyang.personalfinanceassistant;import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;import java.util.List;
import java.util.UUID;
//主页的最下面两个按钮,可依次跳转支出的详情界面,tolast and tofirst
public class ManagePagerActivity extends AppCompatActivity {private static final String EXTRA_MANAGE_ID = "wengxiaoyang.personalfinanceassistant.manage_id";private static final String EXTRA_MANAGE_TITLE = "wengxiaoyang.personalfinanceassistant.manage_title";private ViewPager mViewPager;private List<Manage> mManages;private Button btn_first;private Button btn_last;public static Intent newIntent(Context packageContext, UUID manageId) {Intent intent = new Intent(packageContext, ManagePagerActivity.class);intent.putExtra(EXTRA_MANAGE_ID, manageId);return intent;}public static Intent newIntent(Context packageContext, String title) {Intent intent = new Intent(packageContext, ManagePagerActivity.class);intent.putExtra(EXTRA_MANAGE_TITLE, title);return intent;}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_manage_pager);UUID manageId = (UUID) getIntent().getSerializableExtra(EXTRA_MANAGE_ID);mViewPager = findViewById(R.id.manage_view_pager);// 根据所处位置隐藏按钮mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {if (position == 0) {btn_first.setVisibility(View.INVISIBLE);btn_last.setVisibility(View.VISIBLE);} else if (position == mManages.size() - 1) {btn_first.setVisibility(View.VISIBLE);btn_last.setVisibility(View.INVISIBLE);} else {btn_first.setVisibility(View.VISIBLE);btn_last.setVisibility(View.VISIBLE);}}@Overridepublic void onPageSelected(int i) {}@Overridepublic void onPageScrollStateChanged(int i) {}});btn_first = findViewById(R.id.btn_to_first);btn_first.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mViewPager.setCurrentItem(0);}});btn_last = findViewById(R.id.btn_to_last);btn_last.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mViewPager.setCurrentItem(mManages.size() - 1);}});mManages = ManageLab.get(this).getManages();FragmentManager fragmentManager = getSupportFragmentManager();mViewPager.setAdapter(new FragmentStatePagerAdapter(fragmentManager) {@Overridepublic Fragment getItem(int position) {Manage manage = mManages.get(position);return ManageFragment.newInstance(manage.getId());}@Overridepublic int getCount() {return mManages.size();}});// 给每条记录编号for (int i = 0; i < mManages.size(); i++) {if (mManages.get(i).getId().equals(manageId)) {mViewPager.setCurrentItem(i);break;}}}
}

PhotoDetailFragment

package wengxiaoyang.personalfinanceassistant;import android.app.AlertDialog;
import android.app.Dialog;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;import java.io.File;public class PhotoDetailFragment extends DialogFragment {private static final String ARG_FILE = "file";private ImageView mPhotoView;// 照片细节public static PhotoDetailFragment newInstance(File file) {Bundle args = new Bundle();args.putSerializable(ARG_FILE, file);PhotoDetailFragment fragment =new PhotoDetailFragment();fragment.setArguments(args);return fragment;}// 创建对话框@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {File file = (File) getArguments().getSerializable(ARG_FILE);View v = LayoutInflater.from(getActivity()).inflate(R.layout.dialog_photo, null);mPhotoView = v.findViewById(R.id.manage_photo_detail);Bitmap bitmap = PictureUtils.getScaledBitmap(file.getPath(), getActivity());mPhotoView.setImageBitmap(bitmap);return new AlertDialog.Builder(getActivity()).setView(v).setPositiveButton(android.R.string.ok, null).create();}
}

PictureUtils

package wengxiaoyang.personalfinanceassistant;import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;public class PictureUtils {public static Bitmap getScaledBitmap(String path, int destWidth, int destHeight) {//读入磁盘上图像的尺寸BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeFile(path, options);float srcWidth = options.outWidth;float srcHeight = options.outHeight;//弄清要减少多少int inSampleSize = 1;if (srcHeight > destHeight || srcWidth > destWidth) {float heightScale = srcHeight / destHeight;float widthScale = srcWidth / destWidth;inSampleSize = Math.round(heightScale > widthScale ? heightScale : widthScale);}options = new BitmapFactory.Options();options.inSampleSize = inSampleSize;//读入和创建常量bitmapreturn BitmapFactory.decodeFile(path, options);}public static Bitmap getScaledBitmap(String path, Activity activity) {Point size = new Point();activity.getWindowManager().getDefaultDisplay().getSize(size);return getScaledBitmap(path, size.x, size.y);}
}

RegisterActivity

package wengxiaoyang.personalfinanceassistant;import android.support.v4.app.Fragment;public class RegisterActivity extends SingleFragmentActivity {@Overrideprotected Fragment createFragment() {return new RegisterFragment();}
}

RegisterFragment

package wengxiaoyang.personalfinanceassistant;
//注册界面
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.TargetApi;
import android.content.Intent;import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.support.v4.app.Fragment;public class RegisterFragment extends Fragment {// UIprivate AutoCompleteTextView mEmailView;private EditText mPasswordView;private View mProgressView;private View mLoginFormView;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {// 布局//onCreateView是创建该fragment的视图,并返回给调用者。View view = inflater.inflate(R.layout.fragment_register, container, false);mEmailView = (AutoCompleteTextView) view.findViewById(R.id.email);mPasswordView = (EditText) view.findViewById(R.id.password);mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {@Overridepublic boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {if (id == EditorInfo.IME_ACTION_DONE || id == EditorInfo.IME_NULL) {//输入密码之后监听触发了哪个按钮attemptLogin();return true;}return false;}});Button mEmailSignInButton = (Button) view.findViewById(R.id.email_sign_in_button);//登录按钮mEmailSignInButton.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View view) {attemptLogin();}});mLoginFormView = view.findViewById(R.id.register_form);mProgressView = view.findViewById(R.id.register_progress);return view;}private void attemptLogin() {// 重置错误mEmailView.setError(null);mPasswordView.setError(null);// 获取输入内容String email = mEmailView.getText().toString();String password = mPasswordView.getText().toString();boolean cancel = false;View focusView = null;// 检查密码是否有效if (!TextUtils.isEmpty(password) && !isPasswordValid(password)) {mPasswordView.setError(getString(R.string.error_invalid_password));focusView = mPasswordView;cancel = true;}// 确认有效的邮箱地址if (TextUtils.isEmpty(email)) {mEmailView.setError(getString(R.string.error_field_required));focusView = mEmailView;cancel = true;} else if (!isEmailValid(email)) {mEmailView.setError(getString(R.string.error_invalid_email));focusView = mEmailView;cancel = true;}if (cancel) {// 聚焦到错误发生地focusView.requestFocus();} else {// 成功后showProgress(true);// 将数据添加进数据库Login login = new Login();login.setAccount(email);login.setPassword(password);LoginLab.get(getActivity()).addLogin(login);Intent intent = LoginActivity.newIntent(getActivity());startActivity(intent);}}private boolean isEmailValid(String email) {//邮箱必须有@符号//TODO: Replace this with your own logicreturn email.contains("@");}private boolean isPasswordValid(String password) {//密码太短//TODO: Replace this with your own logicreturn password.length() > 4;}@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)private void showProgress(final boolean show) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);mLoginFormView.animate().setDuration(shortAnimTime).alpha(show ? 0 : 1).setListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);}});mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);mProgressView.animate().setDuration(shortAnimTime).alpha(show ? 1 : 0).setListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);}});} else {// The ViewPropertyAnimator APIs are not available, so simply show// and hide the relevant UI components.mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);}}}

SearchActivity

package wengxiaoyang.personalfinanceassistant;import android.content.Context;
import android.content.Intent;
import android.support.v4.app.Fragment;public class SearchActivity extends SingleFragmentActivity {@Overrideprotected Fragment createFragment() {return new SearchFragment();}public static Intent newIntent(Context packageContext) {Intent intent = new Intent(packageContext, SearchActivity.class);return intent;}}

SearchFragment

package wengxiaoyang.personalfinanceassistant;import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;public class SearchFragment extends Fragment {// UIprivate TextView mTextView;private EditText mSearchView;private Button mSearchButton;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);}public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {// 布局View view = inflater.inflate(R.layout.fragment_search, container, false);mTextView = view.findViewById(R.id.textView_search);mSearchView = (EditText) view.findViewById(R.id.edit_search);mSearchButton  = (Button) view.findViewById(R.id.button_search1);// 跳转到搜索的activitymSearchButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {String search = mSearchView.getText().toString();Intent intent = ManagePagerActivity.newIntent(getActivity(), search);startActivity(intent);}});return view;}
}

SingleFragmentActivity

package wengxiaoyang.personalfinanceassistant;import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;public abstract class SingleFragmentActivity extends AppCompatActivity {protected abstract Fragment createFragment();// 创建fragment@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_fragment);FragmentManager fm = getSupportFragmentManager();Fragment fragment = fm.findFragmentById(R.id.fragment_container);if (fragment == null) {fragment = createFragment();fm.beginTransaction().add(R.id.fragment_container, fragment).commit();}}
}

StatisticActivity

package wengxiaoyang.personalfinanceassistant;import android.support.v4.app.Fragment;public class StatisticActivity extends SingleFragmentActivity {@Overrideprotected Fragment createFragment() {return new StatisticFragment();}}

StatisticFragment

package wengxiaoyang.personalfinanceassistant;import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
//统计年月日的花销总额度
public class StatisticFragment extends Fragment {private EditText mYear;private EditText mMonth;private EditText mDay;private Button mButton;private TextView mMoney;private Double totalMoney = 0.0;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);}public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {// 布局View view = inflater.inflate(R.layout.fragment_statistic, container, false);// 年mYear = view.findViewById(R.id.edit_year);// 月mMonth = view.findViewById(R.id.edit_month);// 日mDay = view.findViewById(R.id.edit_day);mButton = view.findViewById(R.id.button_statistic);mButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 获取输入框内容String year = mYear.getText().toString();String month = mMonth.getText().toString();String day = mDay.getText().toString();// 查找到所有记录List<Manage> manages = ManageLab.get(getActivity()).getManages();// 匹配有相同时间的记录,获得其金额并相加for (int i = 0; i < manages.size(); i++){if (year.equals(manages.get(i).getDate().toString().substring(24,28)) || month.equals(manages.get(i).getDate().toString().substring(4,7)) || day.equals(manages.get(i).getDate().toString().substring(8,10))) {totalMoney += Double.parseDouble(manages.get(i).getMoney());}}mMoney.setText(totalMoney.toString() + "元");totalMoney = 0.0;}});mMoney = view.findViewById(R.id.text_money);return view;}
}

TimePickerFragment

package wengxiaoyang.personalfinanceassistant;import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TimePicker;import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
//支出具体的时间(小时、分钟、秒)
public class TimePickerFragment extends DialogFragment {//两个按钮公用一个EXTRA_DATE,所以不用新添加一个TimePicker专用的RXTRA_TIMEpublic static final String EXTRA_DATE = "wengxiaoyang.hziee.criminalintent.date";private static final String ARG_DATE = "date";private TimePicker mTimePicker;@NonNull@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {Date date = (Date) getArguments().getSerializable(ARG_DATE);final Calendar calendar = Calendar.getInstance();calendar.setTime(date);//不加final的话,GregorianCalendar的构造方法会报错final int year = calendar.get(Calendar.YEAR);final int month = calendar.get(Calendar.MONTH);final int day = calendar.get(Calendar.DAY_OF_MONTH);//时分int hour = calendar.get(Calendar.HOUR_OF_DAY);int minute = calendar.get(Calendar.MINUTE);View v = LayoutInflater.from(getActivity()).inflate(R.layout.dialog_time, null);mTimePicker = v.findViewById(R.id.dialog_time_picker);mTimePicker.setCurrentHour(hour);mTimePicker.setCurrentMinute(minute);return new AlertDialog.Builder(getActivity()).setView(v).setTitle(R.string.date_picker_title).setPositiveButton(android.R.string.ok,new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {int hour = mTimePicker.getCurrentHour();int minute = mTimePicker.getCurrentMinute();Date date = new GregorianCalendar(year, month, day, hour, minute).getTime();sendResult(Activity.RESULT_OK, date);}}).create();}private void sendResult(int resultCode, Date date) {if (getTargetFragment() == null) {return;}Intent intent = new Intent();intent.putExtra(EXTRA_DATE, date);getTargetFragment().onActivityResult(getTargetRequestCode(), resultCode,intent);}public static TimePickerFragment newInstance(Date date) {Bundle args = new Bundle();args.putSerializable(ARG_DATE, date);TimePickerFragment fragment = new TimePickerFragment();fragment.setArguments(args);return fragment;}
}

res部分的drawable
ic_launcher_background.xml(如果源文件里面存在此文件,就可以不要新建)

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="108dp"android:height="108dp"android:viewportWidth="108"android:viewportHeight="108"><pathandroid:fillColor="#008577"android:pathData="M0,0h108v108h-108z" /><pathandroid:fillColor="#00000000"android:pathData="M9,0L9,108"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M19,0L19,108"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M29,0L29,108"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M39,0L39,108"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M49,0L49,108"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M59,0L59,108"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M69,0L69,108"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M79,0L79,108"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M89,0L89,108"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M99,0L99,108"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M0,9L108,9"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M0,19L108,19"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M0,29L108,29"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M0,39L108,39"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M0,49L108,49"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M0,59L108,59"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M0,69L108,69"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M0,79L108,79"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M0,89L108,89"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M0,99L108,99"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M19,29L89,29"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M19,39L89,39"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M19,49L89,49"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M19,59L89,59"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M19,69L89,69"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M19,79L89,79"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M29,19L29,89"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M39,19L39,89"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M49,19L49,89"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M59,19L59,89"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M69,19L69,89"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M79,19L79,89"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" />
</vector>

round_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"><solid android:color="@color/colorPrimary"/><corners android:radius="100dp"/>

round_border.xml

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"><stroke android:color="@color/colorPrimary"android:width="1dp"/><corners android:radius="100dp"/>

接下来是插入的9张可可爱爱的蜡笔小新图片,在drawable文件夹里面添加任意图片,根据个人喜好,添加的方式参考其他博客。
在drawable-anydpi文件夹里面添加以下文件
ic_menu_add.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="24dp"android:height="24dp"android:viewportWidth="24"android:viewportHeight="24"android:tint="#333333"><pathandroid:fillColor="#FF000000"android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>

ic_menu_delete.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="24dp"android:height="24dp"android:viewportWidth="24"android:viewportHeight="24"android:tint="#333333"><pathandroid:fillColor="#FF000000"android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
</vector>

ic_menu_search.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="24dp"android:height="24dp"android:viewportWidth="24"android:viewportHeight="24"android:tint="#333333"><pathandroid:fillColor="#FF000000"android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
</vector>

ic_menu_statistic.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="24dp"android:height="24dp"android:viewportWidth="24"android:viewportHeight="24"android:tint="#333333"><pathandroid:fillColor="#FF000000"android:pathData="M11.8,10.9c-2.27,-0.59 -3,-1.2 -3,-2.15 0,-1.09 1.01,-1.85 2.7,-1.85 1.78,0 2.44,0.85 2.5,2.1h2.21c-0.07,-1.72 -1.12,-3.3 -3.21,-3.81V3h-3v2.16c-1.94,0.42 -3.5,1.68 -3.5,3.61 0,2.31 1.91,3.46 4.7,4.13 2.5,0.6 3,1.48 3,2.41 0,0.69 -0.49,1.79 -2.7,1.79 -2.06,0 -2.87,-0.92 -2.98,-2.1h-2.2c0.12,2.19 1.76,3.42 3.68,3.83V21h3v-2.15c1.95,-0.37 3.5,-1.5 3.5,-3.55 0,-2.84 -2.43,-3.81 -4.7,-4.4z"/>
</vector>

在drawable-v24文件夹添加以下文件
ic_launcher_foreground.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"xmlns:aapt="http://schemas.android.com/aapt"android:width="108dp"android:height="108dp"android:viewportWidth="108"android:viewportHeight="108"><pathandroid:fillType="evenOdd"android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"android:strokeWidth="1"android:strokeColor="#00000000"><aapt:attr name="android:fillColor"><gradientandroid:endX="78.5885"android:endY="90.9159"android:startX="48.7653"android:startY="61.0927"android:type="linear"><itemandroid:color="#44000000"android:offset="0.0" /><itemandroid:color="#00000000"android:offset="1.0" /></gradient></aapt:attr></path><pathandroid:fillColor="#FFFFFF"android:fillType="nonZero"android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"android:strokeWidth="1"android:strokeColor="#00000000" />
</vector>

接下来是layout文件夹,这是前端布局代码,添加以下文件:
activity_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"android:exported="true"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".ManagePagerActivity"><FrameLayoutandroid:id="@+id/fragment_container"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/t10"/>

activity_manage.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".ManageActivity"android:background="@drawable/t10">

activity_manage_pager.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:background="@drawable/t10"><android.support.v4.view.ViewPagerandroid:id="@+id/manage_view_pager"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1" /><FrameLayoutandroid:layout_width="match_parent"android:layout_height="67dp"android:padding="16dp"><Buttonandroid:id="@+id/btn_to_first"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/btn_to_first"android:background="@drawable/round_bg"/><Buttonandroid:id="@+id/btn_to_last"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="end"android:text="@string/btn_to_last"android:background="@drawable/round_bg"/></FrameLayout></LinearLayout>

dialog_date.xml

<?xml version="1.0" encoding="utf-8"?>
<DatePicker xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/dialog_date_picker"android:layout_width="wrap_content"android:layout_height="wrap_content"android:calendarViewShown="true"android:headerBackground="@android:color/holo_blue_bright">
</DatePicker>

dialog_photo.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><ImageViewandroid:id="@+id/manage_photo_detail"android:layout_width="match_parent"android:layout_height="match_parent"/></LinearLayout>

dialog_time.xml

<?xml version="1.0" encoding="utf-8"?>
<TimePicker xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/dialog_time_picker"android:layout_width="wrap_content"android:layout_height="wrap_content"android:calendarViewShown="true"android:timePickerMode="spinner">
</TimePicker>

fragment_login.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center_horizontal"android:orientation="vertical"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingBottom="@dimen/activity_vertical_margin"android:background="@drawable/t8"tools:context=".LoginActivity"><!-- Login progress --><ProgressBarandroid:id="@+id/login_progress"style="?android:attr/progressBarStyleLarge"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginBottom="8dp"android:visibility="gone" /><ScrollViewandroid:id="@+id/login_form"android:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:id="@+id/email_login_form"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><android.support.design.widget.TextInputLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><AutoCompleteTextViewandroid:id="@+id/email"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="@string/prompt_email"android:textColorHint="#000000"android:textColor="#000000"android:inputType="textEmailAddress"android:maxLines="1"android:singleLine="true" /></android.support.design.widget.TextInputLayout><android.support.design.widget.TextInputLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><EditTextandroid:id="@+id/password"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="@string/prompt_password"android:textColor="#000000"android:textColorHint="#000000"android:imeActionId="6"android:imeActionLabel="@string/action_sign_in_short"android:imeOptions="actionUnspecified"android:inputType="textPassword"android:maxLines="1"android:singleLine="true" /></android.support.design.widget.TextInputLayout><Buttonandroid:id="@+id/email_sign_in_button"style="?android:textAppearanceSmall"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="16dp"android:text="@string/action_sign_in"android:background="@drawable/round_bg"android:textStyle="bold" /><Buttonandroid:id="@+id/register_button"style="?android:textAppearanceSmall"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="16dp"android:text="@string/register_button"android:background="@drawable/round_bg"android:textStyle="bold" /></LinearLayout></ScrollView>
</LinearLayout>

fragment_manage.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="16dp"android:background="@drawable/t4"><LinearLayoutandroid:orientation="horizontal"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="16dp"><LinearLayoutandroid:orientation="vertical"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageViewandroid:id="@+id/manage_photo"android:layout_width="80dp"android:layout_height="80dp"android:scaleType="centerInside"android:cropToPadding="true"android:background="@android:color/darker_gray"/><ImageButtonandroid:id="@+id/manage_camera"android:layout_width="match_parent"android:layout_height="wrap_content"android:src="@android:drawable/ic_menu_camera"/></LinearLayout><LinearLayoutandroid:orientation="vertical"android:layout_width="wrap_content"android:layout_height="wrap_content"></LinearLayout><LinearLayoutandroid:orientation="vertical"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:layout_marginStart="10dp"><TextViewstyle="?android:listSeparatorTextViewStyle"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/manage_title_label"android:textColor="#000000"/><EditTextandroid:id="@+id/manage_title"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="@string/manage_title_hint"android:textColorHint="#000000"android:textColor="#000000"/></LinearLayout></LinearLayout><TextViewstyle="?android:listSeparatorTextViewStyle"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/manage_details_money"android:textColor="#000000"/><EditTextandroid:id="@+id/manage_money"android:layout_width="match_parent"android:inputType="numberDecimal"android:layout_height="wrap_content"android:hint="@string/manage_money_hint"android:textColorHint="#000000"android:textColor="#000000"/><TextViewstyle="?android:listSeparatorTextViewStyle"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/manage_details_time"android:textColor="#000000"/><Buttonandroid:id="@+id/manage_date"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/round_bg"/><Buttonandroid:id="@+id/manage_time"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/round_bg"/><TextViewstyle="?android:listSeparatorTextViewStyle"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/manage_details_label"android:textColor="#000000"/><RadioGroupandroid:id="@+id/manage_pay_method"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"><RadioButtonandroid:id="@+id/manage_cash"android:layout_width="match_parent"android:layout_height="wrap_content"android:checked="true"android:text="@string/manage_cash_label"android:textColor="#000000"/><RadioButtonandroid:id="@+id/manage_card"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/manage_card_label"android:textColor="#000000"/></RadioGroup><EditTextandroid:id="@+id/manage_remark"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="@string/manage_remark_label"android:textColor="#000000"android:textColorHint="#000000"/><Buttonandroid:id="@+id/manage_report"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/manage_report_text"/>

fragment_manage_list.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_height="match_parent"android:layout_width="match_parent"android:background="@drawable/t6"><android.support.v7.widget.RecyclerViewandroid:id="@+id/manage_recycler_view"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_alignParentStart="true"android:layout_alignParentTop="true"android:textColor="#000000"android:textSize="30dp" /><TextViewandroid:id="@+id/null_manage_list"style="?android:listSeparatorTextViewStyle"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentTop="true"android:layout_centerHorizontal="true"android:layout_marginTop="280dp"android:text="@string/null_manage_list_text"android:textColor="#000000"android:textSize="20dp" /><Buttonandroid:id="@+id/add_manage"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@+id/null_manage_list"android:layout_marginLeft="32dp"android:layout_marginRight="32dp"android:text="@string/add_manage"android:textColor="#000000"android:textSize="25dp"android:background="@drawable/round_bg"/>
</RelativeLayout>

fragment_register.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center_horizontal"android:orientation="vertical"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingBottom="@dimen/activity_vertical_margin"android:background="@drawable/t4"tools:context=".RegisterActivity"><!-- Login progress --><ProgressBarandroid:id="@+id/register_progress"style="?android:attr/progressBarStyleLarge"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginBottom="8dp"android:visibility="gone" /><ScrollViewandroid:id="@+id/register_form"android:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:id="@+id/email_register_form"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><android.support.design.widget.TextInputLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><AutoCompleteTextViewandroid:id="@+id/email"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="@string/prompt_email"android:textColor="#000000"android:textColorHint="#000000"android:inputType="textEmailAddress"android:maxLines="1"android:singleLine="true" /></android.support.design.widget.TextInputLayout><android.support.design.widget.TextInputLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><EditTextandroid:id="@+id/password"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="@string/prompt_password"android:textColorHint="#000000"android:textColor="#000000"android:imeActionId="6"android:imeActionLabel="@string/action_sign_in_short"android:imeOptions="actionUnspecified"android:inputType="textPassword"android:maxLines="1"android:singleLine="true" /></android.support.design.widget.TextInputLayout><Buttonandroid:id="@+id/email_sign_in_button"style="?android:textAppearanceSmall"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="16dp"android:text="@string/action_register_in"android:background="@drawable/round_bg"android:textStyle="bold" /></LinearLayout></ScrollView>
</LinearLayout>

fragment_search.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:background="@drawable/t7"><TextViewandroid:id="@+id/textView_search"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="@string/search"android:textColor="#000000"android:textSize="30dp" /><EditTextandroid:id="@+id/edit_search"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:hint="@string/edit_search"android:textColor="#000000"android:textSize="20dp"android:textColorHint="#000000"/><Buttonandroid:id="@+id/button_search1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="@string/search"android:textSize="20dp"android:background="@drawable/round_bg"/>

fragment_statistic.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical" android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/t5"><EditTextandroid:id="@+id/edit_year"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:hint="@string/edit_year"android:textColorHint="#000000"android:textColor="#000000"android:textSize="20sp" /><EditTextandroid:id="@+id/edit_month"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:hint="@string/edit_month"android:textColor="#000000"android:textSize="20sp"android:textColorHint="#000000"/><EditTextandroid:id="@+id/edit_day"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:hint="@string/edit_day"android:textColor="#000000"android:textSize="20sp"android:textColorHint="#000000"/><Buttonandroid:id="@+id/button_statistic"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="统计金额"android:textColor="#000000"android:textSize="20dp"android:background="@drawable/round_bg"/><TextViewandroid:id="@+id/text_money"android:layout_width="wrap_content"android:layout_height="wrap_content"android:gravity="center"android:textColor="#000000"android:layout_marginTop="100dp"android:layout_gravity="center"android:textSize="20dp"android:hint="是否超出预算"android:textColorHint="#000000"/></LinearLayout>

list_item_manage.xml

<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/linearLayout"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="8dp"><TextViewandroid:id="@+id/manage_title"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginStart="16dp"android:layout_marginTop="16dp"android:layout_marginEnd="8dp"android:text="@string/item_manage_title"android:textSize="18sp"app:layout_constraintBottom_toTopOf="@+id/manage_date"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintVertical_chainStyle="packed" /><TextViewandroid:id="@+id/manage_date"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginStart="16dp"android:layout_marginTop="8dp"android:layout_marginEnd="8dp"android:text="@string/item_manage_date"android:textColor="#000000"android:textColorHint="#000000"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/manage_title" />

接下来是menu文件夹,添加以下文件:
fragment_manage.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"><itemandroid:id="@+id/delete_manage"android:icon="@drawable/ic_menu_delete"app:showAsAction="ifRoom|withText"android:title="@string/delete_manage" />

fragment_manage_list.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"><itemandroid:id="@+id/new_manage"android:icon="@drawable/ic_menu_add"android:title="@string/new_manage"app:showAsAction="ifRoom|withText" /><itemandroid:id="@+id/search_manage"android:icon="@drawable/ic_menu_search"android:title="@string/search"app:showAsAction="ifRoom|withText" /><itemandroid:id="@+id/statistic_manage"android:icon="@drawable/ic_menu_statistic"android:title="@string/item_statistic"app:showAsAction="ifRoom|withText" /><itemandroid:id="@+id/show_subtitle"android:title="@string/show_subtitle"app:showAsAction="ifRoom" /></menu>

接下来是mipmap-anydpi-v26文件夹,包括以下文件:
ic_launcher.xml

<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"><background android:drawable="@drawable/ic_launcher_background" /><foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

ic_launcher_round.xml

<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"><background android:drawable="@drawable/ic_launcher_background" /><foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

接下来是values文件夹,其包括colors.xml dimens.xml strings.xml styles.xml
colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources><color name="colorPrimary">#0099ff</color><color name="colorPrimaryDark">#0099ff</color><color name="colorAccent">#03dac5</color>
</resources>

dimens.xml

<resources><!-- Default screen margins, per the Android Design guidelines. --><dimen name="activity_horizontal_margin">16dp</dimen><dimen name="activity_vertical_margin">16dp</dimen><dimen name="text_margin">16dp</dimen>
</resources>

strings.xml

<resources><string name="app_name">理财小助手</string><!-- Strings related to login --><string name="prompt_email">邮箱</string><string name="prompt_password">密码</string><string name="action_sign_in">登录</string><string name="action_register_in">注册</string><string name="action_sign_in_short">Sign in</string><string name="error_invalid_email">无效的邮箱地址</string><string name="error_error_acpw">账号或密码错误</string><string name="error_invalid_password">密码太短</string><string name="error_incorrect_password">密码错误</string><string name="error_field_required">必填</string><string name="permission_rationale">"Contacts permissions are needed for providing emailcompletions."</string><string name="manage_title_hint">加一个标题吧</string><string name="manage_title_label">项目名称</string><string name="manage_details_money">金额</string><string name="manage_money_hint">快写上你花了多少钱</string><string name="manage_details_label">支付方式</string><string name="manage_details_time">时间</string><string name="manage_cash_label">现金</string><string name="manage_card_label">银行卡</string><string name="manage_remark_label">备注</string><string name="btn_to_first">To First</string><string name="btn_to_last">To Last</string><string name="date_picker_title">记录日期</string><string name="new_manage">新记录</string><string name="show_subtitle">显示记录条数</string><string name="hide_subtitle">隐藏记录条数</string><string name="subtitle_format">%1$d 条记录</string><string name="delete_manage">删除记录</string><string name="null_manage_list_text">尚未存在理财记录</string><string name="add_manage">添加记录</string><string name="manage_report_text">发送理财报告</string><string name="manage_report">%1$s! 理财在 %2$s. %3$s 和 %4$s发生</string><string name="manage_report_cash">现金支付</string><string name="manage_report_card">信用卡支付</string><string name="manage_report_subject">PersonalFinanceAssistant理财报告</string><string name="send_report">发送理财报告通过: </string><string name="item_manage_title">Manage Title</string><string name="item_manage_date">Manage Date</string><string name="register_button">还没有注册?点我注册</string><string name="search">搜索</string><string name="edit_search">输入你想搜索的内容</string><string name="edit_year">输入年</string><string name="edit_month">输入月</string><string name="edit_day">输入日</string><string name="item_statistic">统计</string>
</resources>

styles.xml

<resources><!-- Base application theme. --><style name="AppTheme" parent="Theme.AppCompat"><!-- Customize your theme here. --><item name="colorPrimary">#000000</item><item name="colorPrimaryDark">#000000</item><item name="colorAccent">#000000</item></style></resources>

接下来是xml文件夹,其中包括了一个文件files.xml
files.xml

<?xml version="1.0" encoding="utf-8"?>
<paths><files-pathname="crime_photos"path="." />
</paths>

清单文件:
AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="wengxiaoyang.personalfinanceassistant"><!-- To auto-complete the email text field in the login form with the user's emails --><uses-permission android:name="android.permission.GET_ACCOUNTS" /><uses-permission android:name="android.permission.READ_PROFILE" /><uses-permission android:name="android.permission.READ_CONTACTS" /><uses-featureandroid:name="android.hardware.camera2"android:required="false" /><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".StatisticActivity"></activity><activity android:name=".SearchActivity" /><activity android:name=".RegisterActivity" /><activityandroid:name=".LoginActivity"android:label="@string/app_name"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><activity android:name=".ManageListActivity" /><activityandroid:name=".ManagePagerActivity"android:parentActivityName=".ManageListActivity" /><providerandroid:name="android.support.v4.content.FileProvider"android:authorities="wengxiaoyang.personalfinanceassistant.fileprovider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/files" /></provider></application></manifest>

最后一个test文件夹
ExampleUnitTest

package wengxiaoyang.personalfinanceassistant;import org.junit.Test;import static org.junit.Assert.*;/*** Example local unit test, which will execute on the development machine (host).** @see <a href="http://d.android.com/tools/testing">Testing documentation</a>*/
public class ExampleUnitTest {@Testpublic void addition_isCorrect() {assertEquals(4, 2 + 2);}
}

怕你们还没有弄清楚,现在将工程目录再进行截图:




最后的java代码不知道为什么会报错,但是程序能够运行,希望大佬知道原因的评论区交流一下。

Android课设——理财小助手相关推荐

  1. 基于Android原生开发的理财小助手APP

    一.实验题目 个人理财小助手 二.实验目的 掌握 SQLite 数据库及其使用. 熟练掌握布局及常用控件 Button.ListView.EditText.TextView 等. 三.总体设计 (含背 ...

  2. Android课设之校园二手交易app

    好了,这学期的Android课设基本完工了,我这次选取的是校园二手交易的主题.好了,相信大家也都等不及了,接下来直接进行演示了.代码已经上传到GitHub上,链接为https://github.com ...

  3. [Android 课设] 一款星座运势查询APP(前言)

    [Android 课设] 一款星座运势查询APP(前言) 前言 熬了几个夜,终于肝完了课设,今天答辩我是第四个,好家伙前面和后面全是大佬,就我一个简简单单连个登录注册都没有的不像APP的APP夹在中间 ...

  4. android 大学生生活助手,基于Android的大学生生活小助手设计与开发.doc

    基于Android的大学生生活小助手设计与开发 基于Android的大学生生活小助手设计与开发 摘要当今社会,大学生受到的社会关注度非常之高,其带来的市场需求和消费能力也一直是各行各业的商家强烈重视的 ...

  5. 在VC中使用ADO开发一款家庭理财小助手软件

    家庭理财小助手(绿色小软件): 此软件可以实现四个功能:1.对家庭月状况进行统计,并可查询之前某月的财务情况,如需查询2010年10月,可输入:201010,点击查询即可:2.对家庭年状况进行统计,如 ...

  6. 基于Android studio的校园小助手app设计

    基于Android的校园小助手系统设计,包含如下主要功能: 校园资讯 校园天气(和风天气api) 外出申请 我的记账本 课程表 考试安排 基于Android studio的校园小助手系统设计

  7. android小助手,基于Android平台的手机小助手的设计与实现

    摘要: 随着移动通信技术和手机软件市场的高速发展,Android智能手机功能也越来越强大,手机管理面临着新的挑战.表现在出现了很多新的问题,诸如手机安全问题.通信安全问题和应用程序管理问题等,矛盾越来 ...

  8. 基于Android平台的疫情小助手APP

    1.选题背景和意义 新型冠状病毒感染的肺炎疫情给人们的身心和生活带来了不利的影响.面对病魔,全国上下团结一心,同舟共济,共同战"疫".疫情小助手APP可以为大家的生活带来便利.疫情 ...

  9. Java课设 2048小游戏

    题目:2048小游戏 目录 1. 引言 2. 主要模块设计 1)游戏面板 2)移动 3)失败 4)新游戏 5)退出 3. 系统实现 1)游戏面板 2)移动 3)失败 4)新游戏 5)退出 4. 结论 ...

最新文章

  1. 使用 FRP 反向代理实现 Windows 远程连接
  2. mysql 存储过程 百万数据 innodb_详解mysql数据库一键查看锁信息(开启InnoDB监控)...
  3. Ubuntu 安装 Sun JDK
  4. POJ - 3922 A simple stone game(K倍博弈-斐波那契博弈进阶)
  5. python 连通域_连通域的原理与Python实现
  6. 计算机科学1pdf,计算机科学导论1.pdf
  7. [QGLViewer]3D场景鼠标点击位置
  8. bootstrap table 主子表 局部数据刷新(刷新子表)
  9. C++新特性探究(9.1):functor仿函数探究
  10. 算法89---图的最小生成树
  11. Dr.Cleaner pro for mac(系统清理和优化软件)
  12. 三句话教你买对房子!买到好房子的都祝福哥三年内赚两个亿!
  13. TensorFlow by Google CNN识别猫和狗 Machine Learning Foundations: Ep #6 - Convolutional cats and dogs
  14. 南京大学计算机考研2022,2022考研策略解读:南京大学计算机专业考研建议与备考指导...
  15. Java 验证码图片不加载处理办法
  16. codeblocks编辑代码输入法光标无法跟随解决方案
  17. 计算机考研落榜了怎么办,一位考研落榜者的自述:考研失败的原因
  18. MATLAB下载时报错原因
  19. php 统计 app 下载量,如何做一个算法估算出一个不定时抓取到一个APP每天的下载量...
  20. 两个led并联和一个电阻串联两个灯不能同时亮问题

热门文章

  1. 【Python零基础入门之终结篇】:虚拟机Linux命令、Vim编辑器、有趣的命令
  2. 2022年甘肃最新初级消防员模拟试题题库及答案
  3. php解压base64编码,php base64编码和urlencode
  4. sql服务器显示error,SQL Server 出现Error: 1326错误(管理器无法连接远程数据库)问...
  5. python下载arcgis地图_互联网地图矢量数据Python获取方法
  6. pat1106 Lowest Price in Supply Chain
  7. java jsp 跳转_JSP 页面跳转的实现方法
  8. [docker]三、docker理论概念(镜像、仓库、容器),用docker运行nginx来搭建一个属于自己网站。查看进程监听哪个端口的命令
  9. 工控主板商用主板的区别及对比
  10. STM32F103学习笔记(6)——4G Cat.1模块EC200S使用