图解Android - 如何看Android的UML 图?
如何看UML图? UML能给我们带来什么? 这是本文要寻找的答案。UML图有很多类型,我们这里只讨论最重要也最常用的两种 - 类图和时序图。
1. 类图
通过类图,我们可以很容易的了解代码架构,理清模块之间的关系, 包括继承(Inheritance),实现(realization),依赖(dependency),组合(Composition), 聚合(Aggregation), 关联 (Association) 等等。
下面就图中给出的7种关系一一解读。
1.1 Composition
Compostion 是一种 Association 关系,但它更强调两个类之间整体和局部关系,它暗示两个类之间有着相同的生命周期,比如说图中的三个1.
- W 是 ViewRootImpl的成员变量之一,ViewRootImpl 对象的构造函数里也构造了W,因此,当ViewRootImpl 析构时,W也被析构,他们的生命周期是一致的。代码如下:
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
...
final W mWindow;
... mWindow = new W(this); //互相引用,所以当一个销毁时,另外一个也无法存在。 } - 同样类似的关系存在于 WindowManagerService 和 WindwoState 之间。
1.2 Realization
Realization就是实现,在Java中体现为implements 一个接口类interface), 在标准的C++中没有明确的接口概念,但抽象类实际上起着和接口类似的功能,因为C++的Realization可以体现为继承一个抽象类。在Android 的C++代码中,有一个特殊的抽象类IInterface, 定义了PC接口类的一些基本方法, 关于它的细节可以参考 图解Android - Binder 和 Service。
1.3 Association
有接口就会有引用,在UML中一根最普通的单向箭头即是引用(关联)关系。它的含义是,某个对象用到了一个其他对象的接口或属性。通常,Assocation 通过两种方式获取
- 依赖注入,通过构造函数或SetXXX()接口,比如说 WindowState 通过构造时传入的参数获取了对IWindow对象的引用
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
int viewVisibility, final DisplayContent displayContent) - 间接获取,通过调用其他对象方法返回。比如
mActivityManager = ActivityManagerNative.getDefault();
和具有组合关系(Composition)的对象相比,Associated对象的生命周期管理要复杂一些,因为他有可能被若干个对象所应用,如果不小心干掉一个还在使用的对象,就会造成不可知的后果。Java中通过GC完全去除了析构方法, 交由系统来决定何时对象应该被析构。C++没有类似GC的功能,所以Android 在C++中引入的智能指针(会有专门文章介绍)来实现类似GC(实现的差异还是很大的)的功能,从而能够减轻开发者的负担,并能够提高代码的稳定性。
1.4 Android 的 IPC interface.
C++和Java 的接口都只支持进程内的调用。为了支持专门用于跨进程的接口调用,Android 专门做了一些规定。凡是以IXXXX 定义的接口类均可以支持IPC(当然,进程内也可以调用IXXXX定义的接口)。当我们在图中看到一个IXXX 接口类,我们便可以认为这是一个进程的边界,他的实现端和调用端对象运行在不同的进程里(至少是不同的线程)。如下图中,IWindow的两端W对象 和 WindowState 对象就用不同的颜色来标明它们分属于不同的进程,W运行在应用程序的进程里,而WinState存在与System Server 进程里。
1.5 Aggregation
聚合表达了两个类的从属关系,但和Composition不同,他们的生命周期并不一样。一个经典的例子就是工厂和车子,车子是工厂造出来的,工厂倒闭了,车子可以继续开,反之亦然。图中PolicyManager 和 PhoneWindow就是类似的关系。
1.6 Inherritance
就是最常见的继承关系了。复杂的继承关系很难阅读和记忆,通过UML图则方便很多,你可以清楚到看出继承关系,同时能够理解继承的设计思想。比如说图中右上角,PhoneWindow 继承了Window 类,Activity 引用的是其基类Window的对象,但背后真正干事的是PhoneWindow对象, 因为Acitivy 用的Window类对象是PolicyManager构造出来的。通过这种方式,PhoneWindow的实现细节被PolicyManager 和 Window 基类隐藏起来,从而大大降低了应用程序(Activity) 改变的几率。这个正是设计模式里有名的工厂模式之一。
1.7 依赖
依赖不同与引用,依赖者和被依赖着之间没有直接的对象引用,通常是常量或静态方法的使用。比如图中,Activity使用了PolicyManager类的静态方法 makeNewWindow() 创建了PhoneWindow对象,我们说Acitivy 依赖PolicyManager 这个模块,但它并没有引用PoclicyManager的对象。依赖通常用一根单向虚线箭头表示。
2. 时序图
通过时序图,我们可以了解代码的调用流程, 并可以检查调用过程中可能产成的潜在问题,如死锁等。时序图可以从两个方向去看,纵向和横向。纵向描述了一个对象在时间轴上所做的事情,一个方块通过代表一个函数的调用。而横向则描述了各个对象之间的调用关系, 包括同步调用,异步调用,返回等等。此外,在时序图中,我们可以给执行块赋予不同的颜色,代表了他们分别运行在不同的进程或线程里。下面就是一张时序图的例子,它描述了Android中一个System server 进程启动的过程,(这里只是局部,更多信息请访问 图解Android - Zygote 和 System Server 启动分析 , 图中的粉红色注释列举了从图中我们可以获知的一些信息。
你刚才不是说从时序图中能看出死锁? 就这样一样图?夸张了吧! 没错,看看下面一个例子吧!
这是一个很简单的例子,图中有两个线程,绿色是app线程,它通过调用MediaPlayer 对象的函数来控制播放器,这里它做了两件事,Start() 然后 Stop (). 而粉色部分代表Driver 线程,它通过回调函数告知Mediaplayer 一下底层的事件。也就是说Mediaplayer 是一个被两个线程同时引用的对象,是一个共享的资源。想当然的,我们用了一把锁来保护它,防止他被同时使用产生冲突。所以,图中,绿色的app在Stop()时候首先拿到了锁。这是问题发生了,Stop()的过程可能会比较长,中途来了一个事件, 图中黄色注释的右方显示了这个情况,两个颜色的长条重叠在一起。这表明有资源冲突发生,也意味着潜在的死锁风险。我们假设Stop()的最终目的就是要析构VideoDecoder 对象,但此时,VideoDecoder调用的eventHandler() 在另外一个线程还没返回,理所当然的我们需要等待它。不幸的是,这个时候死锁发生了,如图中红色注释所示。
通过简单的画这么一个图,我们可以很轻易的分析出一个死锁的情况。那怎么解决它的,尽可以的避免图中不同颜色的条块重叠在一起。看看下面的解决方案,
这回,我们取消了锁的操作,通过添加一个新的线程(变成3个线程,3种颜色)Thread,将同步的调用变成异步,,交由Thread做后台处理。因此图中不再有颜色块重叠(异步调用产生的重叠不算), Stop()和EventHandler都很快返回(异步调用), 从而消除了死锁的存在。这也是为什么Andriod 设计了Looper, MessageQueue 和 Handler 的异步消息处理机制,并在Framework 中大量的使用,因为Android 是个极其复杂的多线程/多进程应用环境(想想任意安装的应用程序和各种各样难以预测的用户操作吧),基于锁的同步调用机制是难于保证完全避免死锁的发生。关于Android 异步消息处理机制,可以参考 图解Android - Looper, Handler 和 MessageQueue 一文。
这下同意了吧,时序图对分析多线程的编程分析有很大的帮助。我们应该在设计阶段尽可能的用类图和时序图来帮助我们避免一些常见的问题,帮助我们得出一个尽可能好的设计。
在图解Andrid 系列博文中,我们将会大量的使用UML图来帮助代码的理解和记忆,相信它会比单纯的解析代码更加清晰。
3. 怎样画Android UML 图?
工具!必须依赖工具,市面上有太多的UML工具,你只需要找一款支持逆向工程的,即将代码转换成UML的数据结构,然后将类图或时序图一步步的绘制出来。
本文用的工具是 bouml,一个Linux上的免费工具(Ubuntu12.10开始就不免费了,所以推荐在12.04上安装使用)。如果你不想从头开始,请访问 https://github.com/samchen2009/android_uml, 那里有一份reverse过的Android 4.3, 以及本系列里面所有的UML图。
图解Android - 如何看Android的UML 图?的更多相关文章
- UML图学习之二 类图
类图(ClassDiagrams)是根据系统中的类以及各类之间的关系描述系统的静态视图.类图不仅显示系统内信息的结构,还描述系统内这些信息的行为.类图的一个重要目的是为其他图(如顺序图.交互图)定义一 ...
- uml 图学习记录
UML类图与类的关系详解 2011-04-21 来源:网络 在画类图的时候,理清类和类之间的关系是重点.类的关系有泛化(Generalization).实现(Realization).依赖(D ...
- 设计模式-UML图简单介绍
直接上法宝: 1.类(Class) 类图分三层: 第一层显示类的名称,如果是抽象类,则就用斜体显示. 第二层是类的特性,通常就是字段和属性. 第三层是类的操作,通常是方 ...
- 【UML】如何看Android的UML图
UML图有很多类型,这里只讨论最重要也最常用的两种 - 类图和时序图. 1. 类图 通过类图,我们可以很容易的了解代码架构,理清模块之间的关系, 包括继承(Inheritance),实现(realiz ...
- Android图表库MPAndroidChart(二)——线形图的方方面面,看完你会回来感谢我的
Android图表库MPAndroidChart(二)--线形图的方方面面,看完你会回来感谢我的 在学习本课程之前我建议先把我之前的博客看完,这样对整体的流程有一个大致的了解 Android图表库MP ...
- Android 高清加载巨图方案 拒绝压缩图片
Android 高清加载巨图方案 拒绝压缩图片 转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/49300989: 本文出自:[张 ...
- Android 高清加载巨图方案, 拒绝压缩图片
源地址:http://blog.csdn.net/lmj623565791/article/details/49300989 一.概述 距离上一篇博客有段时间没更新了,主要是最近有些私事导致的,那么就 ...
- Android图表引擎AChartEngine之折线图使用
最近在帮老师做一个课题,其中app端需要显示折线图以便直观地看数据波动,上网查了些资料后发现了这款图标引擎,另外感谢李坤老师的博客,帮助很大. 废话不多说,下面写代码. 一.AChartEngine是 ...
- 在线看Android系统源码,那些相见恨晚的几种方案
请尊重分享成果,转载请注明出处,本文来自逆流的鱼yuiop,原文链接:http://blog.csdn.net/hejjunlin/article/details/53454514 前言:最近在研究M ...
随机推荐
- codeforces 711D D. Directed Roads(dfs)
题目链接: D. Directed Roads time limit per test 2 seconds memory limit per test 256 megabytes input stan ...
- 第20章 DLL高级技术(2)
20.3 延迟载入DLL 20.3.1延迟载入的目的 (1)如果应用程序使用了多个DLL,那么它的初始化可能比慢,因为加载程序要将所有必需的DLL映射到进程的地址空间.→利用延迟加载可将载入过程延伸到 ...
- java8-4 多态的练习以及题目
1./* 多态练习:猫狗案例*/ class Animal { public void eat(){ System.out.println("吃饭"); } } class Dog ...
- 转:Android开发实践:用脚本编译Android工程
转自: http://ticktick.blog.51cto.com/823160/1365947 一般情况下,我们都是使用Eclipse+ADT插件或者Android studio软件来编译Andr ...
- Netty解决TCP粘包/拆包问题 - 按行分隔字符串解码器
服务端 package org.zln.netty.five.timer; import io.netty.bootstrap.ServerBootstrap; import io.netty.cha ...
- linux添加时间提示符
给PS1添加\t [root@lanny ~]# echo $PS1 [\u@\h \W]\$ [root@lanny ~]# export PS1="[\u@\h \W\t]\$" ...
- Difference Between TIF and TIFF
TIF vs TIFF Many people are confused with similar file extensions that only differ by a single lette ...
- IBatis.Net学习笔记十三:在IBatis.Net中调用存储过程
其实调用方式比较简单,主要也就是两种类型的存储过程:1.更新类型的存储过程2.查询类型的存储过程下面就来看看具体的调用方式:1.更新类型的存储过程sp_InsertAccount: CREATE PR ...
- Android一个大众化的设置界面
布局代码如下: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:an ...
- LeetCode:Search in Rotated Sorted Array I II
LeetCode:Search in Rotated Sorted Array Suppose a sorted array is rotated at some pivot unknown to y ...