当前位置: 首页 > news >正文

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.开机动画

image-20230831113445313

2.主页面展示

image-20230831113437029

3.支出记录页面展示

image-20230831113336101

4.收入记录页面展示

image-20230831113324643

5.总交易流程展示

image-20230831113456028

6.显示余额

image-20230831113317352

7.添加备注

image-20230831113540790

二.具体实现

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);}
}
  1. onCreate 方法:
    这是活动的主要入口点,在活动创建时调用。在这里,活动的布局文件被加载,界面上的视图元素被初始化,并设置了各种点击事件的监听器。

    • setTheme(R.style.AppTheme):设置活动的主题样式。
    • setContentView(R.layout.activity_main):加载布局文件以显示界面。
    • 初始化各个视图元素,如 showBtnstatsBtnmonthlyCost 等。
  2. 按钮点击事件:

    • showBtn.setOnClickListener:设置 “显示余额” 按钮的点击事件监听器。点击按钮会触发 onShowBalanceClick 方法,该方法会调用 mainPresenter 的相应方法来处理逻辑。
    • addBtn.setOnClickListener:设置 “添加” 按钮的点击事件监听器。点击按钮会打开一个新的界面以添加记账项。
    • statsBtn.setOnClickListener:设置 “统计” 按钮的点击事件监听器。点击按钮会打开一个统计界面。
  3. 图片长按事件:

    • headerImg.setOnLongClickListener:设置头部图片的长按事件监听器。长按图片会触发更换图片的操作。
    • drawerBanner.setOnLongClickListener:设置侧边栏图片的长按事件监听器。长按图片会触发更换侧边栏图片的操作。
  4. onResume 方法:
    当活动从暂停状态恢复时(例如从后台返回前台),onResume 方法会被调用。在这里,调用了 mainPresenter.onResume(),用于处理活动的恢复逻辑。

  5. onBackPressed 方法:
    当用户按下后退按钮时,该方法会被调用。在这里,创建一个意图以返回到设备的主屏幕。

  6. onActivityResult 方法:
    当从其他活动返回结果时,onActivityResult 方法会被调用。在这里,根据返回的数据,调用了 mainPresenter 的相应方法来处理图片操作。

  7. openPicGallery 方法:
    用于打开图片库以选择图片。

  8. 图片更新方法:

    • updateHeaderImg:用于更新头部图片。
    • updateDrawerImg:用于更新侧边栏图片。
  9. showBalancehideBalance 方法:
    用于显示和隐藏余额。

  10. 余额和统计信息更新方法:

    • updateMonthlyEarn:用于更新每月收入信息。
    • updateMonthlyCost:用于更新每月支出信息。
  11. 导航方法:

    • navigateToAddItem:用于导航到添加记账项的界面。
    • navigateToStatistics:用于导航到统计界面。
  12. setMainItemRecyclersetBookItemRecycler 方法:
    用于设置记账项列表和账本列表的适配器和布局管理器。

  13. 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();}
}

逐步详细地介绍这段代码:

  1. 导入必要的类和库:代码一开始通过 import 语句导入了许多类,这些类用于构建Android应用界面、处理数据和逻辑等。其中一些重要的类包括 android.content.Intent 用于活动间的数据传递,androidx.fragment.app.FragmentManagerandroidx.fragment.app.FragmentTransaction 用于管理Fragment,android.widget.* 用于处理各种UI元素,以及自定义的类如 com.yuukidach.ucount.model.MoneyItemcom.yuukidach.ucount.presenter.AddItemPresenter

  2. 定义常量和变量:在代码中定义了一些常量和实例变量,如 REQUEST_DESCRIPTION 是一个用于识别意图的请求代码,AddItemPresenter 是一个处理视图和数据之间交互的Presenter,还有各种按钮、图像、文本视图等。

  3. 设置界面布局:在 onCreate 方法中,通过 setContentView 方法将活动的界面布局设置为 “activity_add_item.xml”。这个布局文件描述了活动的用户界面,定义了各种UI元素的位置和交互方式。

  4. 初始化UI元素:接下来,通过 findViewById 方法获取在布局文件中定义的各种UI元素,如按钮、图像、文本视图等。然后对这些UI元素进行一些设置,例如:

    • setTypeface 方法用于为按钮设置自定义字体样式,增加了一些视觉效果。
    • setTextColor 方法用于设置按钮文本的颜色,以区分不同的按钮状态。
  5. 获取传递的数据:通过 getIntent().getExtras() 获取从前一个活动传递过来的额外数据,这里通过键名 “bookId” 获取一个整数值,然后用这个值初始化了 AddItemPresenter

  6. 设置按钮点击事件:通过监听按钮的点击事件,为按钮添加了点击响应的逻辑。例如,addCostBtn 按钮点击时会调用 presenter.onAddCostButtonClick() 方法。

  7. 实现接口方法:这个活动实现了一个接口 AddItemView,这个接口定义了一系列用于与Presenter交互的方法。这些方法用于更新界面、处理用户输入等操作。

  8. 其他方法:代码中还有一些其他方法,用于处理数字输入、小数点操作、启动其他活动、显示提示信息等。

总之,这段代码实现了一个用于记录金钱交易的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 应用程序组件,主要用于展示统计数据并绘制饼状图。我将逐步解释代码的各个部分:

  1. 导入包和库

    • 代码开始处导入了必要的 Android 类和第三方库,用于在应用中使用图表和数据库功能。
  2. 类定义和成员变量

    • StatisticsActivity 类继承自 AppCompatActivity,表示这是一个与界面交互的 Activity。
    • 成员变量包括 TAG(用于日志输出)、presenter(用于处理界面逻辑和数据交互)、selectText(用于显示所选月份)、calendar(用于日期计算)、yearMonth(表示所选年月字符串)、fmtYM(日期格式化工具)以及 PIE_COLORS(饼图颜色数组)等。
  3. onCreate 方法

    • 这是 Activity 的生命周期方法,会在创建时调用。
    • 设置布局和获取界面元素的引用。
    • 通过 getIntent().getExtras() 获取从上一个 Activity 传递的参数,并用该参数初始化 presenter
    • 初始化日期格式化工具和当前日期,并在界面上显示。
    • 调用 drawPieChart 方法绘制饼图。
    • 为前进和后退按钮设置点击监听器,用于在不同月份之间切换。
  4. 接口方法的实现StatisticsView 接口的实现):

    • prevMonth():向前切换一个月份,更新日期并在界面上显示。
    • nextMonth():向后切换一个月份,更新日期并在界面上显示。
    • selectMonth():暂时空实现,用于选择月份。
    • drawPieChart():绘制两个饼图,分别用于显示支出和收入的数据。
  5. 绘制饼图方法 drawPieChart

    • 获取两个 PieChart 控件的引用,分别表示支出和收入饼图。
    • 通过 SQL 查询从数据库中获取特定月份、特定账本和特定类型(支出或收入)的数据,然后将查询结果存储到 entries_costentries_earn 列表中。
    • 创建 PieDataSet 对象,并将查询结果添加到数据集中。
    • 配置数据集的样式、值的位置等参数。
    • 创建 PieData 对象,并设置数据集。
    • 配置图例的样式,然后将数据集绑定到饼图控件上并刷新显示。


三.项目源码

链接:https://pan.baidu.com/s/1wlzPw6kJV_4kSHv-lQPyVw
提取码:****

创作不易,项目已加密,有偿(仅一杯奶茶钱,可做实验报告,代码讲解等…)

请私信作者或

(v)15135757306

相关文章:

Android安卓实战项目(13)---记账APP详细记录每天的收入和支出并且分类统计【生活助手类APP】强烈推荐自己也在用!!!(源码在文末)

Android安卓实战项目&#xff08;13&#xff09;—记账APP详细记录每天的收入和支出并且分类统计【生活助手类APP】强烈推荐自己也在用&#xff01;&#xff01;&#xff01;&#xff08;源码在文末&#x1f415;&#x1f415;&#x1f415;&#xff09; 一.项目运行介绍 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原创

前端&#xff0c;笔者在使用Jaeger进行Trace监控的时候&#xff0c;当数据量增大到一定数量级时&#xff0c;出现了一次CPU暴增导致节点服务器挂了的经典案例&#xff0c;这里对案例进行一个简单的抽象&#xff0c;供大家参考&#xff1a; 首先通过pprof对耗时的函数进行定位&…...

四款简洁好看 自适应的APP下载单页源码

分享四款简洁好看 自适应的APP下载单页源码&#xff0c;采用了底部自动获取ICP备案号&#xff0c;还有蓝奏云文件直链解析。不光可以做APP下载引导页&#xff0c;也可以随便改下按钮做网站引导页&#xff0c;自由发挥即可&#xff01; 蓝奏云直链解析的好处&#xff1a;APP放在…...

【服务器】交换机带外管理和带内管理

一、交换机的带外管理是什么&#xff1f; 在带外管理模式中&#xff0c;网络的管理控制信息与用户网络的承载业务信息在不同的逻辑信道传送。 带外管理最大的优势在于&#xff0c;当网络出现故障中断时数据传输和管理都可以正常进行——不同的物理通道传送管理控制信息和数据…...

Kotlin的内置函数 apply、let、run、with、also

let 1.let函数返回类型&#xff0c;是根据匿名函数的最后一行变化而变化 2.let函数中的匿名函数里面持有的是it 集合自身 fun main() {var num1 1var num2 1var result:Intresult num1 num2var str result?.let {//传入本身&#xff0c;it指代本身即result,result不为空…...

2023年人工景点行业研究报告

第一章 行业概况 1.1 定义及分类 人工景点行业通常指的是设计和构建的为提供娱乐、教育或文化体验的景点。这些景点可能包括主题公园&#xff0c;博物馆&#xff0c;动物园&#xff0c;水族馆&#xff0c;科学中心&#xff0c;历史遗迹&#xff0c;艺术展览等。这个行业通常包…...

react轮播图

这里 我用的是组件&#xff1a; 网址&#xff1a;Collapse 折叠面板 - Ant Design Mobile 1.首先 先声明一个变量 2、把需要的数据存存进去 3、组件内容复制过来&#xff08;这里用到的是map循环&#xff09; 然后图片就出来了 就是这个简单 哈哈哈哈&#xff01;&#xff01…...

Openlayers 叠加天地图-中国近海海洋等深面图层服务

Openlayers 叠加天地图-中国近海海洋等深面图层服务 核心代码完整代码&#xff1a;在线示例 偶然发现天地图有一个近海海洋图层&#xff0c;觉得不错&#xff0c;于是尝试叠加一下&#xff0c;花费了一些时间&#xff0c;叠加成功&#xff0c;这里分享一下。 本文包括核心代码…...

uniapp移动端h5设计稿还原

思路 动态设置html的font-size大小 实现步骤 先创建一个public.css文件&#xff0c;设置初始的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获取项目根路径&#xff0c;如下&#xff1a; 原 http://localhost:8080/testproject/test.html 根路径&#xff1a;http://localhost:8080 function getRootPath(){//获取当前网址&#xff0c;// 如&#xff1a; http://localhost:8080/testpro…...

deepspeed多机多卡并行训练指南

文章目录 前言离线配置训练环境共享文件系统多台服务器之间配置互相免密登录pdsh多卡训练可能会碰到的问题注意总结 前言 我的配置&#xff1a; 7机14卡&#xff0c;每台服务器两张A800 问&#xff1a;为啥每台机只挂两张卡&#xff1f; 答&#xff1a;给我的就这样的&#…...

9.Redis-zset

zset zset 有序集合 -> 升序常用命令zaddzcardzcountzrangezrevrange -> reverse 逆序zrangebyscorezpopmaxzpopminbzpopmax / bzpopminzrankzrevrankzscorezremzremrangebyrankzremrangebyscorezincrby集合间操作zinter -> 交集zunion -> 并集zdiff -> 差集zin…...

云计算的三个主要服务模型:IaaS、PaaS 和 SaaS

文章目录 介绍基础设施即服务&#xff08;Infrastructure as a Service&#xff0c;IaaS&#xff09;平台即服务&#xff08;Platform as a Service&#xff0c;PaaS&#xff09;软件即服务&#xff08;Software as a Service&#xff0c;SaaS&#xff09; 区别基础设施即服务&…...

spring ioc,DI,AOP概述

Spring是一个轻量级的Java开发框架。其中&#xff0c;IoC、DI和AOP是Spring框架的核心概念。 IoC&#xff08;Inversion of Control&#xff0c;控制反转&#xff09;&#xff1a;IoC是一种设计模式&#xff0c;是指将对象的创建、管理和控制权交给IoC容器&#xff0c;由IoC容器…...

meethigher-Apache Poi 实现Excel多级联动下拉框

由于最近做的功能&#xff0c;需要将接口返回的数据列表&#xff0c;输出到excel中&#xff0c;以供后续导入&#xff0c;且网上现有的封装&#xff0c;使用起来都较为麻烦&#xff0c;故参考已有做法封装了工具类。 使用apache poi实现excel联动下拉框思路 创建隐藏单元格&a…...

基于食肉植物算法优化的BP神经网络(预测应用) - 附代码

基于食肉植物算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码 文章目录 基于食肉植物算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码1.数据介绍2.食肉植物优化BP神经网络2.1 BP神经网络参数设置2.2 食肉植物算法应用 4.测试结果&#xff1a;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 编程题 前言 “芳林新叶催陈叶&#xff0c;流水前波让后波。”改革开放40年来&#xff0c;我们以敢闯敢干的勇气和自我革新的担当&#xff0c;闯出了一条新路、好路&#xff0c;实现了从“赶上时代”到“引领时代”的伟大跨越。今天&#xff0c;我们要不忘初心、牢记…...

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总结...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

C# 表达式和运算符(求值顺序)

求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如&#xff0c;已知表达式3*52&#xff0c;依照子表达式的求值顺序&#xff0c;有两种可能的结果&#xff0c;如图9-3所示。 如果乘法先执行&#xff0c;结果是17。如果5…...

Python 训练营打卡 Day 47

注意力热力图可视化 在day 46代码的基础上&#xff0c;对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...

yaml读取写入常见错误 (‘cannot represent an object‘, 117)

错误一&#xff1a;yaml.representer.RepresenterError: (‘cannot represent an object’, 117) 出现这个问题一直没找到原因&#xff0c;后面把yaml.safe_dump直接替换成yaml.dump&#xff0c;确实能保存&#xff0c;但出现乱码&#xff1a; 放弃yaml.dump&#xff0c;又切…...

基于开源AI智能名片链动2 + 1模式S2B2C商城小程序的沉浸式体验营销研究

摘要&#xff1a;在消费市场竞争日益激烈的当下&#xff0c;传统体验营销方式存在诸多局限。本文聚焦开源AI智能名片链动2 1模式S2B2C商城小程序&#xff0c;探讨其在沉浸式体验营销中的应用。通过对比传统品鉴、工厂参观等初级体验方式&#xff0c;分析沉浸式体验的优势与价值…...

webpack面试题

面试题&#xff1a;webpack介绍和简单使用 一、webpack&#xff08;模块化打包工具&#xff09;1. webpack是把项目当作一个整体&#xff0c;通过给定的一个主文件&#xff0c;webpack将从这个主文件开始找到你项目当中的所有依赖文件&#xff0c;使用loaders来处理它们&#x…...