流程图用什么软件做

流程图用什么软件做,第1张

制作流程图可以使用Microsoft Office Visio软件。该软件是微软公司的产品,其是在Windows *** 作系统下运行的流程图和矢量绘图软件。软件主要的功能定位帮助是IT和商务人员就复杂信息、系统和流程进行可视化处理、分析和交流。

其中使用该软件在制作流程图时,可以采用可视方式将需要的形状拖放到绘图中进行绘制即可完成。另外该软件可以提供包括业务流程图、软件界面、网络图、工作流图表、数据库模型和软件图表等多种不同形式的流程图设计以及制作。

Microsoft Office Visio制作流程图方法:

1、在电脑左下角点击开始,选择该软件进入。

2、进入到软件以后点击基本框图进入。

3、在出现的页面中点击新建按钮。

4、可以看到导航栏的相关图形,选中需要的图形将其拖拽到页面中。

5、双击该输入需要的流程文字。

6、再继续根据需要拖拽相应的图形进入并编辑文字。

7、继续根据需要输入对应的内容。

8、输入完成以后点击上方的连接线按钮。

9、依次根据需要使用连接线将对应的流程予以连接即可。

以上内容参考 百度百科-Microsoft Office Visio

接上一篇,IMMS设置当前默认输入法为LatinIME输入法后,调用onCreate方法,然后会调用startInputInnerLocked启动输入法LatinIME的服务

本章节主要分析,onCreate生命周期中,各个流程调用

bindServiceAsUser启动的服务是LatinIME

如上图流程图,服务启动后,会调用到InputMethodManagerService的setAdditionalInputMethodSubtypes方法

该流程的主要逻辑:

完成对mMethodList和mMethodMap的数据初始化;检查当前默认的输入法(LatinIME)服务是否存在,很明显,经过systemrunning过程以后,

mMethodMap已经包含了LatinIME,因此不会重复执行选择和设定另外输入法为默认输入法的 *** 作

该方法主要是检查默认的LatinIME是否是可用的可用的输入法,如果不可用,则设置为可用;

对应的settingprovider字段为:

经过以上流程后,默认输入法依然为LatinIME输入法,该流程的主要作用为,将启动的输入法应用更新到可用列表enabled_input_methods中;

不过,目前默认的输入法依然为LatinIME输入法,跟重启手机前,我们设置的输入法(搜狗输入法)依然不一致

下一篇文章,我们研究下,输入法启动过程中的onBind和onServiceConnected流程

       传统的多线程是通过继承Thread类及实现Runnable接口来实现的,每次创建及销毁线程都会消耗资源、响应速度慢,且线程缺乏统一管理,容易出现阻塞的情况,针对以上缺点,线程池就出现了。

       线程池是一个创建使用线程并能保存使用过的线程以达到复用的对象,简单的说就是一块缓存了一定数量线程的区域。

       1复用线程:线程执行完不会立刻退出,继续执行其他线程;

       2管理线程:统一分配、管理、控制最大并发数;

       1降低因频繁创建&销毁线程带来的性能开销,复用缓存在线程池中的线程;

       2提高线程执行效率&响应速度,复用线程:响应速度;管理线程:优化线程执行顺序,避免大量线程抢占资源导致阻塞现象;

       3提高对线程的管理度;

       线程池的使用也比较简单,流程如下:

       接下来通过源码来介绍一下ThreadPoolExecutor内部实现及工作原理。

       线程池的最终实现类是ThreadPoolExecutor,通过实现可以一步一步的看到,父接口为Executor:

       其他的继承及实现关系就不一一列举了,直接通过以下图来看一下:

       从构造方法开始看:

       通过以上可以看到,在创建ThreadPoolExecutor时,对传入的参数是有要求的:corePoolSize不能小于0;maximumPoolSize需要大于0,且需要大于等于corePoolSize;keepAliveTime大于0;workQueue、threadFactory都不能为null。

       在创建完后就需要执行Runnable了,看以下execute()方法:

       在execute()内部主要执行的逻辑如下:

       分析点1:如果当前线程数未超过核心线程数,则将runnable作为参数执行addWorker(),true表示核心线程,false表示非核心线程;

       分析点2:核心线程满了,如果线程池处于运行状态则往workQueue队列中添加任务,接下来判断是否需要拒绝或者执行addWorker();

       分析点3:以上都不满足时 [corePoolSize=0且没有运行的线程,或workQueue已经满了] ,执行addWorker()添加runnable,失败则执行拒绝策略;

        总结一下:线程池对线程创建的管理,流程图如下:

       在执行addWorker时,主要做了以下两件事:

       分析点1:将runnable作为参数创建Worker对象w,然后获取w内部的变量thread;

       分析点2:调用start()来启动thread;

       在addWorker()内部会将runnable作为参数传给Worker,然后从Worker内部读取变量thread,看一下Worker类的实现:

       Worker实现了Runnable接口,在Worker内部,进行了赋值及创建 *** 作,先将execute()时传入的runnable赋值给内部变量firstTask,然后通过ThreadFactorynewThread(this)创建Thread,上面讲到在addWorker内部执行tstart()后,会执行到Worker内部的run()方法,接着会执行runWorker(this),一起看一下:

       前面可以看到,runWorker是执行在子线程内部,主要执行了三件事:

       分析1:获取当前线程,当执行shutdown()时需要将线程interrupt(),接下来从Worker内部取到firstTask,即execute传入的runnable,接下来会执行;

       分析2:while循环,task不空直接执行;否则执行getTask()去获取,不为空直接执行;

       分析3:对有效的task执行run(),由于是在子线程中执行,因此直接run()即可,不需要start();

       前面看到,在while内部有执行getTask(),一起看一下:

       getTask()是从workQueue内部获取接下来需要执行的runnable,内部主要做了两件事:

       分析1:先获取到当前正在执行工作的线程数量wc,通过判断allowCoreThreadTimeOut[在创建ThreadPoolExecutor时可以进行设置]及wc > corePoolSize来确定timed值;

       分析2:通过timed值来决定执行poll()或者take(),如果WorkQueue中有未执行的线程时,两者作用是相同的,立刻返回线程;如果WorkQueue中没有线程时,poll()有超时返回,take()会一直阻塞;如果allowCoreThreadTimeOut为true,则核心线程在超时时间没有使用的话,是需要退出的;wc > corePoolSize时,非核心线程在超时时间没有使用的话,是需要退出的;

       allowCoreThreadTimeOut是可以通过以下方式进行设置的:

       如果没有进行设置,那么corePoolSize数量的核心线程会一直存在。

        总结一下:ThreadPoolExecutor内部的核心线程如何确保一直存在,不退出?

       上面分析已经回答了这个问题,每个线程在执行时会执行runWorker(),而在runWorker()内部有while()循环会判断getTask(),在getTask()内部会对当前执行的线程数量及allowCoreThreadTimeOut进行实时判断,如果工作数量大于corePoolSize且workQueue中没有未执行的线程时,会执行poll()超时退出;如果工作数量不大于corePoolSize且workQueue中没有未执行的线程时,会执行take()进行阻塞,确保有corePoolSize数量的线程阻塞在runWorker()内部的while()循环不退出。

       如果需要关闭线程池,需要如何 *** 作呢,看一下shutdown()方法:

       以上可以看到,关闭线程池的原理:a 遍历线程池中的所有工作线程;b 逐个调用线程的interrupt()中断线程(注:无法响应中断的任务可能永远无法终止)

       也可调用shutdownNow()来关闭线程池,二者区别:

       shutdown():设置线程池的状态为SHUTDOWN,然后中断所有没有正在执行任务的线程;

       shutdownNow():设置线程池的状态为STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表;

       使用建议:一般调用shutdown()关闭线程池;若任务不一定要执行完,则调用shutdownNow();

        总结一下:ThreadPoolExecutor在执行execute()及shutdown()时的调用关系,流程图如下:

       线程池可以通过Executors来进行不同类型的创建,具体分为四种不同的类型,如下:

       可缓存线程池:不固定线程数量,且支持最大为IntegerMAX_VALUE的线程数量:

       1、线程数无限制

       2、有空闲线程则复用空闲线程,若无空闲线程则新建线程

       3、一定程度上减少频繁创建/销毁线程,减少系统开销

       固定线程数量的线程池:定长线程池

       1、可控制线程最大并发数(同时执行的线程数)

       2、超出的线程会在队列中等待。

       单线程化的线程池:可以理解为线程数量为1的FixedThreadPool

       1、有且仅有一个工作线程执行任务

       2、所有任务按照指定顺序执行,即遵循队列的入队出队规则

       定时以指定周期循环执行任务

       一般来说,等待队列 BlockingQueue 有: ArrayBlockingQueue 、 LinkedBlockingQueue 与 SynchronousQueue 。

       假设向线程池提交任务时,核心线程都被占用的情况下:

        ArrayBlockingQueue :基于数组的阻塞队列,初始化需要指定固定大小。

       当使用此队列时,向线程池提交任务,会首先加入到等待队列中,当等待队列满了之后,再次提交任务,尝试加入队列就会失败,这时就会检查如果当前线程池中的线程数未达到最大线程,则会新建线程执行新提交的任务。所以最终可能出现后提交的任务先执行,而先提交的任务一直在等待。

        LinkedBlockingQueue :基于链表实现的阻塞队列,初始化可以指定大小,也可以不指定。

       当指定大小后,行为就和 ArrayBlockingQueue一致。而如果未指定大小,则会使用默认的 IntegerMAX_VALUE 作为队列大小。这时候就会出现线程池的最大线程数参数无用,因为无论如何,向线程池提交任务加入等待队列都会成功。最终意味着所有任务都是在核心线程执行。如果核心线程一直被占,那就一直等待。

        SynchronousQueue :无容量的队列。

       使用此队列意味着希望获得最大并发量。因为无论如何,向线程池提交任务,往队列提交任务都会失败。而失败后如果没有空闲的非核心线程,就会检查如果当前线程池中的线程数未达到最大线程,则会新建线程执行新提交的任务。完全没有任何等待,唯一制约它的就是最大线程数的个数。因此一般配合IntegerMAX_VALUE就实现了真正的无等待。

       但是需要注意的是, 进程的内存是存在限制的,而每一个线程都需要分配一定的内存。所以线程并不能无限个。

       上篇文章从整体上介绍了事件处理的流程 Android IMS原理解析之processEvent ,本篇文章将详细介绍事件的处理过程;

       前面分析到,InputDispatcher将触摸事件通过InputChannel发送到目标窗口的接收方WindowInputEventReceiver的dispatchInputEvent(),接下来经过一系列调用会最终调用到ViewPostImeInputStage的processKeyEvent()处理keyEvent、调用processPointerEvent()处理MotionEvent;接下来就一起来看一下对应事件的处理逻辑:

       此方法主要处理key事件比如:BACK、MENU、HOME等事件:

       本文主要分析mViewdispatchKeyEvent(event),针对activity及back键来进行分析,mView对应Activity的DecorView,看一下DecorView内部的dispatchKeyEvent()方法:

       mWindow对应着Activity的PhoneWindow,mWindowgetCallback()会返回Activity本身,该处是在Activity的attach()内部执行以下逻辑来执行赋值的,

       接着上面的分析,callback不为null,featureId为-1(所有Activity的featureId都是默认为-1),所以会执行cbdispatchKeyEvent()即Activity的dispatchKeyEvent():

       执行eventdispatch(),对应到KeyEvent里面的dispatch()方法:

       receiver是Activity,所以会执行Activity内部的onKeyDown()及onKeyUp()方法:

       所以在Activity界面收到Back事件后,会回调Activty的onBackPressed()方法,默认在onBackPressed()内部关闭activity,如果不想关闭可以重写onBackPressed()或onKeyDown()等,都能实现;

       以上就是针对在Activity界面执行Back键时processKeyEvent()的整个执行过程。

       用一张流程图总结一下:

       在processPointerEvent()内部调用的是mViewdispatchPointerEvent(event),即DecorView的dispatchPointEvent(),该方法是在Viewjava内部,一起看一下:

       本文只分析MotionEvent的对应的touch事件,在dispatchPointerEvent()内部会执行dispatchTouchEvent():

       前面分析到,mWindowgetCallback()为activity,mFeatureId为-1,所以最终执行的是cbdispatchTouchEvent(ev),即Activity的dispatchTouchEvent(ev):

       可以看到,先执行getWindow()superDispatchTouchEvent(ev),如果返回false会执行onTouchEvent(),先看一下PhoneWindow的superDispatchTouchEvent(ev)方法:

       在PhoneWindow内部的superDispatchTouchEvent()执行了DecorView的superDispatchTouchEvent(),又回到DecorView:

       在DecorView内部调用父类的dispatchTouchEvent,即ViewGroup的dispatchTouchEvent():

       该方法逻辑实现比较长,本文就只拿关键的地方来进行分析,主要有两点:

       1通过onInterceptTouchEvent()来判断是否对事件进行拦截,比如:如果ViewGroup想拦截事件,可以重写onInterceptTouchEvent()来返回true,默认返回false;

       2如果ViewGroup没有对事件进行拦截,那么会从ViewGroup的所有child View里面找到匹配的目标view执行dispatchTransformedTouchEvent()来对事件进行处理,在dispatchTransformedTouchEvent()内部会调用child的dispatchTouchEvent()来对Event进行处理;

       该方法内部主要有两项重点:

       1先判断View(控件)是否实现了mOnTouchListener,如果没实现,直接跳过;否则判断onTouch()返回值,如果返回true,则result为true,如果返回false,则result为false;

       2如果满足result为false,则执行onTouchEvent(event);

       在onTouchEvent()内部逻辑处理如下,只分析DOWN和UP事件,先看DOWN事件:

       因为在DOWN时,可能会出现长按不放的情况,那么就会触发LongClick事件,执行checkForLongClick(0, x, y)来进行判断:

       通过以上调用流程可以看到,最终返回的值由是OnLongClickListener的onLongClick()来决定,如果返回true的话,那么在CheckForLongPress里面会设置mHasPerformedLongPress为true,如果返回false的话,那么mHasPerformedLongPress还是false;

       接下来分析Up事件,我们知道onClick()就是在Up后进行处理的,一起看一下UP事件处理:

       如果先处理的onLongClick()且返回true,那么mHasPerformedLongPress值为true,那么就不会处理后续事件了,如果返回false,那么mHasPerformedLongPress为false,那么就会执行post(mPerformClick),一起看一下执行逻辑:

       通过上面可以看到,在performClick()里面会执行OnClickListener的onClick()方法,onClick事件也就分析完了;

       用一张流程图总结一下:

(1)项目开发步骤的完整性(系统需求分析、概念设计、物理设计、系统环境和配置、系统实施以及系统测试和调试等)

(2)每个开发步骤所得结果的正确性(业务流程图、数据流程图、数据词典、HIPO图、E-R图、关系模式、人机界面设计及模块处理等的详细分析和说明)

(3)论文整体结构的完整性(前言、各个具体步骤的叙述和分析、结语、参考文献和有关附录)

(4)提供软件系统的可执行盘片及 *** 作说明书

(5)参考资料(列出必要的参考资料)

帧的渲染过程中一些关键组件的流程图

任何可以产生图形信息的组件都统称为图像的生产者,比如OpenGL ES, Canvas 2D, 和 媒体解码器等。

SurfaceFlinger是最常见的图像消费者,Window Manager将图形信息收集起来提供给SurfaceFlinger,SurfaceFlinger接受后经过合成再把图形信息传递给显示器。同时,SurfaceFlinger也是唯一一个能够改变显示器内容的服务。SurfaceFlinger使用OpenGL和Hardware Composer来生成surface

某些OpenGL ES 应用同样也能够充当图像消费者,比如相机可以直接使用相机的预览界面图像流,一些非GL应用也可以是消费者,比如ImageReader 类。

Window Manager是一个用于控制window的系统服务,包含一系列的View。每个Window都会有一个surface,Window Manager会监视window的许多信息,比如生命周期、输入和焦点事件、屏幕方向、转换、动画、位置、转换、z-order等,然后将这些信息(统称window metadata)发送给SurfaceFlinger,这样,SurfaceFlinger就能将window metadata合成为显示器上的surface。

为硬件抽象层(HAL)的子系统。SurfaceFlinger可以将某些合成工作委托给Hardware Composer,从而减轻OpenGL和GPU的工作。此时,SurfaceFlinger扮演的是另一个OpenGL ES客户端,当SurfaceFlinger将一个缓冲区或两个缓冲区合成到第三个缓冲区时,它使用的是OpenGL ES。这种方式会比GPU更为高效。

一般应用开发都要将UI数据使用Activity这个载体去展示,典型的Activity显示流程为:

一般app而言,在任何屏幕上起码有三个layer:

那么android是如何使用这两种合成机制的呢?这里就是Hardware Composer的功劳。处理流程为:

借用google一张图说明,可以将上面讲的很多概念展现,很清晰。地址位于 >

以上就是关于流程图用什么软件做全部的内容,包括:流程图用什么软件做、Android输入法IMMS服务启动流程(3)(启动IMS应用)、Android线程池ThreadPoolExecutor详解等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zz/9266749.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-26
下一篇2023-04-26

发表评论

登录后才能评论

评论列表(0条)

    保存