求教如何阅读java开源oa系统源码项目源码

关于阅读开源项目的源码,有哪些经验值得分享?
我先说下自己的经历吧。我比较完整的读过的有wordpress,ttserver(tokyotyrant+tokyocabinet),memcached,redis的源码,最近正在系统地读nginx的源码。相信重复的力量读源码过程中最深的一点体会就是,重复重复再重复。当年读ttserver源码是刚入行,本来对C就不熟,ttserver里有很多比较奇怪的代码习惯,于是硬着头皮vim一行一行一遍一遍地看,有些不懂的地方,看十来遍,还真就懂了,可能算是量变引发质变吧。从数据结构入手,先想后读然后后来我学聪明了一点,不再从main函数一行一行的开始,学着先读 .h 文件,了解数据结构,结合能找着的文档,脑补作者的思路,在这个基础上再去读源码,看自己和作者想的有什么不一样,经常能发现自己错误或者不周全的地方,偶尔也能窃喜和大师们的不谋而合。善用工具再后来发现原来有ctags这类东西,如有神助,加上这时对C语言的基本写法有了一些了解,读码效率顿时提升。今年下半年在lua和nginx中选了先读nginx代码,目前结合一些工具做记录,也颇有成效。理论与实践结合当然,我读过的所有源码,都不是为了读而读,基本都是我工作中经常会用到,会面对的一些东西。所以这里有一点也很重要,建议最好先了解你这个东西的功用,再去读源码,否则真的很难读懂。最最好的当然是经常用到的东西,自己对其本身的功能已经很熟悉了,甚至说内部实现机理都能略说一二,这时候读起来肯定更省力。教就是学读码之后写文章也不错,有时候你以为自己读懂了,真提笔要写一个模块分析的时候,突然发现还有东西是模糊的,或者前后逻辑串起来是矛盾的,这种事也常有。于是我一直认为,能真正写出一篇让人看得懂,没有问题的分析文章,才真的算是读懂了一个模块。我就先扯到这,期待更多牛人们的分享!
TA的最新馆藏分享》:关于阅读开源项目的源码思路方法 - 简书
分享》:关于阅读开源项目的源码思路方法
关于阅读开源项目的源码思路方法:《不喜勿喷》一般开源项目, 如果这个项目你很熟悉经常用, 那么你直接从 main 入手没问题.。如果你不熟悉或者代码量很大, 最好从代码的 example 代码 或者 client 的代码入手比较容易. 这些代码直接 gdb 进去就可以调试运行了, 客户端的功能搞清楚了,会用了, 恐惧感就降下去了, 再看服务端就容易了.看 c 代码要 关注主体核心 struct , 整个server, client 可能都是围绕整个 struct 运行起来的, 这个struct 的指针 传来传去. 而看 java 代码 就需要关注最主要的 interface, 通过 interface
看继承类.有的人喜欢微观从main开始看,有的喜欢宏观先看数据结构(接口), 这个都可以.另外看网络代码,最要关注的就是 何时 listen, 何时 accept, epoll_ctl 注入的几个函数是谁,对应java 里就是 selector 之后的几个读写函数. 找到这几个函数,基本网络框架就理解了, 网络模型就那么几种.看网络协议包处理函数可以让你更好的理解干巴巴的协议.看
help 函数 可以更快的知道 如何使用.如果代码不好调试, 根据程序运行的日志输出, 在代码里找日志输出点也是一种方法.自己写一个 cscope.sh 脚本, 放到path里, 代码下载下来在主目录运行一下就可以开看了.find . -name "*.h" -o -name "*.c" -o -name "*.py" -o -name "*.lua" -o -name "*.erl" -o -name "*.hrl" -name "*.java" && cscope.filescscope -bkq -i cscope.filesctags -Rctags -I __THROW --langmap=c:+.h --languages=c --c-kinds=+p --if0=yes --exclude=java --file-scope=yes -f systemtags /usr/include/* /usr/include/sys/*用 gdb 看代码, 反复进去退出, 写个 macro file 也是不错的b mainr --user=mysql --gdb --basedir=/usr/local/mysql --datadir=/usr/local/mysql/var --log-error=/usr/local/mysql/var/hoterran-laptop.err --pid-file=/usr/local/mysql/var/hoterran-laptop.pidset scheduler-locking offgdb -x macro-file libexec/mysqldgdb --args 挺好用的, 很多人喜欢在 gdb 里输入参数多麻烦阿.vim 的 ctags, cscop只能利用symbol 来查找还是弱了一点, 用 eclipse 看 java 就更加方便了, 看 扩展类, 看调用关系都是一个右键可以搞定的. java 项目可以利用 maven 把依赖的jar的 source 都下下来.我一般习惯左边显示器开代码(vim, eclipse). 右边我一般会开个 xmind, dia 或者 luchidchart, griffly 画画uml流程时序图什么的.尤其多线程的程序, 各种 lock 和 queue 调用, 你没有图比较难理清楚思路. 纸笔有的时候更加效果.个人觉得代码比看书更应该有产出, 我们可以看闲书一扫而过, 看代码最好还是记点笔记, 画个图. 方便回忆,方便continued.
如果想保护自己开源项目的源码不被逆向,详情了解,爱加密教你Android APP如何防止二次打包ExpandableTextView,可展开和收起的TextView,就像GooglePlay里面显示应用的描述那样。项目地址:/Manabu-GT/ExpandableTextView其中包含项目源码和示例代码。运行效果图:在国内很多应用中,也可以看到这种效果的使用场景。如豌豆荚的详情页:一、项目使用(1).在工程的build.gradle文件中添加项目引用。该项目较简单,java代码部分只有ExpandableTextView.java一个文件。&dependencies {
compile 'com.ms-square:expandableTextView:0.1.4'}(2).在布局中添加如下代码。注意,TextView的id只能定义为expandable_text,ImageButton的id只能定义为expand_collapse。
ExpandableTextView支持使用自定义属性。对应的attrs.xml文件及属性释义如下。
(3).添加Java代码。ExpandableTextView expandableTextView = (ExpandableTextView) rootView.findViewById(R.id.expand_text_view);// 设置显示内容expandableTextView.setText(&&);// 设置状态监听expandableTextView.setOnExpandStateChangeListener(new ExpandableTextView.OnExpandStateChangeListener() {
public void onExpandStateChanged(TextView textView, boolean isExpanded) {
}});二、源码分析实现原理:该View扩展自LinearLayout,由一个TextView和一个ImageButton组成,垂直排列。初始时,限定TextView的maxHeight使内容未完全显示,此时处于&收起&状态。当被点击时,为View添加自定义动画,在动画执行过程中,不断的修改TextView的maxHeight和整个View的height,达到&展开&和&收起&的效果。下面进入代码部分。其核心在于自定义动画的实现,和onMeasure()、onClick()方法。(1).类的定义。&ExpandableTextView继承自LinearLayout类,实现了OnClickListener接口,监听自身的点击事件,处理&展开&和&收起&。public class ExpandableTextView extends LinearLayout implements View.OnClickListener {}(2).成员变量介绍。&// 默认行数private static final int MAX_COLLAPSED_LINES = 8;// 默认动画时长private static final int DEFAULT_ANIM_DURATION = 300;// 动画启动时TextView的默认透明度private static final float DEFAULT_ANIM_ALPHA_START = 0.7f;// 显示内容的TextViewprotected TextView mTv;// 箭头按钮ImageButtonprotected ImageButton mB// 是否需要重新布局。当调用了setText()方法后,该值置为trueprivate boolean mR// 默认TextView处于收起状态private boolean mCollapsed =// 收起状态下的整个View的高度private int mCollapsedH// TextView整个文本的高度private int mTextHeightWithMaxL// 收起状态下的最大显示行数private int mMaxCollapsedL// TextView的bottomMarginprivate int mMarginBetweenTxtAndB// 箭头按钮的展开图标private Drawable mExpandD// 箭头按钮的收起图标private Drawable mCollapseD// 动画执行时长private int mAnimationD// 动画启动时显示内容的透明度private float mAnimAlphaS// 是否正在执行动画private boolean mA// 状态改变的监听private OnExpandStateChangeListener mL// 如果是在ListView中,需要使用到mCollapsedStatus和mPosition,保存当前position的展开或收起状态private SparseBooleanArray mCollapsedSprivate int mP(3).构造方法。在构造方法中,调用init()方法,执行初始化操作。包括获取布局文件中的自定义属性,设置默认按钮图标,设置方向,限定布局的方向只能为垂直。&public ExpandableTextView(Context context) {
this(context, null);}public ExpandableTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);}@TargetApi(Build.VERSION_CODES.HONEYCOMB)public ExpandableTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);}private void init(AttributeSet attrs) {
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.ExpandableTextView);
mMaxCollapsedLines = typedArray.getInt(R.styleable.ExpandableTextView_maxCollapsedLines, MAX_COLLAPSED_LINES);
mAnimationDuration = typedArray.getInt(R.styleable.ExpandableTextView_animDuration, DEFAULT_ANIM_DURATION);
mAnimAlphaStart = typedArray.getFloat(R.styleable.ExpandableTextView_animAlphaStart, DEFAULT_ANIM_ALPHA_START);
mExpandDrawable = typedArray.getDrawable(R.styleable.ExpandableTextView_expandDrawable);
mCollapseDrawable = typedArray.getDrawable(R.styleable.ExpandableTextView_collapseDrawable);
if (mExpandDrawable == null) {
mExpandDrawable = getDrawable(getContext(), R.drawable.ic_expand_more_black_12dp);
if (mCollapseDrawable == null) {
mCollapseDrawable = getDrawable(getContext(), R.drawable.ic_expand_less_black_12dp);
typedArray.recycle();
// 强制把方向设置为垂直
setOrientation(LinearLayout.VERTICAL);
// 默认不显示
setVisibility(GONE);}(4).onFinishInflate()方法。&当xml布局文件加载完成之后,后执行onFinishInflate()方法,在这里完成View的初始化。@Overrideprotected void onFinishInflate() {
findViews();}private void findViews() {
mTv = (TextView) findViewById(R.id.expandable_text);
mTv.setOnClickListener(this);
mButton = (ImageButton) findViewById(R.id.expand_collapse);
mButton.setImageDrawable(mCollapsed ? mExpandDrawable : mCollapseDrawable);
mButton.setOnClickListener(this);}(5).核心之onMeasure()方法。首先是条件判断,当View没有设置内容或内容为空,或者内容本身较短无需处理展开和收起,此时隐藏箭头按钮,直接return代码不再往下执行。然后,通过setMaxLines()缩小TextView的显示行数,计算TextView显示全部内容时的高度、整个LinearLayout的高度、TextView的bottomMargin值,并保存起来再之后执行动画时使用。@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 如果没有改变显示内容,或者显示内容为空,执行super.onMeasure()并返回
if (!mRelayout || getVisibility() == View.GONE) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mRelayout =
// 先隐藏箭头按钮,将文字最大显示行数设置到最大,后面再根据测量情况修改
mButton.setVisibility(View.GONE);
mTv.setMaxLines(Integer.MAX_VALUE);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 如果内容未超出限定的最大显示行数,直接返回。在这种情况下,无需展开和收起。
if (mTv.getLineCount() &= mMaxCollapsedLines) {
// 计算TextView的真实高度并保存
mTextHeightWithMaxLines = getRealTextViewHeight(mTv);
// 限定TextView的最大行数,并将箭头按钮显示出来
if (mCollapsed) {
mTv.setMaxLines(mMaxCollapsedLines);
mButton.setVisibility(View.VISIBLE);
// 再次重新测量
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mCollapsed) {
mTv.post(new Runnable() {
public void run() {
// TextView的bottomMargin
mMarginBetweenTxtAndBottom = getHeight() - mTv.getHeight();
// 保存收起状态下的整个View的高度
mCollapsedHeight = getMeasuredHeight();
}}// 获取TextView的真实高度,即内容展开时的高度private static int getRealTextViewHeight(@NonNull TextView textView) {
int textHeight = textView.getLayout().getLineTop(textView.getLineCount());
int padding = textView.getCompoundPaddingTop() + textView.getCompoundPaddingBottom();
return textHeight +}(6).核心之自定义动画的实现。继承Animation类实现动画,主要是重写Animation类的applyTransformation(float interpolatedTime, Transformation t)方法来实现自定义动画效果。要点:动画在执行过程中会反复的调用applyTransformation()方法,每次调用时参数interpolatedTime都在变化,从0逐渐递增为1,当该参数为1时表明动画结束。利用interpolatedTime参数,我们可以逐步改变TextView的高度、TextView的透明度和整个LinearLayout的高度,来达到展开和收起的效果。// 实现了展开/收起功能的动画class ExpandCollapseAnimation extends Animation {
private final View mTargetV
private final int mStartH
private final int mEndH
public ExpandCollapseAnimation(View view, int startHeight, int endHeight) {
mTargetView =
mStartHeight = startH
mEndHeight = endH
setDuration(mAnimationDuration);
protected void applyTransformation(float interpolatedTime, Transformation t) {
// 计算在执行动画时,逐渐变化产生的整个View的新高度
final int newHeight = (int)((mEndHeight - mStartHeight) * interpolatedTime + mStartHeight);
// 修改TextView的最大高度
mTv.setMaxHeight(newHeight - mMarginBetweenTxtAndBottom);
// 如果初始设置了透明度,修改TextView的透明度,直到alpha==1完全不透明
if (pare(mAnimAlphaStart, 1.0f) != 0) {
applyAlphaAnimation(mTv, mAnimAlphaStart + interpolatedTime * (1.0f - mAnimAlphaStart));
// 修改整个View的高度
mTargetView.getLayoutParams().height = newH
mTargetView.requestLayout();
}}// 改变View的透明度@TargetApi(Build.VERSION_CODES.HONEYCOMB)private static void applyAlphaAnimation(View view, float alpha) {
if (isPostHoneycomb()) {
// setAlpha()方法是Android3.0以上才有的api
view.setAlpha(alpha);
// 在Android3.0以下,使用AlphaAnimation并将Duration设置为0来实现
AlphaAnimation alphaAnimation = new AlphaAnimation(alpha, alpha);
alphaAnimation.setDuration(0);
alphaAnimation.setFillAfter(true);
view.startAnimation(alphaAnimation);
}}private static boolean isPostHoneycomb() {
return Build.VERSION.SDK_INT &= Build.VERSION_CODES.HONEYCOMB;}(7).核心之onClick()方法。触发点击时,Animation开始执行,主要是ExpandCollapseAnimation在构造时startHeight和endHeight的计算。执行&收起&动画时,从当前高度开始,降低到收起状态下的高度mCollapsedHeight;执行&展开&动画时,在当前高度的基础上,增加TextView变化的高度mTextHeightWithMaxLines - mTv.getHeight()。这里有个小细节,动画开始时标记mAnimating为true,结束时标记为false,标记mAnimating变量是为了在onInterceptTouchEvent()方法中使用。这样,在动画执行期间,可以拦截掉触摸事件,不传递给子View。@Overridepublic void onClick(View view) {
// 文字内容太短,无需折叠时,箭头按钮是隐藏的。这时直接返回。
if (mButton.getVisibility() != View.VISIBLE) {
// 将变量mCollapsed和mButton显示的图片赋值为相反
mCollapsed = !mC
mButton.setImageDrawable(mCollapsed ? mExpandDrawable : mCollapseDrawable);
// 将当前位置的状态保存起来,在ListView中需要使用
if (mCollapsedStatus != null) {
mCollapsedStatus.put(mPosition, mCollapsed);
// 标记动画开始
mAnimating =
if (mCollapsed) {
// &收起&动画,从当前高度开始,降低到收起状态下的高度mCollapsedHeight
animation = new ExpandCollapseAnimation(this, getHeight(), mCollapsedHeight);
// &展开&动画,在当前整个View高度的基础上,增加TextView变化的高度(mTextHeightWithMaxLines - mTv.getHeight())
animation = new ExpandCollapseAnimation(this, getHeight(), getHeight() +
mTextHeightWithMaxLines - mTv.getHeight());
animation.setFillAfter(true);
animation.setAnimationListener(new Animation.AnimationListener() {
public void onAnimationStart(Animation animation) {
// 动画开始,改变TextView的透明度
applyAlphaAnimation(mTv, mAnimAlphaStart);
public void onAnimationEnd(Animation animation) {
// 清除动画,防止applyTransformation()重复执行
clearAnimation();
// 标记动画结束
mAnimating =
// 通知listener
if (mListener != null) {
mListener.onExpandStateChanged(mTv, !mCollapsed);
public void onAnimationRepeat(Animation animation) { }
// 清除之前的动画,开启新的动画
clearAnimation();
startAnimation(animation);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {
// 动画执行期间,拦截掉触摸事件,不传递给子View
return mA}(8).其它方法之setText()。一般情况下,只需调用setText(text)方法即可。在ListView等存在item复用的情况下,需要调用setText(text,collapsedStatus,position)方法,这里使用了SparseBooleanArray记录当前位置的展开收起状态。以ListView为例,在实现BaseAdapter类的代码中,定义成员变量SparseBooleanArray collapsedStatus = new SparseBooleanArray(),当在getView()中调用setText(text,collapsedStatus,position)时,传入成员变量collapsedStatus和当前的position。&// 设置显示内容public void setText(@Nullable CharSequence text) {
mRelayout =
mTv.setText(text);
// 内容不为空时,才会显示
setVisibility(TextUtils.isEmpty(text) ? View.GONE : View.VISIBLE);}// 设置显示内容,在ListView等存在item复用的情况下需要使用该方法public void setText(@Nullable CharSequence text, @NonNull SparseBooleanArray collapsedStatus, int position) {
mCollapsedStatus = collapsedS
mPosition =
boolean isCollapsed = collapsedStatus.get(position, true);
clearAnimation();
mCollapsed = isC
mButton.setImageDrawable(mCollapsed ? mExpandDrawable : mCollapseDrawable);
setText(text);
getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
requestLayout();}(9).其它方法之setOnExpandStateChangeListener()。设置状态(&展开&、&收起&)改变的监听,可以根据实际需求决定是否使用该方法。public void setOnExpandStateChangeListener(@Nullable OnExpandStateChangeListener listener) {
mListener =}// 状态改变的监听器public interface OnExpandStateChangeListener {
* 当展开或收起的动画执行完毕之后,该方法被回调
* @param textView - 展开或收起的TextView
* @param isExpanded - 如果文字被展开,该值为true;否则为false
void onExpandStateChanged(TextView textView, boolean isExpanded);}(10).其它方法之setOrientation()。在setOrientation()方法中,限定了当前布局的方向只能为垂直。&@Overridepublic void setOrientation(int orientation){
if(LinearLayout.HORIZONTAL == orientation){
throw new IllegalArgumentException(&ExpandableTextView only supports Vertical Orientation.&);
super.setOrientation(orientation);}&就爱阅读网友整理上传,为您提供最全的知识大全,期待您的分享,转载请注明出处。
欢迎转载:
推荐:    

我要回帖

更多关于 java web开源项目源码 的文章

 

随机推荐