Android安卓实战项目(13)---记账APP详细记录每天的收入和支出并且分类统计【生活助手类APP】强烈推荐自己也在用!!!(源码在文末)
Android安卓实战项目(13)—记账APP详细记录每天的收入和支出并且分类统计【生活助手类APP】强烈推荐自己也在用!!!(源码在文末🐕🐕🐕)
一.项目运行介绍
B站视频链接:
【Android安卓实战项目(13)—记账APP详细记录每天的收入和支出并且分类统计【生活助手类APP】强烈推荐自己也在用!!!(源码在文末🐕🐕🐕)】
https://www.bilibili.com/video/BV1tH4y1Q7kX/?share_source=copy_web&vd_source=b2e9b9ed746acda34f499009647748ed
1.开机动画

2.主页面展示

3.支出记录页面展示

4.收入记录页面展示

5.总交易流程展示

6.显示余额

7.添加备注

二.具体实现
1.MainActivity.java
package com.yuukidach.ucount;import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;import androidx.drawerlayout.widget.DrawerLayout;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.ItemTouchHelper;import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;import com.yuukidach.ucount.view.adapter.BookItemAdapter;
import com.yuukidach.ucount.view.adapter.MoneyItemAdapter;
import com.yuukidach.ucount.callback.BookItemCallback;
import com.yuukidach.ucount.callback.MainItemCallback;
import com.yuukidach.ucount.model.BookItem;
import com.yuukidach.ucount.model.ImgUtils;
import com.yuukidach.ucount.model.MoneyItem;
import com.yuukidach.ucount.presenter.MainPresenter;
import com.yuukidach.ucount.view.MainView;import java.text.DecimalFormat;
import java.util.List;import at.markushi.ui.CircleButton;public class MainActivity extends AppCompatActivity implements MainView {private final ImgUtils imgUtils = new ImgUtils(this);private final MainPresenter mainPresenter = new MainPresenter(this, imgUtils);private Button showBtn;private ImageButton statsBtn;private TextView monthlyCost;private TextView monthlyEarn;private ImageView headerImg;private RecyclerView MoneyItemRecyclerView;// parameter for drawerprivate DrawerLayout drawerLayout;private LinearLayout bookLinearLayout;private RecyclerView bookItemRecyclerView;private ImageView drawerBanner;public static String PACKAGE_NAME;public static Resources resources;public DecimalFormat decimalFormat = new DecimalFormat("0.00");private static final String TAG = "MainActivity";@Overrideprotected void onCreate(Bundle savedInstanceState) {setTheme(R.style.AppTheme);super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 获得包名和资源,方便后面的程序使用PACKAGE_NAME = getApplicationContext().getPackageName();resources = getResources();showBtn = (Button) findViewById(R.id.show_money_button);statsBtn = (ImageButton) findViewById(R.id.stats_button);monthlyCost = (TextView) findViewById(R.id.monthly_cost_money);monthlyEarn = (TextView) findViewById(R.id.monthly_earn_money);headerImg = (ImageView) findViewById(R.id.header_img);CircleButton addBtn = (CircleButton) findViewById(R.id.add_button);ImageButton addBookButton = (ImageButton) findViewById(R.id.add_book_button);MoneyItemRecyclerView = (RecyclerView) findViewById(R.id.in_and_out_items);// drawerdrawerLayout = (DrawerLayout) findViewById(R.id.drawer_of_books);bookItemRecyclerView = (RecyclerView) findViewById(R.id.book_list);bookLinearLayout = (LinearLayout) findViewById(R.id.left_drawer);drawerBanner = (ImageView) findViewById(R.id.drawer_banner);showBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {String str = showBtn.getText().toString();mainPresenter.onShowBalanceClick(str);}});// start activity to add cost or earning itemaddBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {navigateToAddItem();}});// start activity to statisticsstatsBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {navigateToStatistics();}});addBookButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mainPresenter.onAddBookClick();}});// 设置首页header图片长按以更换图片headerImg.setOnLongClickListener(new View.OnLongClickListener() {@Overridepublic boolean onLongClick(View v) {mainPresenter.onImageLongClick(ImageType.HEADER);return false;}});drawerBanner.setOnLongClickListener(new View.OnLongClickListener() {@Overridepublic boolean onLongClick(View v) {mainPresenter.onImageLongClick(ImageType.DRAWER);return false;}});}@Overrideprotected void onResume() {super.onResume();mainPresenter.onResume();}@Overridepublic void onBackPressed() {Intent intent = new Intent(Intent.ACTION_MAIN); // ACTION_MAIN 作为Task中第一个Activity启动intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.addCategory(Intent.CATEGORY_HOME); // CATEGORY_HOME 设备启动时的第一个ActivitystartActivity(intent);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (data == null) return;Uri uri = data.getData();mainPresenter.onActivityResult(uri, requestCode);// get permanent permission to access the imageint takeFlags = data.getFlags()& (Intent.FLAG_GRANT_READ_URI_PERMISSION| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);getContentResolver().takePersistableUriPermission(uri, takeFlags);}@Overridepublic void openPicGallery(ImageType type) {Log.d(TAG, "openPicGallery: " + type.ordinal());Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);intent.setType("image/*");startActivityForResult(intent, type.ordinal());}@Overridepublic void updateHeaderImg(String uriStr) {// If there is no picture in SharedPreferences, then use default pictureif (uriStr.isEmpty()) return;Uri uri = Uri.parse(uriStr);this.headerImg.setImageURI(uri);}@Overridepublic void updateDrawerImg(String uriStr) {// If there is no picture in SharedPreferences, then use default pictureif (uriStr.isEmpty()) return;Uri uri = Uri.parse(uriStr);this.drawerBanner.setImageURI(uri);}@Overridepublic void showBalance(String numStr) {showBtn.setText(numStr);}@Overridepublic void hideBalance() {showBtn.setText(R.string.show_balance);}@Overridepublic void updateMonthlyEarn(String numStr) {monthlyEarn.setText(numStr);}@Overridepublic void updateMonthlyCost(String numStr) {monthlyCost.setText(numStr);}@Overridepublic void navigateToAddItem() {Intent intent = new Intent(MainActivity.this, AddItemActivity.class);Bundle bundle = new Bundle();// tell addItemActivity which book is onbundle.putInt("bookId", mainPresenter.getCurBookId());intent.putExtras(bundle);startActivity(intent);}@Overridepublic void setMainItemRecycler(List<MoneyItem> list) {LinearLayoutManager layoutManager = new LinearLayoutManager(this);layoutManager.setStackFromEnd(true); // show from bottom to toplayoutManager.setReverseLayout(true); // reverse the layoutMoneyItemAdapter moneyItemAdapter = new MoneyItemAdapter(mainPresenter, list);MoneyItemRecyclerView.setAdapter(moneyItemAdapter);MoneyItemRecyclerView.setLayoutManager(layoutManager);ItemTouchHelper ioTouchHelper = new ItemTouchHelper(new MainItemCallback(this, MoneyItemRecyclerView, moneyItemAdapter));ioTouchHelper.attachToRecyclerView(MoneyItemRecyclerView);}@Overridepublic void setBookItemRecycler(List<BookItem> list) {LinearLayoutManager layoutManager = new LinearLayoutManager(this);bookItemRecyclerView.setLayoutManager(layoutManager);bookItemRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));BookItemAdapter bookAdapter = new BookItemAdapter(mainPresenter);bookAdapter.setOnItemClickListener(new BookItemAdapter.OnItemClickListener() {@Overridepublic void onItemClick(View view, int position) {mainPresenter.updateBookItemView(position);drawerLayout.closeDrawer(bookLinearLayout);onResume();}});bookItemRecyclerView.setAdapter(bookAdapter);ItemTouchHelper bookTouchHelper = new ItemTouchHelper(new BookItemCallback(this, bookItemRecyclerView, bookAdapter));bookTouchHelper.attachToRecyclerView(bookItemRecyclerView);}@Overridepublic void setNewBook() {final EditText book_title = new EditText(MainActivity.this);// 弹窗输入AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);builder.setMessage(R.string.new_book_prompt);builder.setView(book_title);builder.setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {if (!book_title.getText().toString().isEmpty()) {mainPresenter.onAddBookConfirmClick(book_title.getText().toString());onResume();} else {// TODO: use strings.xmlToast.makeText(getApplicationContext(), "没有输入新账本名称哦", Toast.LENGTH_SHORT).show();}}}).setNegativeButton(R.string.cancle, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {}}).show();}@Overridepublic void navigateToStatistics() {Intent intent = new Intent(MainActivity.this, StatisticsActivity.class);Bundle bundle = new Bundle();// tell StatisticsActivity which book is onbundle.putInt("bookId", mainPresenter.getCurBookId());intent.putExtras(bundle);startActivity(intent);}
}
-
onCreate方法:
这是活动的主要入口点,在活动创建时调用。在这里,活动的布局文件被加载,界面上的视图元素被初始化,并设置了各种点击事件的监听器。setTheme(R.style.AppTheme):设置活动的主题样式。setContentView(R.layout.activity_main):加载布局文件以显示界面。- 初始化各个视图元素,如
showBtn、statsBtn、monthlyCost等。
-
按钮点击事件:
showBtn.setOnClickListener:设置 “显示余额” 按钮的点击事件监听器。点击按钮会触发onShowBalanceClick方法,该方法会调用mainPresenter的相应方法来处理逻辑。addBtn.setOnClickListener:设置 “添加” 按钮的点击事件监听器。点击按钮会打开一个新的界面以添加记账项。statsBtn.setOnClickListener:设置 “统计” 按钮的点击事件监听器。点击按钮会打开一个统计界面。
-
图片长按事件:
headerImg.setOnLongClickListener:设置头部图片的长按事件监听器。长按图片会触发更换图片的操作。drawerBanner.setOnLongClickListener:设置侧边栏图片的长按事件监听器。长按图片会触发更换侧边栏图片的操作。
-
onResume方法:
当活动从暂停状态恢复时(例如从后台返回前台),onResume方法会被调用。在这里,调用了mainPresenter.onResume(),用于处理活动的恢复逻辑。 -
onBackPressed方法:
当用户按下后退按钮时,该方法会被调用。在这里,创建一个意图以返回到设备的主屏幕。 -
onActivityResult方法:
当从其他活动返回结果时,onActivityResult方法会被调用。在这里,根据返回的数据,调用了mainPresenter的相应方法来处理图片操作。 -
openPicGallery方法:
用于打开图片库以选择图片。 -
图片更新方法:
updateHeaderImg:用于更新头部图片。updateDrawerImg:用于更新侧边栏图片。
-
showBalance和hideBalance方法:
用于显示和隐藏余额。 -
余额和统计信息更新方法:
updateMonthlyEarn:用于更新每月收入信息。updateMonthlyCost:用于更新每月支出信息。
-
导航方法:
navigateToAddItem:用于导航到添加记账项的界面。navigateToStatistics:用于导航到统计界面。
-
setMainItemRecycler和setBookItemRecycler方法:
用于设置记账项列表和账本列表的适配器和布局管理器。 -
setNewBook方法:
弹出对话框,允许用户输入新的账本名称,并在确认后创建一个新账本。
以上是对主要部分的详细解释,这段代码涵盖了Android应用程序中常见的UI交互和逻辑处理。它包含了处理点击事件、图片操作、界面导航以及适配器和布局管理器的使用等内容。
2.AddItemActivity.java
package com.yuukidach.ucount;import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;import com.yuukidach.ucount.model.MoneyItem;
import com.yuukidach.ucount.presenter.AddItemPresenter;
import com.yuukidach.ucount.view.AddItemView;import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Locale;public class AddItemActivity extends AppCompatActivity implements AddItemView {private final int REQUEST_DESCRIPTION = 1;private AddItemPresenter presenter;private static final String TAG = "AddItemActivity";private FragmentManager manager;private FragmentTransaction transaction;private Button addCostBtn;private Button addEarnBtn;private Button clearBtn;private ImageButton addFinishBtn;private ImageButton addDescription;private ImageView bannerImage;private TextView bannerText;private TextView moneyText;private TextView words;private SimpleDateFormat formatItem = new SimpleDateFormat("yyyy年MM月dd日", Locale.CHINA);private SimpleDateFormat formatSum = new SimpleDateFormat("yyyy年MM月", Locale.CHINA);private DecimalFormat decimalFormat = new DecimalFormat("0.00");protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_add_item);addCostBtn = (Button) findViewById(R.id.add_cost_button);addEarnBtn = (Button) findViewById(R.id.add_earn_button);addFinishBtn = (ImageButton) findViewById(R.id.add_finish);addDescription = (ImageButton) findViewById(R.id.add_description);clearBtn = (Button) findViewById(R.id.clear);words = (TextView) findViewById(R.id.anime_words);// 设置字体颜色Typeface typeface = Typeface.createFromAsset(getAssets(), "fonts/chinese_character.ttf");clearBtn.setTypeface(typeface);words.setTypeface(typeface);Bundle bundle = getIntent().getExtras();presenter = new AddItemPresenter(this, bundle.getInt("bookId"));bannerText = (TextView) findViewById(R.id.chosen_title);bannerImage = (ImageView) findViewById(R.id.chosen_image);moneyText = (TextView) findViewById(R.id.input_money_text);presenter.onCreate();addCostBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {presenter.onAddCostButtonClick();}});addEarnBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {presenter.onAddEarnButtonClick();}});addFinishBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {presenter.onAddFinishButtonClick();finish();}});clearBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {presenter.onClearButtonClick();}});addDescription.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {presenter.onDescriptionButtonClick();}});}// 数字输入按钮public void calculatorNumOnclick(View v) {presenter.OnNumPadNumClick(v);}// 小数点处理工作public void calculatorPushDot(View view) {presenter.onNumPadDotClock();}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (requestCode == REQUEST_DESCRIPTION) {if (resultCode == RESULT_OK) {presenter.setDescription(data.getStringExtra(Intent.EXTRA_TEXT));}}}@Overridepublic void highlightEarnButton() {addCostBtn.setTextColor(0xff908070); // set cost button as grayaddEarnBtn.setTextColor(0xffff8c00); // set earn button as orange}@Overridepublic void highlightCostButton() {addEarnBtn.setTextColor(0xff908070); // set earn button as grayaddCostBtn.setTextColor(0xffff8c00); // set cost button as orange}@Overridepublic void setAmount(String numStr) {moneyText.setText(numStr);}@Overridepublic void useEarnFragment() {transaction.replace(R.id.item_fragment, new EarnFragment());}@Overridepublic void useCostFragment() {transaction.replace(R.id.item_fragment, new CostFragment());}@Overridepublic void setupTransaction() {manager = getSupportFragmentManager();beginTransaction();transaction.replace(R.id.item_fragment, new CostFragment());endTransaction();}@Overridepublic void beginTransaction() {transaction = manager.beginTransaction();}@Overridepublic void endTransaction() {transaction.commit();}@Overridepublic String getMoney() {return moneyText.getText().toString();}@Overridepublic void navigateToDescription() {Intent intent = new Intent(AddItemActivity.this, DescriptionActivity.class);Bundle bundle = new Bundle();bundle.putString("description", presenter.getDescription());intent.putExtras(bundle);startActivityForResult(intent, REQUEST_DESCRIPTION);}@Overridepublic void alarmNoMoneyInput() {Toast.makeText(getApplicationContext(),"唔姆,你还没输入金额",Toast.LENGTH_SHORT).show();}@Overridepublic void alarmCanNotContinueToInput() {Toast.makeText(getApplicationContext(), "唔,已经不能继续输入了", Toast.LENGTH_SHORT).show();}@Overridepublic void alarmAlreadyHasDot() {Toast.makeText(getApplicationContext(), "已经输入过小数点了 ━ω━●", Toast.LENGTH_SHORT).show();}@Overridepublic String getTypeName() {return bannerText.getText().toString();}@Overridepublic String getTypeImgResourceName() {return bannerText.getTag().toString();}@Overridepublic MoneyItem.InOutType getInOutFlag() {Log.d(TAG, "getInOutFlag: " + (MoneyItem.InOutType)bannerImage.getTag());return (MoneyItem.InOutType) bannerImage.getTag();}@Overridepublic String getPressedNumPadValue(View view) {Button button = (Button) view;return button.getText().toString();}
}
逐步详细地介绍这段代码:
-
导入必要的类和库:代码一开始通过
import语句导入了许多类,这些类用于构建Android应用界面、处理数据和逻辑等。其中一些重要的类包括android.content.Intent用于活动间的数据传递,androidx.fragment.app.FragmentManager和androidx.fragment.app.FragmentTransaction用于管理Fragment,android.widget.*用于处理各种UI元素,以及自定义的类如com.yuukidach.ucount.model.MoneyItem和com.yuukidach.ucount.presenter.AddItemPresenter。 -
定义常量和变量:在代码中定义了一些常量和实例变量,如
REQUEST_DESCRIPTION是一个用于识别意图的请求代码,AddItemPresenter是一个处理视图和数据之间交互的Presenter,还有各种按钮、图像、文本视图等。 -
设置界面布局:在
onCreate方法中,通过setContentView方法将活动的界面布局设置为 “activity_add_item.xml”。这个布局文件描述了活动的用户界面,定义了各种UI元素的位置和交互方式。 -
初始化UI元素:接下来,通过
findViewById方法获取在布局文件中定义的各种UI元素,如按钮、图像、文本视图等。然后对这些UI元素进行一些设置,例如:setTypeface方法用于为按钮设置自定义字体样式,增加了一些视觉效果。setTextColor方法用于设置按钮文本的颜色,以区分不同的按钮状态。
-
获取传递的数据:通过
getIntent().getExtras()获取从前一个活动传递过来的额外数据,这里通过键名 “bookId” 获取一个整数值,然后用这个值初始化了AddItemPresenter。 -
设置按钮点击事件:通过监听按钮的点击事件,为按钮添加了点击响应的逻辑。例如,
addCostBtn按钮点击时会调用presenter.onAddCostButtonClick()方法。 -
实现接口方法:这个活动实现了一个接口
AddItemView,这个接口定义了一系列用于与Presenter交互的方法。这些方法用于更新界面、处理用户输入等操作。 -
其他方法:代码中还有一些其他方法,用于处理数字输入、小数点操作、启动其他活动、显示提示信息等。
总之,这段代码实现了一个用于记录金钱交易的Android活动。它通过获取用户输入、点击按钮、调用Presenter等方式,交互地在界面上显示交易细节,并将数据传递给Presenter进行进一步处理。
3.StatisticsActivity.java
package com.yuukidach.ucount;import android.database.Cursor;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;import androidx.appcompat.app.AppCompatActivity;import com.github.mikephil.charting.charts.PieChart;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.data.PieData;
import com.github.mikephil.charting.data.PieDataSet;
import com.github.mikephil.charting.data.PieEntry;
import com.yuukidach.ucount.model.MoneyItem;
import com.yuukidach.ucount.presenter.StatisticsPresenter;
import com.yuukidach.ucount.view.StatisticsView;import org.litepal.LitePal;import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;public class StatisticsActivity extends AppCompatActivity implements StatisticsView {private static final String TAG = "StatisticsActivity";private StatisticsPresenter presenter;private TextView selectText;private Calendar calendar;private String yearMonth;private SimpleDateFormat fmtYM;private final int[] PIE_COLORS={Color.rgb(181, 194, 202), Color.rgb(129, 216, 200), Color.rgb(241, 214, 145),Color.rgb(108, 176, 223), Color.rgb(195, 221, 155), Color.rgb(251, 215, 191),Color.rgb(237, 189, 189), Color.rgb(172, 217, 243)};protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_statistics);ImageButton prevBtn = (ImageButton) findViewById(R.id.prev_month);ImageButton nextBtn = (ImageButton) findViewById(R.id.next_month);selectText = (TextView) findViewById(R.id.selected_month);Bundle bundle = getIntent().getExtras();presenter = new StatisticsPresenter(this, bundle.getInt("bookId"));presenter.onCreate();fmtYM = new SimpleDateFormat("yyyy-MM", Locale.getDefault());calendar = Calendar.getInstance();yearMonth = fmtYM.format(calendar.getTime());selectText.setText(yearMonth);Log.d("calendar", "format:"+ yearMonth);drawPieChart();prevBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {presenter.onPrevButtonClick();}});nextBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {presenter.onNextButtonClick();}});}@Overridepublic void prevMonth() {calendar.add(Calendar.MONTH, -1);yearMonth = fmtYM.format(calendar.getTime());Log.d("calendar", "format:"+ fmtYM.format(calendar.getTime()));selectText.setText(yearMonth);}@Overridepublic void nextMonth() {calendar.add(Calendar.MONTH, 1);yearMonth = fmtYM.format(calendar.getTime());Log.d("calendar", "format:"+ fmtYM.format(calendar.getTime()));selectText.setText(yearMonth);}@Overridepublic void selectMonth() {}@Overridepublic void drawPieChart() {PieChart chart_cost = (PieChart) findViewById(R.id.chart_cost);PieChart chart_earn = (PieChart) findViewById(R.id.chart_earn);List<PieEntry> entries_cost = new ArrayList<PieEntry>();List<PieEntry> entries_earn = new ArrayList<PieEntry>();Cursor cursor_cost = LitePal.findBySQL("select sum(money),typename from MoneyItem " +"where bookId = ? and " +"inOutType = ? and " +"date like ? " +"group by typename", String.valueOf(presenter.getBookId()), MoneyItem.InOutType.COST.toString(), yearMonth+"%");Cursor cursor_earn = LitePal.findBySQL("select sum(money),typename from MoneyItem " +"where bookId = ? and " +"inOutType = ? and " +"date like ? " +"group by typename", String.valueOf(presenter.getBookId()), MoneyItem.InOutType.EARN.toString(), yearMonth+"%");if (cursor_cost != null && cursor_cost.moveToFirst()) {do {Log.d("database", "#######"+cursor_cost.getString(1)+"########");Log.d("database", "#######"+cursor_cost.getDouble(0)+"########");entries_cost.add(new PieEntry((float) cursor_cost.getDouble(cursor_cost.getColumnIndex("sum(money)")),cursor_cost.getString(cursor_cost.getColumnIndex("typename"))));} while (cursor_cost.moveToNext());}if (cursor_earn != null && cursor_earn.moveToFirst()) {do {Log.d("database", "#######"+cursor_earn.getString(1)+"########");Log.d("database", "#######"+cursor_earn.getDouble(0)+"########");entries_earn.add(new PieEntry((float) cursor_earn.getDouble(cursor_earn.getColumnIndex("sum(money)")),cursor_earn.getString(cursor_earn.getColumnIndex("typename"))));} while (cursor_earn.moveToNext());}PieDataSet dataSet_cost = new PieDataSet(entries_cost, "");dataSet_cost.setColors(PIE_COLORS);dataSet_cost.setValueLinePart1OffsetPercentage(60f);dataSet_cost.setYValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);dataSet_cost.setValueLinePart1Length(0.4f);dataSet_cost.setValueLinePart2Length(0.4f);PieData pieData_cost = new PieData(dataSet_cost);pieData_cost.setValueTextSize(18f);Legend l = chart_cost.getLegend();l.setTextSize(15f);l.setFormSize(12f);l.setXEntrySpace(10f);chart_cost.setData(pieData_cost);chart_cost.getDescription().setText("");chart_cost.setExtraOffsets(10f, 0, 10f, 0);chart_cost.setEntryLabelColor(0xff000000);chart_cost.setEntryLabelTextSize(15f);chart_cost.invalidate();PieDataSet dataSet_earn = new PieDataSet(entries_earn, "");dataSet_earn.setColors(PIE_COLORS);dataSet_earn.setValueLinePart1OffsetPercentage(60f);dataSet_earn.setYValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);dataSet_earn.setValueLinePart1Length(0.4f);dataSet_earn.setValueLinePart2Length(0.4f);PieData pieData_earn = new PieData(dataSet_earn);pieData_earn.setValueTextSize(18f);l = chart_earn.getLegend();l.setTextSize(15f);l.setFormSize(12f);l.setXEntrySpace(10f);chart_earn.setData(pieData_earn);chart_earn.getDescription().setText("");chart_earn.setExtraOffsets(10f, 0, 10f, 0);chart_earn.setEntryLabelColor(0xff000000);chart_earn.setEntryLabelTextSize(15f);chart_earn.invalidate();}
}
这段代码是一个名为 “StatisticsActivity” 的 Android 应用程序组件,主要用于展示统计数据并绘制饼状图。我将逐步解释代码的各个部分:
-
导入包和库:
- 代码开始处导入了必要的 Android 类和第三方库,用于在应用中使用图表和数据库功能。
-
类定义和成员变量:
StatisticsActivity类继承自AppCompatActivity,表示这是一个与界面交互的 Activity。- 成员变量包括
TAG(用于日志输出)、presenter(用于处理界面逻辑和数据交互)、selectText(用于显示所选月份)、calendar(用于日期计算)、yearMonth(表示所选年月字符串)、fmtYM(日期格式化工具)以及PIE_COLORS(饼图颜色数组)等。
-
onCreate 方法:
- 这是 Activity 的生命周期方法,会在创建时调用。
- 设置布局和获取界面元素的引用。
- 通过
getIntent().getExtras()获取从上一个 Activity 传递的参数,并用该参数初始化presenter。 - 初始化日期格式化工具和当前日期,并在界面上显示。
- 调用
drawPieChart方法绘制饼图。 - 为前进和后退按钮设置点击监听器,用于在不同月份之间切换。
-
接口方法的实现(
StatisticsView接口的实现):prevMonth():向前切换一个月份,更新日期并在界面上显示。nextMonth():向后切换一个月份,更新日期并在界面上显示。selectMonth():暂时空实现,用于选择月份。drawPieChart():绘制两个饼图,分别用于显示支出和收入的数据。
-
绘制饼图方法
drawPieChart:- 获取两个
PieChart控件的引用,分别表示支出和收入饼图。 - 通过 SQL 查询从数据库中获取特定月份、特定账本和特定类型(支出或收入)的数据,然后将查询结果存储到
entries_cost和entries_earn列表中。 - 创建
PieDataSet对象,并将查询结果添加到数据集中。 - 配置数据集的样式、值的位置等参数。
- 创建
PieData对象,并设置数据集。 - 配置图例的样式,然后将数据集绑定到饼图控件上并刷新显示。
- 获取两个
三.项目源码
链接:https://pan.baidu.com/s/1wlzPw6kJV_4kSHv-lQPyVw
提取码:****
创作不易,项目已加密,有偿(仅一杯奶茶钱,可做实验报告,代码讲解等…)
请私信作者或
(v)15135757306
相关文章:
Android安卓实战项目(13)---记账APP详细记录每天的收入和支出并且分类统计【生活助手类APP】强烈推荐自己也在用!!!(源码在文末)
Android安卓实战项目(13)—记账APP详细记录每天的收入和支出并且分类统计【生活助手类APP】强烈推荐自己也在用!!!(源码在文末🐕🐕🐕) 一.项目运行介绍 B站…...
嵌入式开发之syslog和rsyslog构建日志记录
1.syslogd作客户端 BusyBox v1.20.2 (2022-04-06 16:19:14 CST) multi-call binary.Usage: syslogd [OPTIONS]System logging utility-n Run in foreground-O FILE Log to FILE (default:/var/log/messages)-l N Log only messages more urge…...
Jaeger的经典BUG原创
前端,笔者在使用Jaeger进行Trace监控的时候,当数据量增大到一定数量级时,出现了一次CPU暴增导致节点服务器挂了的经典案例,这里对案例进行一个简单的抽象,供大家参考: 首先通过pprof对耗时的函数进行定位&…...
四款简洁好看 自适应的APP下载单页源码
分享四款简洁好看 自适应的APP下载单页源码,采用了底部自动获取ICP备案号,还有蓝奏云文件直链解析。不光可以做APP下载引导页,也可以随便改下按钮做网站引导页,自由发挥即可! 蓝奏云直链解析的好处:APP放在…...
【服务器】交换机带外管理和带内管理
一、交换机的带外管理是什么? 在带外管理模式中,网络的管理控制信息与用户网络的承载业务信息在不同的逻辑信道传送。 带外管理最大的优势在于,当网络出现故障中断时数据传输和管理都可以正常进行——不同的物理通道传送管理控制信息和数据…...
Kotlin的内置函数 apply、let、run、with、also
let 1.let函数返回类型,是根据匿名函数的最后一行变化而变化 2.let函数中的匿名函数里面持有的是it 集合自身 fun main() {var num1 1var num2 1var result:Intresult num1 num2var str result?.let {//传入本身,it指代本身即result,result不为空…...
2023年人工景点行业研究报告
第一章 行业概况 1.1 定义及分类 人工景点行业通常指的是设计和构建的为提供娱乐、教育或文化体验的景点。这些景点可能包括主题公园,博物馆,动物园,水族馆,科学中心,历史遗迹,艺术展览等。这个行业通常包…...
react轮播图
这里 我用的是组件: 网址:Collapse 折叠面板 - Ant Design Mobile 1.首先 先声明一个变量 2、把需要的数据存存进去 3、组件内容复制过来(这里用到的是map循环) 然后图片就出来了 就是这个简单 哈哈哈哈!!…...
Openlayers 叠加天地图-中国近海海洋等深面图层服务
Openlayers 叠加天地图-中国近海海洋等深面图层服务 核心代码完整代码:在线示例 偶然发现天地图有一个近海海洋图层,觉得不错,于是尝试叠加一下,花费了一些时间,叠加成功,这里分享一下。 本文包括核心代码…...
uniapp移动端h5设计稿还原
思路 动态设置html的font-size大小 实现步骤 先创建一个public.css文件,设置初始的font-size大小 /* 注意这样写 只能使用css文件, scss 是不支持的, setProperty 只适用于原生css上 */ html {--gobal-font-size: 0.45px; } .gobal-font-size {font-size: var(--g…...
后端数据配置相对路径,前端添加网站根 URL (根路径)- js获取网站项目根路径- 获取根路径后的第一个斜杠前 / 的项目- - 判断url包含某字符串
1、js获取网站项目根路径 js获取项目根路径,如下: 原 http://localhost:8080/testproject/test.html 根路径:http://localhost:8080 function getRootPath(){//获取当前网址,// 如: http://localhost:8080/testpro…...
deepspeed多机多卡并行训练指南
文章目录 前言离线配置训练环境共享文件系统多台服务器之间配置互相免密登录pdsh多卡训练可能会碰到的问题注意总结 前言 我的配置: 7机14卡,每台服务器两张A800 问:为啥每台机只挂两张卡? 答:给我的就这样的&#…...
9.Redis-zset
zset zset 有序集合 -> 升序常用命令zaddzcardzcountzrangezrevrange -> reverse 逆序zrangebyscorezpopmaxzpopminbzpopmax / bzpopminzrankzrevrankzscorezremzremrangebyrankzremrangebyscorezincrby集合间操作zinter -> 交集zunion -> 并集zdiff -> 差集zin…...
云计算的三个主要服务模型:IaaS、PaaS 和 SaaS
文章目录 介绍基础设施即服务(Infrastructure as a Service,IaaS)平台即服务(Platform as a Service,PaaS)软件即服务(Software as a Service,SaaS) 区别基础设施即服务&…...
spring ioc,DI,AOP概述
Spring是一个轻量级的Java开发框架。其中,IoC、DI和AOP是Spring框架的核心概念。 IoC(Inversion of Control,控制反转):IoC是一种设计模式,是指将对象的创建、管理和控制权交给IoC容器,由IoC容器…...
meethigher-Apache Poi 实现Excel多级联动下拉框
由于最近做的功能,需要将接口返回的数据列表,输出到excel中,以供后续导入,且网上现有的封装,使用起来都较为麻烦,故参考已有做法封装了工具类。 使用apache poi实现excel联动下拉框思路 创建隐藏单元格&a…...
基于食肉植物算法优化的BP神经网络(预测应用) - 附代码
基于食肉植物算法优化的BP神经网络(预测应用) - 附代码 文章目录 基于食肉植物算法优化的BP神经网络(预测应用) - 附代码1.数据介绍2.食肉植物优化BP神经网络2.1 BP神经网络参数设置2.2 食肉植物算法应用 4.测试结果:5…...
FFDNet-pytorch版本代码训练教程
一、FFDNet-pytorch版本代码下载 (1)FFDNet-pytorch下载 https://download.csdn.net/download/qq_41104871/88233742 (2)FFDNet-pytorch版本代码运行环境配置 https://blog.csdn.net/qq_41104871/article/details/132497008 二、FFDNet-pytorch版本代码训练教程 (1)按…...
C语言练习7(巩固提升)
C语言练习7 编程题 前言 “芳林新叶催陈叶,流水前波让后波。”改革开放40年来,我们以敢闯敢干的勇气和自我革新的担当,闯出了一条新路、好路,实现了从“赶上时代”到“引领时代”的伟大跨越。今天,我们要不忘初心、牢记…...
golangORM框架Gorm
ORM框架Gorm gorm简介gorm声明模型gorm连接到数据库gorm创建记录gorm查询记录gorm高级查询gorm更新gorm删除SQL 构建器gorm Belongs To关系gorm Has One关系gorm Has Many关系gorm Many To Many关系gorm 实体关联gorm 会话gorm事务Gorm总结...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...
离线语音识别方案分析
随着人工智能技术的不断发展,语音识别技术也得到了广泛的应用,从智能家居到车载系统,语音识别正在改变我们与设备的交互方式。尤其是离线语音识别,由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力,广…...
热烈祝贺埃文科技正式加入可信数据空间发展联盟
2025年4月29日,在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上,可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞,强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...
