宅宅记账——基于AI的智能记账软件(Android Studio)

研究背景和意义

        随着社会的发展,人们的消费水平有了明显提高,消费理念也发生了一定变化。合理的消费理念对于构建社会主义和谐社会具有十分重要的意义。大学生作为消费群体的重要组成部分,他们的消费行为对大学生全面发展和社会和谐具有深远的影响。而在大学生活中,学生们往往会有着收支账单的记录、储存等需求,从而更好的规划自己的资金使用情况。但是,在市面中并没有一个完全适合当代大学生使用的App。为此,宅宅记账孕育而生。为方便用户使用本产品为目的,从而编写本产品使用说明书,本产品免费面向广泛群众使用,主要面向大学生使用。

        由于大学生在同龄人中是知识文化水平较高,思想道德素质相对较好的群体,因而在同龄人中就会具有表率和示范作用。重视大学生消费观,正确引导大学生的消费心理和消费行为,不仅有益于大学生的健康成长,而且对社会消费行为及消费观的正确引导,也必将起到良好的示范作用。

        大学生的消费观与人生观、价值观紧密相联,如果我们不重视新时期大学生消费心理的研究,不去探讨大学生消费观的变化及其规律,将不利于大学生的成长。本文就大学生消费偏高的原因做出分析,力求找到应对大学生消费偏高的对策。近几年来,我国的社会生产力获得了长足的发展,城乡面貌发生了巨大变化,由此也使得人们的消费观发生了很大变化。这些变化必然直接或间接地涉及到高校校园,产生了广泛而深刻的影响。大学生作为社会成员的一个重要群体,其消费结构被社会广泛关注。

        随着社会的发展,人们的消费水平有了明显提高,消费理念也发生了一定变化。合理的消费理念对于构建社会主义和谐社会具有十分重要的意义。大学生作为消费群体的重要组成部分,他们的消费行为对大学生全面发展和社会和谐具有深远的影响。80+后、甚至90+已长大成人、走进高等学府,他们的学费、生活费基本由家庭负担。他们互相攀比,除吃喝外,还穿名牌,利用节假日出游等。当然,生活水平的提高是社会进步的标志之一。,但如果超过一定限度,则会带来负面影响。消费结构是衡量消费特性的重要指标,大学生这一特殊群体的消费结构尤应引起公众关注。大学生是当前消费主体之一,也是未来中国消费的主力和消费潮流的引导者,其消费方式将深刻影响未来中国的消费方式。21世纪的大学生不仅应该具有良好的政治思想素质、扎实的专业素质和优秀的职业道德素质,而且应该具有高超的理财素质。然而由于理财教育的欠缺,导致了大学生在消费方面存在着许多问题,这样势必影响以后的工作和生活。大学生消费偏高也已经成为一个热门话题。

国外研究:

        国外发达国家的记账软件系统起步较早,并已经运用于社会多个领域,如医疗、器械、银行等。祁迅速发展实在微处理器出现后的80和90年代。以医疗方向为例:在80和90年以微处理器为核心 的智能仪器(如自动生化分析仪、血球计数器、免疫分析仪等等)不断进入临床实验室,大大的提高了工作效率和样本检测精度,推动了临床实验室的自动化进程,为实现临床检测数据的实时性存储和传输,相关的医疗记录系统孕育而生(HIS)。虽然国外经过长时间的有关记账系统的发展,很大程度上促进了医疗、军事、工业等大规模的发展,但是却忽视了有关国民日常生活实用方向的发展,据不完全统计,国外有关民用记账软件系统不足市场需求的百分之6.5。

国内研究:

        相对于国外发展情况,我国有关记账软件系统的起步较晚,且多为民间自主开发,规模较小,且面临着很多社会问题。很多居民担心其信息泄露等问题的出现,这也直接限制了国内有关记账系统的发展。同时,就目前分析,我国有关记账APP市场有着巨大缺口。当前市场所拥有的记账APP有着功能单一、广告过多、收费过高等一系列缺点。

应用现状:

(1)市场规模逐年递增:近几年来,我国财务及企业管理软件的市场规模呈逐年快速递增状态。 由于服务产业的应用需求和跨行业的应用需求, 企业应用软件市场是未来一段时间增长最快的市场。 随着我国企业信息化的加速、 效益的突显,软件市场将实现迅速增长。

(2)国内财务软件仍有较大市场:目前,有相当的国有企业、事业单位等使用了计算机代替手工记账, 而国有企业在我国国民经济中占主导地位, 所以仅国有企业、事业单位就为我国的财务软件提供了巨大的市场。

(3)软件品牌更集中:我国财务及企业管理软件市场经过多年发展,整个市场已经从刚开始的好汉纷争, 走到了诸侯割据的状态, 进入了全国性品牌一同天下的市场格局。目前,主要集中在用友、金蝶和安易三大品牌上,其中,用友发展迅猛。因此,财务软件应积极对应,抓住机遇,迎接挑战,寻求和扩展发展空间。 这是企业规模优势和品牌修饰在市场竞争中的反映, 也说明整个市场更加成熟。

(4)中国的财务软件市场上国内品牌具有绝对优势:虽然国内品牌厂商占这一领域市场份额的 95%, 但是还有不少企业因找不到合适的财务软件而委托财务软件公司或自行开发, 这对于国内财务软件是损失了一部分市场。 我国境内的外资、 盒子、 国外驻华机构及少数国内有实力的企业, 他们购买使用的是价格远远高于国内品牌的国外产品,这也是国内财务软件公司不能忽视的问题。

(5)财务及企业管理软件领域产品创新加快:自从 1998 年 6 月,全国 8家主要财务软件企业在北京宣布全面向企业管理软件进军, 财务软件与企业管理软件的发展密切相联系,加快了品牌创新;出现了“数字化管理”、 “管理型财务软件”、“决策型财务软件”、“全能管理软件”和“全能 ERP软件”等。但是与发达国家相比,我国财务软件水平较低

(6)多角度,全方位的进行合理推广,进行广告植入等多种手段,在APP端,网页端,小程序端进行信息宣传,进一步加深用户对产品的全面认识,在项目管理趋于成熟完整的状态下可以进一步加深通信领域内对于本产品的工程实践,完善项目关于通信原理上的应用。

课题研究的主要内容:

        本项目可做到记录支出和收入的记账功能,首先数据采集端有:APP采集、网页采集两种方式。即可以通过手机端和网页端进行账号的注册登录,在注册账号后,将账号密码等数据上传到云端服务器进行记录备份。在此之后,为解决相关图片账单核对等问题,拥有关于账单的专属图片识别技术。在记账功能方面,可以做到根据支出手段选择记录,如:微信,支付宝,银行卡等。同时,根据相似的原理,记录收入情况,并且提供备注功能。以上两个功能可以将数据传至云端之后,通过数据采集做到实时同步。本项目的优点和独特点在于,在提供收支记录的情况下,同时提供聊天室功能,可以在群聊天室内进行沟通交流,支持录音和上传照片的功能,更加方便账务核对以及收支情况。同时提供有关发票、单票等的图像识别功能,帮助用户快速识别记录。 

需求分析

        目前大学生之间存在借钱、带饭、收支记录等问题,很多时候我们没有一个有效的方便的记录工具,虽然一两顿饭钱并不会有多大影响。但是,积少成多,这就表明,大学生之间对记账APP的强烈需求。与此同时,很多大学生出现月末资金不足的情况,这就表明很多大学生对自己的花钱多少没有一个很清晰的概念和记录。与此同时,很多时候很多花销需要找社团、组织等地方报销,这时,需要提供发票依据,为以防出现突发情况,急需自动识别功能的出现。为解决以上多个问题,宅宅记账应运而生。

总体设计思路:

        首先进行数据采集,即APP接受信息和网页接受信息两种方式,。通过将接收的信息进行相关处理与拟合,分为云端和本地两种处理方式。针对本地存储,主要为应对网络不佳或者无网络连接时进行手机本地的账单记录处理;而相对于本地处理,云端则是为了进行正常的数据存储,同时作为开拓功能,增加账单批量处理的功能。之后针对数据处理后的信息数据进行应用集成处理,分为四个模块。针对本地存储数据,可进行本地账单以及备忘录的数据处理与记录;而针对云端则分别是IM即时通信应用、图像数字读取应用、语句情感分析应用三个应用集成模块。其中IM即时通信主要是为用户提供跨平台的聊天服务区;而图像数字读取方面主要是为进行账单的批量处理;语句情感分析是提供人性化智能化的AI语句情感判断回馈工作。

系统整体功能模块   

本产品主要分为三大模块,分别为网络层、技术层以及应用层。

 宅宅记账——基于AI的智能记账软件(Android Studio)_第1张图片

宅宅记账——基于AI的智能记账软件(Android Studio)_第2张图片

技术路线:   

        关于网络层层面,本项目主要运用阿里云轻量服务器、百度智能云预计环信IM即时通信,通过飞桨AI大数据训练模型对本项目中的图像识别功能进行训练,运用websocket,全方位的训练模型。通过进行宝塔部署,内置CentOS7.9.2009系统完成数据库的云端搭建,以保障和完成实时数据和信息的传递,同时通过环信IM即时通信实现文字交互、语音交互以及图像交互的实现与运用。

        关于技术层层面,通过建立两大模块分细化做工。第一模块为只能AI模块,通过判断接受信息的不同,关于发票、单据等图片信息,直接进行账单识别功能的运用;如果为语言信息或文字信息,则会对其进行情感分析,通过Paddlehub模块,将接收的信息进行分析,之后再通过智能AI回复Chatbot()模块记性相应的智能回复,最后将数据回传,进行消息的反诉。而对于记账算法模块,则通过相应流程,完成相对任务。实现流程如下:

宅宅记账——基于AI的智能记账软件(Android Studio)_第3张图片

        而关于应用层面,通过模块化的利用数据的交汇完成数据的自由性选择,根据用户的不同使用类别,提供自由化的数据记录。创新性的应用于人性化处理,面向解决实际性问题,在此之上,本项目通过进行理性化的数据交汇、信息共享平台的搭建、实时信息的交汇、信息实时化采集与储存,很好的满足了大部分客户的需求。与此同时注重隐私化设置以及精细化舒菊初,通过及时的通信反馈、机器学习的数据分析和机器学习的功能化体现,出色的完成了不同客户的特性化要求。 

项目设计制约因素

        工具类APP未来发展的趋势,如果要单纯从功能收费来说,很难盈利,要保证这个市场的正常运行,可行的办法还是精准化广告的投入。和相关的领域的产品达成合作,既提高广告的变现作用又能降低用户对于广告的反感程度。与此同时,由于本项目存在网页端和手机App的信息接收功能,因此可能会被某不法分子以非法手段窃取用户信息,因此安全性以及隐私性的保障也是至关重要的。如若不对现有安全技术进行实时性的更新与提升,未来将很难在市场中立足,这也是制约本项目发展的缘由之一。

 图像识别分割:

from aip import AipOcr
from pathlib import Path
import cv2 as cv
from time import sleep
import openpyxl


wb = openpyxl.Workbook()
sheet = wb.active
sheet.append(['消费', '商品', '支付时间', '支付方式', '交易单号', '商品单号'])

APP_ID = ''
API_KEY = ''
SECRET_KEY = ''

client = AipOcr(APP_ID, API_KEY, SECRET_KEY)
def get_file_content(filePath):
    with open(filePath, 'rb') as fp:
        return fp.read()

def identity(num):
    result_list = []
    for i in range(num):
        image = get_file_content('img{}.jpg'.format(i))
 
        result = client.basicAccurate(image)
        print(result)
        sleep(1)

        info = ''.join([i['words'] for i in result['words_result']])
        result_list.append(info)

    result_list[2] = result_list[2] + ' ' + result_list[3]
    result_list.pop(3)
    print(result_list)
    sheet.append(result_list)

p = Path(r'D:\OCR\img')

file = p.glob('**/*.jpg')
for img_file in file:
    img_file = str(img_file)
    src = cv.imread(r'{}'.format(img_file))
    src = cv.resize(src, None, fx=0.5, fy=0.5)
    # print(src.shape)
    img = src[260:850, 0:580]        
    money = img[70:130, 150:450]     
    goods = img[260:330, 140:560]    
    time_1 = img[380:425, 160:292]       
 time_2 = img[380:425, 290:390]    
    way = img[430:475, 160:560]       
    num_1 = img[480:520, 160:560]    
    num_2 = img[525:570, 160:560]     
    img_list = [money, goods, time_1, time_2, way, num_1, num_2]
    for index_, item in enumerate(img_list):
        cv.imwrite(f'img{index_}.jpg', item)
    identity(len(img_list))
    # cv.imshow('img', img)
    # cv.imshow('goods', time_2)
    # cv.waitKey(0)

wb.save(filename='识别账单结果.xlsx')

 情感分析:

import paddlehub as hub

# 加载模型
senta = hub.Module(name = "senta_lstm")

# 待分类文本
test_text = ["大概就是因为无聊吧", "非常高兴","不想说什么了,听首歌吧","我从你身上感受到了这个世界的参差","错的不是我,是这个世界"]

# 情感分类
results = senta.sentiment_classify(data={"text":test_text})

# 得到结果
for result in results:
    print(result)

机器训练:

from chatterbot import ChatBot
from chatterbot.trainers import ListTrainer

Chinese_bot = ChatBot("Training demo") 
trainer = ListTrainer(Chinese_bot)
trainer.train([
    '在吗?',
    '亲,在呢',
    '鞋按正常尺码买吗?',
    '是呢,请放心下单吧。',
    '有43码的吗?',
    '暂时没有哦。',
])
question="在吗?"
print(question)
response=Chinese_bot.get_response(question)
print(response)
print("\n")

机器案例:

from chatterbot import ChatBot
from chatterbot.trainers import ListTrainer

Chinese_bot = ChatBot("Training demo")
while(1):
 question=input()
 print(question)
 response=Chinese_bot.get_response(question)
 print(response)
 print("\n")

自动回复机器人训练:

from chatterbot import ChatBot
from chatterbot.trainers import ChatterBotCorpusTrainer
bot = ChatBot(
    'Xjw',
    storage_adapter='chatterbot.storage.MongoDatabaseAdapter'
)


def r(s):return bot.get_response(s).text

while True:
    i = input('>>> ').strip()
    if i != 'exit':
        print(r(i))
    else:
        break

from chatterbot import ChatBot
from chatterbot.trainers import ChatterBotCorpusTrainer

bot = ChatBot(
    'Xjw',
    storage_adapter='chatterbot.storage.MongoDatabaseAdapter'
)
trainer = ChatterBotCorpusTrainer(bot)
trainer.train("chatterbot.corpus.chinese")
trainer.train("chatterbot.corpus.english")

移动终端开发模块(核心):

package com.example.zhaizhaijizhang.login;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import  android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.os.Handler;
import android.os.Message;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.text.SimpleDateFormat;
import java.util.Date;



import com.example.zhaizhaijizhang.MainActivity;
import com.example.zhaizhaijizhang.R;
import com.example.zhaizhaijizhang.util.AnalysisUtils;
import com.example.zhaizhaijizhang.util.MD5Utils;


public class LoginActivity extends Activity {

    private TextView tv_main_title;
    private TextView tv_back;
    private TextView tv_register;
    private Button bt_login;
    private EditText et_user_name, et_pwd;
    private String username, pwd, spPwd;
    private CheckBox cb_remeberme;
    private boolean IsChecked = false;
    private SharedPreferences sps;
    private String USERNAME = "USER_NAME";
    private String PWD = "PWD";
    private String IS_CHECKED = "IS_CHECKED";
    public static String mUsername ;
    private RelativeLayout rl_title_bar;
    private  Thread thread;
    private Handler handler;
    private TextView tvTime;
     private SimpleDateFormat sdf;
     private boolean runing;
    private TextView Tv1;
    private Button Btn1;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        //设置此界面为竖屏
        tvTime = findViewById(R.id.tv_1);
        sdf = new SimpleDateFormat("hh:mm:ss");
        sdf = new SimpleDateFormat("hh:mm:ss");
        handler = new Handler(){
             @Override
            public void handleMessage(Message msg) {
                                 super.handleMessage(msg);
                               if(msg.what == 1){
                                         tvTime.setText(sdf.format(new Date()));
                                   }
                            }
        };

                thread = new Thread(new Runnable() {
            @Override
             public void run() {
                                 while (true){

                                         handler.sendEmptyMessage(1);

                                         try {
                                                Thread.sleep(500);
                                             } catch (InterruptedException e) {
                                                 e.printStackTrace();
                                             }
                                     }
                             }
         });

                 thread.start();




        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

        init();

        initDate();
    }

    private void init() {


        tv_register = (TextView) findViewById(R.id.tv_register);
        bt_login = (Button) findViewById(R.id.btn_login);
        et_user_name = (EditText) findViewById(R.id.et_user_name);
        et_pwd = (EditText) findViewById(R.id.et_pwd);
        cb_remeberme = (CheckBox) findViewById(R.id.cb_remeberme);


        tv_main_title = (TextView) findViewById(R.id.tv_main_title);
        tv_main_title.setText("登录");
//        tv_main_title.setBackgroundColor(Color.argb(0,0,0,0));//透明
        rl_title_bar = (RelativeLayout) findViewById(R.id.title_bar);
        rl_title_bar.setBackgroundColor(Color.TRANSPARENT);

        tv_back = (TextView) findViewById(R.id.tv_back);
        tv_back.setVisibility(View.GONE);


        tv_register.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                Intent intent = new Intent(LoginActivity.this, RegisterActivity.class);
                startActivityForResult(intent, 1);
            }
        });


        bt_login.setOnClickListener(new View.OnClickListener() {


            @Override
            public void onClick(View arg0) {
                username = et_user_name.getText().toString().trim();
                pwd = et_pwd.getText().toString().trim();
                String md5Pwd = MD5Utils.MD5(pwd);
                spPwd = readPwd(username);
                if (TextUtils.isEmpty(username)) {
                    Toast.makeText(LoginActivity.this, "请输入用户名", Toast.LENGTH_SHORT).show();
                    return;
                } else if (TextUtils.isEmpty(pwd)) {
                    Toast.makeText(LoginActivity.this, "请输入密码", Toast.LENGTH_SHORT).show();
                    return;
                } else if (md5Pwd.equals(spPwd)) {
                    Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show();

                    saveLoginStatus(true, username);

                    Intent data = new Intent();
                    data.putExtra("isLogin", true);
                    setResult(RESULT_OK, data);
                    LoginActivity.this.finish();
                    startActivity(new Intent(LoginActivity.this, MainActivity.class));
                    return;
                } else if ((!TextUtils.isEmpty(spPwd) && !md5Pwd.equals(spPwd))) {
                    Toast.makeText(LoginActivity.this, "用户名或密码错误", Toast.LENGTH_SHORT).show();
                    return;
                } else {
                    Toast.makeText(LoginActivity.this, "此用户不存在", Toast.LENGTH_SHORT).show();
                }
            }
        });



        cb_remeberme.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                if (IsChecked) {
                    if (sps == null) {
                        sps = getApplicationContext().getSharedPreferences("config", Context.MODE_PRIVATE);
                    }

                    SharedPreferences.Editor editor = sps.edit();

                    editor.putString(USERNAME, et_user_name.getText().toString());
                    editor.commit();
                }
            }
        });

        et_pwd.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }


         @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }


            @Override
            public void afterTextChanged(Editable s) {
                if (IsChecked) {
                    if (sps == null) {
                        sps = getApplicationContext().getSharedPreferences("config", Context.MODE_PRIVATE);
                    }

                    SharedPreferences.Editor editor = sps.edit();

                    editor.putString(PWD, et_pwd.getText().toString());
                    editor.commit();
                }

            }
        });

        cb_remeberme.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                IsChecked = isChecked;
                if (isChecked) {

                    if (sps == null) {
                        sps = getApplicationContext().getSharedPreferences("config", Context.MODE_PRIVATE);
                    }

                    SharedPreferences.Editor editor = sps.edit();

                    editor.putString(USERNAME, et_user_name.getText().toString());
                    editor.putString(PWD, et_pwd.getText().toString());

                    editor.putBoolean(IS_CHECKED, isChecked);
                    Toast.makeText(LoginActivity.this, "已记住密码:" + isChecked, Toast.LENGTH_SHORT).show();

                    editor.commit();
                } else {

                    SharedPreferences.Editor editor = sps.edit();

                    editor.putString(USERNAME, null);
                    editor.putString(PWD, null);

                    editor.putBoolean(IS_CHECKED, isChecked);
                    Toast.makeText(LoginActivity.this, "取消记住密码:" + isChecked, Toast.LENGTH_SHORT).show();

                    editor.commit();
                }
            }
        });
    }


    private String readPwd(String username) {
        SharedPreferences sp = getSharedPreferences("loginInfo", MODE_PRIVATE);
        return sp.getString(username, "");
    }


    private void saveLoginStatus(boolean status, String username) {
        this.mUsername = username;

        SharedPreferences sp = getSharedPreferences("loginInfo", MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.putBoolean("isLogin", status);
        editor.putString("loginUserName", username);
        editor.commit();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode,
                                    Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (data != null) {

            String username = data.getStringExtra("username");
            if (!TextUtils.isEmpty(username)) {
                et_user_name.setText(username);

                et_user_name.setSelection(username.length());
            }
        }
    }


    private void initDate() {
        if (sps == null) {
            sps = getApplicationContext().getSharedPreferences("config", Context.MODE_PRIVATE);
        }

        et_user_name.setText(sps.getString(USERNAME, ""));
        et_pwd.setText(sps.getString(PWD, ""));
        IsChecked = sps.getBoolean(IS_CHECKED, false);
        cb_remeberme.setChecked(IsChecked);
    }

    public static String getmUsername() {
        return mUsername;
    }

}














云服务器与数据库搭建模块:

var app = require('express')();
var http = require('http').Server(app);
var io = require(' socket.io')(http);

app.get('/', function(req, res){
    res.sendFile(__dirname + '/index.html');
});

io.on('connection', function(socket){
    console.log('an user connected');
});



io.on('connection', (socket) => {
    const nickname = 'user' + Math.ceil((Math.random() * 1000))
    socket.broadcast.emit('connection', nickname + ' connected')

    socket.on('chat message', (msg) => {
        io.emit('chat message', nickname + ': ' + msg)
    })
})

http.listen(3000, function(){
    console.log('listening on *:3000');
});

网页主界面:




    
    
    
    
    
    
    
    
    
    
    
    

    
    
    爱情匹配~
    

    
    


已成功匹配 对情侣

假装情侣

假装情侣

宅宅账单
脱单必学,灵魂匹配,童叟无欺,伞流丝明猩团倾情推荐!

匹配中
载入中... 正在寻找另一半...

宅宅记账——基于AI的智能记账软件(Android Studio)_第4张图片 宅宅记账——基于AI的智能记账软件(Android Studio)_第5张图片

宅宅记账——基于AI的智能记账软件(Android Studio)_第6张图片宅宅记账——基于AI的智能记账软件(Android Studio)_第7张图片

需要源码可在评论区留言!!!

你可能感兴趣的:(android-studio,python,java,sql)