Acitivty生命周期

为什么80%的码农都做不了架构师?>>>   hot3.png

Acitivty 有七个生命周期:

onCreate:当第一次调用一个Activity就会执行onCreate方法

onStart:当Activity处于可见状态的时候就会调用onStart方法

onResume:当Activity可以得到用户焦点的时候就会调用onResume方法,由被覆盖状态回到前台或解锁屏调用此方法。

onRestart:当Activity没有被销毁的时候重新调用这个Activity就会调用onRestart方法

onPause:当Activity被遮挡住的时候就会调用onPause方法,暂停当前activity。

onStop:当Activity处于不可见状态的时候就会调用onStop方法

onDestory:当Activity被销毁时会调用onDestory方法


环境:一共两个页面,A,B A页面有一个button点击之后打开B页面

activity启动的时候:onCreate ---> onStart ---> onResume,打开A页面:启动时调用,可见状态调用,获取焦点调用。

点击button后打开B页面此时A页面的状态是:onPause--->onStop,首先暂停A页面activity,然后对B页面的activity执行上面的三步,然后对A页面进行停止操作。

当按返回键时:onRestart--->onStart--->onResume,首先暂停B页面,其次对A页面重新调用,可见状态调用,获取焦点是调用,最后在停止B页面。

以下是运行时print截图:

    154258_ZmTM_2250447.png


通过实施这些方法,您可以监视Activity生命周期中的三个嵌套循环

1、entire lifetime (整个生命周期)

一个Activity整个生命周期,存在于onCreate()方法和onDestroy()调用之间。你的Activity应该在onCreate()方法里执行设置“全局”状态(如定义布局)。并在onDestroy()方法里释放所有剩余资源。例如,如果你的活动有一个线程在后台运行下载网络数据它可以在onCreate()创建该线程然后onDestroy()停止线程

2、visible lifetime(可见生命周期)

一个Activity可见生命周期,存在于onStart()和onStop()调用之间。在此期间用户可以看到屏幕上的activity并与之交互。当一个其他的Activity启动,并且这个Activity完全不可见的时候,onStop()方法就会被调用。在这两个方法,你可以保持该Activity需要展示给用户的资源。例如,您可以在onStart()方法里注册一个BroadcastReceiver来监控你的UI的变化,并在onStop()方法里注销它。在整个生命周期的活动中,系统可能会调用onStart()和onStop()多次,因为活动之间交替进行隐藏或显示给用户。

3、 foreground lifetime(前台生命周期)

一个Activity前台生命周期,存在于onResume()和onPause()调用之间。在这段时间里,这个Activity在其他所有Activity的前面,拥有用户输入焦点。一个Activity可以经常在前台状态发生转换—比如,当设备休眠或者弹出了个对话框。因为经常会发生转换,所以在这两个方法之间的代码应该是轻量级的,防止导致其他转换变慢使得用户需要等待。


一个Activity本质上只有三种状态:

Resumed(运行)、Paused(暂停)、Stopped(停止),因为从Activity被创建之后,它只可能在这三种状态保持长久的停 留,其他的回调方法结束后的状态都只能称之为过渡状态。比如进入到onStart方法后,执行完该方法,会立即进入到OnResume方法。(这里所说的 状态都是指对应的某个方法返回之后)。

     Activity相当于一个servlet,我们的Activity处在这个容器中,一切创建实例、初始化、销毁实例等过程都是容器来调用的,这也就是所谓的“Don't call me, I'll call you.”机制。

我们来看一下这一张经典的生命周期流程图:


相信不少朋友也已经看过这个流程图了,也基本了解了Activity生命周期的几个过程,我们就来说一说这几个过程。

1.启动Activity:系统会先调用onCreate方法,然后调用onStart方法,最后调用onResume,Activity进入运行状态。

2.当前Activity被其他Activity覆盖其上或被锁屏:系统会调用onPause方法,暂停当前Activity的执行。

3.当前Activity由被覆盖状态回到前台或解锁屏:系统会调用onResume方法,再次进入运行状态。

4.当前Activity转到新的Activity界面或按Home键回到主屏,自身退居后台:系统会先调用onPause方法,然后调用onStop方法,进入停滞状态。

5.用户后退回到此Activity:系统会先调用onRestart方法,然后调用onStart方法,最后调用onResume方法,再次进入运行状态。

6.当前Activity处于被覆盖状态或者后台不可见状态,即第2步和第4步,系统内存不足,杀死当前Activity,而后用户退回当前Activity:再次调用onCreate方法、onStart方法、onResume方法,进入运行状态。

7.用户退出当前Activity:系统先调用onPause方法,然后调用onStop方法,最后调用onDestory方法,结束当前Activity。

生命周期对于用户体验的实际作用

    activity生命周期不同的周期可以写不同的代码,举个例子,比如你正在播放音乐的时候突然电话来了,这个时候不可能一边接电话一边听音乐吧?这时你就需要在相应的周期里面对播放进行处理,比如你可以在当前activity失去焦点的时候暂停播放。


我还找了一些资料用以扩充学习原文链接

每一个活动( Activity )都处于某一个状态,对于开发者来说,是无法控制其应用程序处于某一个状态的,这些均由系统来完成。 
但是当一个活动的状态发生改变的时候,开发者可以通过调用 onXX() 的方法获取到相关的通知信息。 
在实现 Activity 类的时候,通过覆盖( override )这些方法即可在你需要处理的时候来调用。 
•onCreate :当活动第一次启动的时候,触发该方法,可以在此时完成活动的初始化工作。 
onCreate 方法有一个参数,该参数可以为空( null ),也可以是之前调用 onSaveInstanceState()方法保存的状态信息。
•onStart :该方法的触发表示所属活动将被展现给用户。 
•onResume :当一个活动和用户发生交互的时候,触发该方法。 
•onPause :当一个正在前台运行的活动因为其他的活动需要前台运行而转入后台运行的时候,触发该方法。这时候需要将活动的状态持久化,比如正在编辑的数据库记录等。 
•onStop :当一个活动不再需要展示给用户的时候,触发该方法。如果内存紧张,系统会直接结束这个活动,而不会触发 onStop 方法。 所以保存状态信息是应该在onPause时做,而不是onStop时做。活动如果没有在前台运行,都将被停止或者Linux管理进程为了给新的活动预留足 够的存储空间而随时结束这些活动。因此对于开发者来说,在设计应用程序的时候,必须时刻牢记这一原则。在一些情况下,onPause方法或许是活动触发的 最后的方法,因此开发者需要在这个时候保存需要保存的信息。 
•onRestart :当处于停止状态的活动需要再次展现给用户的时候,触发该方法。 
•onDestroy :当活动销毁的时候,触发该方法。和 onStop 方法一样,如果内存紧张,系统会直接结束这个活动而不会触发该方法。 
•onSaveInstanceState :系统调用该方法,允许活动保存之前的状态,比如说在一串字符串中的光标所处的位置等。 
通常情况下,开发者不需要重写覆盖该方法,在默认的实现中,已经提供了自动保存活动所涉及到的用户界面组件的所有状态信息。
  
4. 必调用的三个方法:onCreate() –> onStart() –> onResume(),用AAA表示
(1)父Activity(A)启动,点击启动子Activity(B),子Actvity退出,返回父Activity调用顺序如下:
AAA –> onFreeze() –> onPause() –> B onCreate() -> B onStart() -> B onResume –> onStop() –> onRestart() –> onStart()->onResume()
(2)用户点击Home,Actvity调用顺序如下
AAA –> onFreeze() –> onPause() –> onStop() — Maybe –> onDestroy()
( 3 ) 用户点击back键,Activity调用顺序如下:
AAA-> onPause() –> onStop() –> onDestroy() ->onCreate()->onStart()->onResume()
(4)调用finish(), Activity调用顺序如下 
AAA –> onPause() –> onStop() –> onDestroy() 
(5)在Activity上显示dialog, Activity调用顺序如下 
AAA -> onPause()
(6)在父Activity上显示透明的或非全屏的activity,Activity调用顺序如下 
AAA –> onFreeze() –> onPause() 
(7)设备进入睡眠状态,Activity调用顺序如下 
AAA –> onFreeze() –> onPause()

5. 和其他手机平台的应用程序一样,Android的应用程序的生命周期是被统一掌控的,也就是说我们写的应用程序命运掌握在别人(系统)的手里,我们不能改变它,只能学习并适应它。
简单地说一下为什么是这样:我们手机在运行一个应用程序的时候,有可能打进来电话发进来短信,或者没有电了,这时候程序都会被中断,优先去服务电话的基本功能,另外系统也不允许你占用太多资源,至少要保证电话功能吧,所以资源不足的时候也就有可能被干掉。 
言归正传,Activity的基本生命周期如下代码所示: 
Java 代码 
public class MyActivity extends Activity {  
protected void onCreate(Bundle savedInstanceState);  
protected  void onStart();
protected  void onResume();
protected  void onPause();
protected  void onStop();
protected  void onDestroy();
}   
        
       你自己写的Activity会按需要重载这些方法,onCreate是免不了的,在一个Activity正常启动的过程中,他们被调用的顺序是 onCreate -> onStart -> onResume, 在Activity被干掉的时候顺序是onPause -> onStop -> onDestroy ,这样就是一个完整的生命周期,但是有人问了 ,程序正运行着呢来电话了,这个程序咋办?中止了呗,如果中止的时候新出的一个Activity是全屏的那么:onPause->onStop,恢 复的时候onStart->onResume,如果打断这个应用程序的是一个Theme为Translucent 或者Dialog 的Activity那么只是onPause ,恢复的时候onResume 。 
详细介绍一下这几个方法中系统在做什么以及我们应该做什么: 
onCreate:   在这里创建界面,做一些数据的初始化工作 
onStart:   到这一步变成用户可见不可交互的 
onResume:   变成和用户可交互的,(在activity栈系统通过栈的方式管理这些个Activity的最上面,运行完弹出栈,则回到上一个Activity) 
onPause:到这一步是可见但不可交互的,系统会停止动画等消耗CPU 的事情
        从上文的描述已经知道,应该在这里保存你的一些数据,因为这个时候你的程序的优先级降低,有可能被系统收回。在这里保存的数据,应该在onResume里读出来,注意:这个方法里做的事情时间要短,因为下一个activity不会等到这个方法完成才启动 
onstop:变得不可见,被下一个activity覆盖了 
onDestroy: 这是activity被干掉前最后一个被调用方法了,可能是外面类调用finish方法或者是系统为了节省空间将它暂时性的干掉,可以用 isFinishing()来判断它,如果你有一个Progress Dialog在线程中转动,请在onDestroy里把他cancel掉,不然等线程结束的时候,调用Dialog的cancel方法会抛异常的。 onPause,onstop, onDestroy,三种状态下activity都有可能被系统干掉,为了保证程序的正确性,你要在onPause()里写上持久层操作的代码,将用户编 辑的内容都保存到存储介质上(一般都是数据库 )。实际工作中因为生命周期的变化而带来的问题也很多,比如你的应用程序起了新的线程在跑,这时候中断了,你还要去维护那个线程,是暂停还是杀掉还是数据 回滚,是吧?因为Activity可能被杀掉,所以线程中使用的变量和一些界面元素就千万要注意了,一般我都是采用Android的消息机制 [Handler,Message]来处理多线程和界面交互的问题。这个我后面会讲一些。 

相关问题:
1. 能说下Android应用的入口点吗?
真正的Android入口点是application的main,你可以看下androidmanifest.xml的包含关系就清楚了。可以没有Activity但是必须有Application。
2. 如果后台的Activity由于某原因被系统回收了,如何在被系统回收之前保存当前状态?
在”暂停 onPause” 状态将数据保存。
3. 如何退出Activity?如何安全退出已调用多个Activity的Application?
对于单一Activity的应用来说,退出很简单,直接finish()即可。当然,也可以用killProcess()和System.exit()这样的方法。

4. 返回键与Home键区别?
   back键默认行为是finish处于前台的Activity的,即Activity的状态为Destroy状态为止,再次启动该Activity是从 onCreate开始的(不会调用onSaveInstanceState()方法)。Home键默认是stop前台的Activity即状态为 onStop为止,而不是Destroy,若再次启动它,会调用onSaveInstanceState() 方法,保持上次Activity的状态则是从OnRestart开始的---->onStart()--->onResume()。

5. 如果后台的Activity由于某原因被系统回收了,如何在被系统回收之前保存当前状态?onSaveInstanceState()
当你的程序中某一个Activity A在运行时,主动或被动地运行另一个新的Activity B,这个时候A会执行onSaveInstanceState()。B完成以后又会来找A,这个时候就有两种情况:一是A被回收,二是A没有被回收,被回 收的A就要重新调用onCreate()方法,不同于直接启动的是这回onCreate()里是带上了参数savedInstanceState;而没被 收回的就直接执行onRestart()->onStart()->onResume(),跳过onCreate()了。

6. 你后台的Activity被系统回收怎么办:onSaveInstanceState 
当你的程序中某一个Activity A 在运行时中,主动或被动地运行另一个新的Activity B,这个时候A会执行 
Java代码   
public void onSaveInstanceState(Bundle outState) {    
super.onSaveInstanceState(outState);    
outState.putLong("id", 1234567890);

B 完成以后又会来找A, 这个时候就有两种情况,一种是A被回收,一种是没有被回收,被回收的A就要重新调用onCreate()方法,不同于直接启动的是这回 onCreate()里是带上参数savedInstanceState,没被收回的就还是onResume就好了。 
savedInstanceState是一个Bundle对象,你基本上可以把他理解为系统帮你维护的一个Map对象。在onCreate()里你可能会用到它,如果正常启动onCreate就不会有它,所以用的时候要判断一下是否为空。 
Java代码 
if(savedInstanceState != null){     
long id = savedInstanceState.getLong("id");

就像官方的Notepad教程里的情况,你正在编辑某一个note,突然被中断,那么就把这个note的id记住,再起来的时候就可以根据这个id去把那 个note取出来,程序就完整一些。这也是看你的应用需不需要保存什么,比如你的界面就是读取一个列表,那就不需要特殊记住什么,哦, 没准你需要记住滚动条的位置(滚动条的位置如何记住?)...

7. 怎样关闭一个Activity;怎样关闭一个Application?
ActivityManager activityMgr= (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
activityMgr.restartPackage(getPackageName());
最后还需要添加这个权限才行:
<!-- 关闭应用程序的权限 -->
<uses-permission android:name="android.permission.RESTART_PACKAGES" />

8. 横竖屏切换的生命周期

9. Activity栈
   上面提到开发者是无法控制Activity的状态的,那Activity的状态又是按照何种逻辑来运作的呢?这就要知道 Activity 栈。
每个Activity的状态是由它在Activity栈(是一个后进先出LIFO,包含所有正在运行Activity的队列)中的位置决定的。
当一个新的Activity启动时,当前的活动的Activity将会移到Activity栈的顶部。
如果用户使用后退按钮返回的话,或者前台的Activity结束,在栈上的Activity将会移上来并变为活动状态。如下图所示:

   2.JPG 

    一个应用程序的优先级是受最高优先级的Activity影响的。当决定某个应用程序是否要终结去释放资源,Android内存管理使用栈来决定基于Activity的应用程序的优先级。
Activity状态 
一般认为Activity有以下四种状态: 
活动的:当一个Activity在栈顶,它是可视的、有焦点、可接受用户输入的。Android试图尽最大可能保持它活动状态,杀死其它Activity来确保当前活动Activity有足够的资源可使用。当另外一个Activity被激活,这个将会被暂停。 
暂停: 在很多情况下,你的Activity可视但是它没有焦点,换句话说它被暂停了。有可能原因是一个透明或者非全屏的Activity被激活。 
当被暂停,一个Activity仍会当成活动状态,只不过是不可以接受用户输入。在极特殊的情况下,Android将会杀死一个暂停的Activity来为活动的Activity提供充足的资源。当一个Activity变为完全隐藏,它将会变成停止。 
停止:当一个Activity不是可视的,它“停止”了。这个Activity将仍然在内存中保存它所有的状态和会员信息。尽管如此,当其它地方需要内存 时,它将是最有可能被释放资源的。当一个Activity停止后,一个很重要的步骤是要保存数据和当前UI状态。一旦一个Activity退出或关闭了, 它将变为待用状态。 
待用: 在一个Activity被杀死后和被装在前,它是待用状态的。待用Acitivity被移除Activity栈,并且需要在显示和可用之前重新启动它。


转载于:https://my.oschina.net/mmda/blog/503863

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/287679.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

还不懂你现在学习的编程语言能做什么?还不懂如何进阶?过来看图

前言说七说八 本篇文章的配图标注、内容并不代表仅有&#xff1b;本篇仅以个人经验及当前大学&#xff08;大专、本科&#xff09;相关课程作对比&#xff0c;列出比较常规的语言发展走向及相关技术&#xff1b;再次重申&#xff0c;本图及本文所涉及的技术发展走向并不代表着…

【遥感数字图像处理】实验:遥感影像几何纠正完整操作流程(Erdas版)

☆☆☆ 几何纠正预备知识 ☆☆☆ 1、几何变形误差的影响因素 遥感器本身引起的畸变外部因素引起的畸变处理过程中引起的畸变2、需要做精纠正的情况 景与景之间作比较GIS建模之前监督分类时提取样本创建高精度比例尺的影像地图与矢量数据叠加源于不同比例尺的地图之间比较提取精…

openid 钉钉_钉钉开发入门,微应用识别用户身份,获取用户免登授权码code,获取用户userid,获取用户详细信息...

最近有个需求,在钉钉内,点击微应用,获取用户身份,根据获取到的用户身份去企业内部的用户中心做校验,校验通过,相关子系统直接登陆;就是在获取这个用户身份的时候,网上的资料七零八落的,找的人烦躁的很,所以自己记录一下;实现这个要求,有好几种方式,使用ISV方式相对来说比较简单…

趣味二维码生成

1背景介绍 最近在 Github 看到了一个有趣的项目 amazing-qr&#xff0c;它支持生成普通二维码&#xff0c;带图片的艺术二维码&#xff0c;动态二维码。项目是用 python 编写的&#xff0c;以命令行的方式运行生成&#xff0c;不太方便调用&#xff0c;因此&#xff0c;我…

《零基础看得懂的C++入门教程 》——(1)第一个C++程序就让你知其所以然

一、学习目标 了解第一个C程序了解第一个C程序结构了解什么是注释了解什么是命名空间了解C语言的输出&#xff08;如何在程序运行时显示内容&#xff09;了解语句结束后需要使用什么符号表示结束 了解程序入口 目录 预备第一篇&#xff0c;使用软件介绍在这一篇&#xff0c;…

1、Locust压力测试环境搭建

环境准备&#xff1a;阿里云服务器一台、python2.7、pip Locust 介绍Locust 是一个开源负载测试工具。使用 Python 代码定义用户行为&#xff0c;也可以仿真百万个用户。 Locust 简单易用&#xff0c;分布式&#xff0c;用户负载测试工具。Locust 主要为网站或者其他系统进行负…

交互式 .Net

1名词解析 1. 交互式交互式是指输入代码后可直接运行该代码&#xff0c;然后持续输入运行代码。2. 交互式 .Net.Net 是一种编译型语言&#xff0c;不像 python 这类的脚本型语言&#xff0c;可以边输入代码边运行结果。幸运的是&#xff0c;软微推出了 interactive 这个项…

mysql signed 长度_浅谈mysql字段长度设置

mysql 中最常用的数据类型是tinyint,smallint,int,bigint,char,varchar;char(n)和varchar(n)存储固定长度的字符数据&#xff0c;长度最大为254字节。使用 ‘n’字节的存储空间;有符号和无符号区别:有符号可以存储负值,无符号只能存储0和非负值数值;tinyint 占用1字节的存储空间…

R语言-异常数据处理2

在R中进行基于稳健马氏距离的异常检验 前言 我们研究的数据中经常包含着一些不同寻常的样本&#xff0c;这称之为异常值(Outlier)。这些异常值会极大的影响回归或分类的效果。异常值产生的原因有很多&#xff0c;其中可能是人为错误、数据测量误差&#xff0c;或者是实际确实存…

《零基础看得懂的C++入门教程 》——(2)什么是数据类型、变量?一看便会

一、学习目标 了解基本常用的数据类型了解什么是变量 目录 预备第一篇&#xff0c;使用软件介绍在这一篇&#xff0c;C与C使用的软件是一样的&#xff0c;查看这篇即可&#xff1a;《软件介绍》 想了解编译原理和学习方法点这篇&#xff0c;学习方法和一些原理C与C都是相同的…

pycharm 快捷键介绍

CtrlN (Navigate | Class) 打开输入框输入要查找的类名 Ctrl空格 代码自动补全 Ctrl空格&#xff08;按两次&#xff09;对于没有导入的类自动完成导入代码并自动补全 AltF7 查找方法变量在工程中的所有应用 CtrlQ (View | Quick Documentation). 快速查看文档 …

db2和mysql语句区别_db2和mysql语法的区别是什么

MySQL默认使用大小写敏感的数据库名、表名和列名(可以通过lower_case_table_names参数控制是否大小写敏感)&#xff0c;DB2数据库对大小写不敏感。虽然MySQL与DB2都遵循并符合SQL92标准且大多数SQL相互兼容&#xff0c;但是在一些细节的实现上有一些不同的地方。比如&#xff1…

查缺补漏系统学习 EF Core 6 - 数据查询

这是 EF Core 系列的第四篇文章&#xff0c;上一篇文章讲述了 EF Core 中的实体迁移与数据播种。这篇文章盘点一下 EF Core 的几种数据查询方式&#xff0c;内容较多分上下两篇。点击上方或后方蓝字&#xff0c;阅读 EF Core 系列合集。简单查询在 EF Core 中&#xff0c;每个查…

《零基础看得懂的C++入门教程 》——(3)表达式花样挺多鸭

一、学习目标 了解变量之间的计算了解什么是表达式了解什么是自增、自减 目录 预备第一篇&#xff0c;使用软件介绍在这一篇&#xff0c;C与C使用的软件是一样的&#xff0c;查看这篇即可&#xff1a;《软件介绍》 想了解编译原理和学习方法点这篇&#xff0c;学习方法和一些…

prometheus python client

为什么80%的码农都做不了架构师&#xff1f;>>> 当我刚开始准备使用Python写一个promethues的client的时候&#xff0c;并没有想到过程这么麻烦。github上的大佬们也没兴趣帮我解决这些细节的问题。以下是我在使用prometheus_client遇到的一些问题&#xff0c;仅供…

【遥感数字图像处理】实验:遥感影像分类(监督、非监督分类)完整流程(Erdas版)

一.实验目的: 理解计算机图像分类的基本原理,掌握数字图像非监督分类以及监督分类的具体方法和过程,以及两种分类方法的区别。 二.实验平台:ERDAS IMAGINE 9.1 三.实验要求:掌握非监督分类;非监督分类结果评价;监督分类;监督分类结果评价;分类后处理。 四.实验…

重大跨越!Windows 11 23H2 25115 推送:2023 年更新测试开启,水印回归

面向 Dev 频道的 Windows 预览体验成员&#xff0c;微软现已发布 Windows 11 预览版 Build 25115。主要变化1.微软宣布从 Dev 频道切换到 Beta 频道的选项正式关闭&#xff0c;Beta 频道将继续测试 Windows 11 版本 22H2&#xff0c;而 Dev 频道将开启 2023 年更新 Windows 11 …

《零基础看得懂的C++入门教程 》——(4)条件判断原来如此

一、学习目标 了解什么是条件判断了解多个条件判断了解输入了解什么是逻辑与、逻辑或 目录 预备第一篇&#xff0c;使用软件介绍在这一篇&#xff0c;C与C使用的软件是一样的&#xff0c;查看这篇即可&#xff1a;《软件介绍》 想了解编译原理和学习方法点这篇&#xff0c;学…

Django学习笔记(4)

为什么80%的码农都做不了架构师&#xff1f;>>> 首先提一个问题&#xff1a;在Django中如何处理CRSF(Cross-site request forgery)? 先看一下CSRF原理。 其实就是恶意网站利用正常网站的cookie去非法请求。 ##Java处理方式## 一般做法需要后台和前端配合采取策略去…

.NET版OCR紧随PP-OCRv3重磅发布

.net版OCR地址PaddleOCRSharp&#xff1a;https://gitee.com/raoyutian/paddle-ocrsharpPaddleOCRSharp是一个基于PaddleOCR的C代码修改并封装的.NET的工具类库。包含文本识别、文本检测、基于文本检测结果的统计分析的表格识别功能&#xff0c;同时针对小图识别不准的情况下&a…