安卓andbase框架源码解读( 一)
常做开发,怎么能不用框架。框架不仅可以加快我们开发人员的开发效率,还能提高程序的可维护性所以花点时间来学习几个比较优秀的框架还是很有必要的,这样可以省去很多我们去写单调重复的代码的时间,专注功能逻辑的实现,快准狠地开发出优秀的产品。
本人更多的时间是在进行安卓开发,这里选取介绍的框架是andbase,优点这里我就不一一介绍了,不好的话我也不会花时间写博客来介绍它,项目地址:https://github.com/zhaoqp2010/andbase,官方网站http://www.amsoft.cn/post-47.html,里面有展示效果的图片,文档,还有一个apk,可以安到手机上看看效果是不是你想要的,
我觉得效果还是不错,比较符合主流趋势,在github上下载下来之后解压会得到两个项目,一个是源码,一个是demo,其中demo项目要引用源码项目,所以用的时候要将两个一起导入,demo项目会自动去找源码项目这个依赖,找不到的话就会在项目上显示红叉,好,现在都准备好了,让我们开始分析源码吧------〉
AbActivity是整个框架activity的基类,官方是建议activity继承这个类的,这样可以使你的项目有统一的结构,一会我们分析源码的时候我们就会发现,这个类为我们提供了很多常用的视图,比如标题栏titlebar,底部栏,一些进度条,toast,dialog,handler,总之可以让我们省去很多麻烦,当然你可以根据自己的需要再去扩展这个基类,那么作为重中之重,我们这次分析的就是AbActivity类,let‘s go!!!
这个类大约有900行代码,一点点分析是不太现实的,我这里只是捡重点难点来发表一下我的看法,相信弄懂了这些,这个类对你来说就是小case了。
这个类为了兼容较低的api,继承的是FragmentActivity,所以我们以后用的时候自然也可以使用FragmentActivity的属性和方法。
然后看属性,就像我们前面说的,既然这个类为我们提供很多方便的视图,那么自然就得有属性去支持它们,这些属性主要有调试标签TAG,日志开关D,加载进度条 ProgressDialog mProgressDialog;,从底部,中部,上部弹出的Dialog和对应的内容View,应用程序对象abApplication,各种LayoutParams,然后就是界面的结构了,
首先是RelativeLayout ab_base充当总布局,AbTitleBar mAbTitleBar作标题栏布局,AbBottomBar mAbBottomBar 做底部栏布局,RelativeLayout contentLayout做内容布局,
还有一个帧测试的AbMonitorView mAbMonitorView和mMonitorHandler,这两个我们暂时先不说,留到后面再讲,然后就是窗口管理对象WindowManager mWindowManager和它的Params:mMonitorParams,最后还有一个baseHandler,是用来处理发过来的异步消息的
private Handler baseHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case AbConstant.SHOW_TOAST: showToast(msg.getData().getString("Msg")); break; case AbConstant.SHOW_PROGRESS: showProgressDialog(mProgressMessage); break; case AbConstant.REMOVE_PROGRESS: removeProgressDialog(); break; case AbConstant.REMOVE_DIALOGBOTTOM: removeDialog(AbConstant.DIALOGBOTTOM); case AbConstant.REMOVE_DIALOGCENTER: removeDialog(AbConstant.DIALOGCENTER); case AbConstant.REMOVE_DIALOGTOP: removeDialog(AbConstant.DIALOGTOP); default: break; } } };
接着看onCreate函数,挑重要的说,
//主标题栏 mAbTitleBar = new AbTitleBar(this); //最外层布局 ab_base = new RelativeLayout(this); ab_base.setBackgroundColor(Color.rgb(255, 255, 255)); //内容布局 contentLayout = new RelativeLayout(this); contentLayout.setPadding(0, 0, 0, 0); //副标题栏 mAbBottomBar = new AbBottomBar(this); //填入View ab_base.addView(mAbTitleBar,layoutParamsFW); RelativeLayout.LayoutParams layoutParamsFW2 = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); layoutParamsFW2.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE); ab_base.addView(mAbBottomBar, layoutParamsFW2); RelativeLayout.LayoutParams layoutParamsFW1 = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); layoutParamsFW1.addRule(RelativeLayout.BELOW, mAbTitleBar.getId()); //跟我们在xml中设置android:layout_below="@id/..."一样 layoutParamsFW1.addRule(RelativeLayout.ABOVE, mAbBottomBar.getId()); ab_base.addView(contentLayout, layoutParamsFW1);
这里就是刚才说的在整个布局里添加标题栏,底部栏,和显示的主要内容,因为用的相对布局,而且是在代码中设置的,可能这里看起来比较费劲,尤其是addRule方法,之前不知道,跳到源码中看了看其实就是在LayoutParams中有一个整形数组,属性作为int保存,我们设置的是属性对应的值,就是这个方法
public void addRule(int verb, int anchor) { mRules[verb] = anchor; }
然后再挑着往下看,我们平常要用的函数就在这里,包括弹出Toast,设置内容界面,这个有好几个重载的函数,咱们看一个就懂了
public void setAbContentView(View contentView) { contentLayout.removeAllViews(); //先将原先的内容清掉 contentLayout.addView(contentView,layoutParamsFF);//再将新加的布局加到内容中去, //ioc initIocView(); }
我们看到这里调用了一个initIocView方法,那么就让我们深入进去,
private void initIocView(){ Field[] fields = getClass().getDeclaredFields(); if(fields!=null && fields.length>0){ for(Field field : fields){ try { field.setAccessible(true); if(field.get(this)!= null ) continue; AbIocView viewInject = field.getAnnotation(AbIocView.class); if(viewInject!=null){ int viewId = viewInject.id(); field.set(this,findViewById(viewId)); setListener(field,viewInject.click(),Method.Click); setListener(field,viewInject.longClick(),Method.LongClick); setListener(field,viewInject.itemClick(),Method.ItemClick); setListener(field,viewInject.itemLongClick(),Method.itemLongClick); AbIocSelect select = viewInject.select(); if(!TextUtils.isEmpty(select.selected())){ setViewSelectListener(field,select.selected(),select.noSelected()); } } } catch (Exception e) { e.printStackTrace(); } } } }
其实就是通过反射让我们可以使用注解来声明view控件,省去繁琐的findviewbyId,比如我们之前要用id为tv_name的textview,要这样写
TextView name; name = (TextView)(findViewById(R.id.tv_name));
而现在我们只需要用注解声明一下就ok了
@AbIocView(id=R.id.tv_name) TextView name;
这和很多的注解框架是一样的道理,不过在这里我们就看到了注解底层的实现原理,是不是一下子顿悟了,当然这里用到了反射机制和自定义注解,所以对于一些初学者还是建议先去看看这方面的知识,我们来看AbIocView的源码,就是自定义的注解,
@Target(ElementType.FIELD) //作用于属性 @Retention(RetentionPolicy.RUNTIME) //编译器将annotation存储于class中<span style="color: rgb(103, 102, 21); font-family: ‘Hiragino Sans GB W3‘, ‘Hiragino Sans GB‘, Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; line-height: 28px; "> </span> public @interface AbIocView { public int id(); //属性必须,其他可以不指定,因为有默认值 public String click() default ""; public String longClick() default ""; public String itemClick() default ""; public String itemLongClick() default ""; public AbIocSelect select() default @AbIocSelect(selected="") ; }
AbIocSelect类似,大家就自己去看吧就当是巩固上面学到的东西了,然后在刚才的initIocView中有这么个方法setListener,就是根据AbIocView那几个方法设置监听器,相信大家肯定能看懂,这里我就不说了
openMonitor和closeMonitor就先不说了,一般也用不到(其实是我还没有看到那里),再然后就没有然后了吧,ok,今天的分析就到这里,若有错误,敬请提出,大家交流学习,共同进步---〉
睡觉qu,累死了
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。