2017安卓主流框架搭建?看这篇就够了(上)

  • 前言:记得那是2014年8月份13号,在亲戚的鼓励下,C#转android,自学了15天网上下载的“黑马视频”后,怀着忐忑不安的心情被带来了深圳,赶鸭子上架般接手了人生中的第一个android项目“橙果新闻”。当时毫无框架的概念,listview也没有viewholder优化,整个app可以说各种卡顿!然鹅,,,对于初学的我来讲,当时的追求也只是app不闪退就好,哈哈。
    转眼三年有余,前段时间新公司app项目重构,采用的主框架正好是当下比较热门的MVP+RXJava2+Retrofit2.0,当时由于时间紧任务重,粗略的看了看使用方法就开始编码了,这段时间项目小版本迭代空闲时间多,于是决定将别人整理,封装的框架自己再整理完善一下,以后开发项目都可以用这一套熟练的进行开发了!

构建顺序:

1.常用基础工具类(包括File,Bitmap,字符串处理,图片加载等,UI辅助等等)
2.基类BaseActivity,BaseFragment的构建(titlebar,statebar,loadingview,defalutview四大模块的封装)
3.屏幕适配(图片,长度)
4.mvp模式(使用MVPPluge插件,自动生成MVP的类文件以及该插件的改装)
5.网络框架的接入(RXJava2+Retrofit2.0)


6.gradle多环境配置(测试,预发布,正式)
7.CI自动化打包上传(jenkins+git+码云or蒲公英)

*其中1,2,3跟业务逻辑关系不大,我抽取出来作为一个lib,下载过去直接应用就行。

本次系列文章,本人一改之前懒得传代码的尿性,完整的demo项目地址将会在系列结束后贴上(目前还在整理中),恩,拿去就用!你值得clone


一.常用工具类清单:

Base64Util:图片文件与Base64互转。
BaseBitmapUtil:处理图片的压缩,缩放,裁剪,旋转,并且含有代码创建一些Drawable XML的方法
BaseConstant:定义一下常量
BaseFileUtil:文件的常用操作方法
BasePackageUtil:获取包信息,检查包名应用是否安装等pack相关方法
BaseStringUtil:常规例如:手机号,邮箱等的正则检验,全半角转换,等字符串处理方法
DateUtil:给我时间戳~给你各种日期,时间
KeyboardHelper:专业处理软键盘遮挡,软键盘隐藏,显示等
NetworkUtil:获取网络状态等方法
PreferUtil:专业处理shareperder数据
UiUtil:.提供常见的获取屏幕宽高、获取各种资源等方法,px dp转换,提供延时处理的Handle
这部分没啥好说,都是一些常用的方法,开发必备,当然也不那么完善,根据需求,后期再添加


二.(重点来了)基类BaseActivity,BaseFragment的构建:

一个功能完善,封装优雅的基类无疑可以很大程度上减少重复代码,使得开发时可以专注于业务逻辑,而不是在什么导航栏啊,缺省页啊,加载框啊之类的东西上反复花时间!BaseActivity里面封装了titlebar,statebar,loadingview,defalutview四大模块,开发时界面Activity的相关的UI直接几行代码配置即可,十分方面。
且BaseFragment里面会获取父容器activity,然后直接复用BaseActivity的各种方法。既然是重点,那么下面就来详细讲讲四大模块的封装。

TitleBar

导航栏,toolbar有自身的一些缺陷,还是感觉不够灵活,所以自己封装一个公用的TitleBar是很有必要的。
封装过程:
1.画一个导航栏布局layout,明确导航栏的基本组成,这里我是直接封装了三个Textview,由于Textview有一个drawableX属性,这就使得每个Textview既能做纯文本,又能图文混合, 左右中,三个Textview,基本够用了。

2.定义一个BaseTitleBar接口,里面定义好常用方法:

 /*设置整体背景色*/
BaseTitleBar setBgColor(int color);

/*标题栏相关*/
BaseTitleBar setTitle(@StringRes int StringResId);

BaseTitleBar setTitle(String text);

BaseTitleBar setTitleIcon(@DrawableRes int drawableId);

BaseTitleBar setTitleTextColor(int color);


/*右侧文本或按钮相关*/
BaseTitleBar setRightText(String text);

BaseTitleBar setRightText(@StringRes int stringResId);

BaseTitleBar setRightIcon(@DrawableRes int drawableId);

BaseTitleBar showRightTextView();

BaseTitleBar hideRightTextView();

BaseTitleBar setRightTextColor(int color);

BaseTitleBar setRightTextClickListener(View.OnClickListener listener);


/*左侧文本或按钮相关*/
BaseTitleBar setLeftText(String text);

BaseTitleBar setLeftText(@StringRes int stringResId);

BaseTitleBar setLeftIcon(@DrawableRes int drawableId);

BaseTitleBar showLeftTextView();

BaseTitleBar hideLeftTextVeiw();

BaseTitleBar setLeftTextColor(int color);

BaseTitleBar setLeftTextClickListener(View.OnClickListener listener);

int getId();

OK,机智如你,一看这些方法名字就懂了吧。

3.创建TitleBar,继承FrameLayout,实现BaseTitleBar,具体的代码就不贴了,之后自己看。

StateBar

关于状态栏,网上有太多教程,太多方法,太多框架了,这里针对SDK>Build.VERSION_CODES.KITKAT,统一隐藏状态栏,然后建个StateBar去覆盖,StateBar的颜色自定义,还可以隐藏,效果感觉还不错,就不去使用框架了,如果您对状态栏要求比较高,一定要多种效果,一定要适配侧滑等等 那你可以略过StateBar,自己去封装下就好。
封装过程:
1.定义接口BaseStateBar,明确需要提供的方法

void hide();

void show();

void setBackgroundColor(int color);

void setBackgroundDrawable(@DrawableRes int resId);

View getView();

int getId();

boolean isEnabled();

2.创建StateBar,实现BaseStateBar接口

至于具体在BaseActivity中如何去初始化StateBar,可以详见BaseActivity代码

Loadingview

终于到了Loadingview,想想还有点小激动!因为这次,再也不用gif,不用帧动画,不同一张破图旋啊转,用上了大名鼎鼎的lottie,然如您还没有听说过或者使用过lottie(好low啊,掩面偷笑中..)可以看看这篇简单的介绍,内有大量免费炫酷示例,down一下就进自己的app了,,这X装的豪不费功夫有木有?
http://www.jianshu.com/p/15c18049f642

LoadingView的封装相对简单,画个xml,在baseactivity中提供两个方法show,hide 你懂的,重点就是引入了lottie,炫酷不止一点点~打了好多字,这里放一段demo里用lottie实现的启动动画来缓解一下木有图的尴尬吧!

SM-G9350_20170920211104.gif

缺省页Defaultview

总结起来,app中的缺省页其实无外乎以下几种:
1.无网络缺省页面
2.网络请求错误缺省页
3.空数据缺省页
另外除了缺省页有时候只是toast一下,并不需要缺省页,具体如何,得看业务,得听产品的!哈哈
这里针对最为复杂的情况做一下封装,其他简单情况自然好处理
复杂情况:

进入页面一瞬掉咔嚓断网,显示带有““”刷新看看”按钮的无网络缺省页
点击刷新看看请求网络后服务错抛出错误,显示网络错误缺省页,并且带有按钮“再试试"
点击再试试,请求正常了,可是没有业务数据,显示空数据缺省页,带有按钮“XXXX”
点击按钮XXXX,响应别的业务逻辑

思路有两种:
1.多个defaultview实例,分别控制各个view的层级,显示状态
2.一个实例,根据需要动态变换view中的文本,按钮,图片
对比一下就明白,思路1处理起来会比较麻烦,万一有更复杂的情况需要继续添加不同的defaultview
所以这次的框架中采用思路2,一个defaultview,各种变换!

封装过程和loading大同小异,只不过提供的方法会多一些,三个核心view
图片Image,文本Textview,按钮Textview

BaseActivty中需要封装的四个模块已经分析完,那么他们如何封装进BaseActivity里呢?
大家都知道,ViewGroup有个Addview方法可以添加子类,那么在BaseActivity中设置一个根RelativeLayout,初始化添加StateBar和TitleBar后,将子界面的contentview添加到TitleBar下方:

  //mContainer为根RelativeLayout
  mContainer.addView(view, getLayoutParams());
  private RelativeLayout.LayoutParams getLayoutParams() {
    RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    if (titleBar != null) {
        lp.addRule(RelativeLayout.BELOW, titleBar.getId());
    } else if (stateBar.isEnabled()) {
        lp.addRule(RelativeLayout.BELOW, stateBar.getId());
    }
    return lp;
}

而LoadingView和DefaultVie在需要的时候直接addView进根RelativeLayout,不用addrule。
到此为止,BaseActivity的封装基本完成。至于BaseFragment中就更简单了,除了DefultView之外,其他的地方直接:

         public void XXXXX() {
          BaseActivity baseActivity = getBaseActivity();
          if (baseActivity != null) {
               baseActivity.XXXXX();
       }
  }

意思就是任何BaseActivity里面封装过调度UI的方法在BaseFragment里直接通过获取父容器Activity后复用一下。 可以是对于DefaultVie却不能这么用,这是为神马呢?哈哈,留个课后习题,欢迎留言里回答~


三.屏幕适配

网上关于anroid适配的文章太多太多,这里就不去复制了,直接说简单处理方法

适配图片:使用mipmap系列文件夹放图片,mipmap系统会在缩放上提供一定的性能优化,

让UI切一套720P的图(或者用ios 750的,如果UI太懒,你又搞不定他),放入mipmap-xhdpi文件夹 这一套其实就够了,不同分辨率手机上系统会自动去缩放,如果担心高分辨率图片变的模糊可以再适配一套xxx的,反正我的S7edge上基本看不出差别。

长度适配:
多dimens.png

如图,简单解释一下,w300dp表示手机 分辨率和手机屏幕密度经过计算后得出该手机宽度300dp
框架中设置了300-420范围的宽度文件夹,绝对涵盖了96%+主流的手机宽度。

像素px =dp* (屏幕密度/160)

一个720px的手机,如果屏幕密度是320,那么他的宽度用dp表示就是360dp,会使用w360里面的dimen,而点开W360里面的deimens看一下

W360.png

我们设置的dp1正好也是1dp,那么如果UI按照720P给你标注,你直接按标注的px除以2用dp就好。
你可能会问,如果我的手机不是W360的呢? 例如去年的机皇S7edge:

S7edge.png

按照公式像素px =dp* (屏幕密度/160)
算出 S7的屏幕宽度是1440/(534/160)= w431.46

系统会根据手机的宽度去选择接近的尺寸文件夹(听说是向下取,431的手机还是会用w420,不会用w440?未实测哦),如果UI按照720P给你标注一个头像Image的宽度是100px, 你还是除以2,用50dp

   <ImageView         
       android:layout_width="@dimen/dp50"
        android:layout_height="@dimen/dp50"
      />

注意,这时候是W420文件夹里的dp50哦,同样 打开看看

w420.png

可以看到,同样取dp50,这时候设置的是58.3, 然后你再算算
58.3/50 是不是 约= 420/360
至于明明是w431,可是取的是w420,或者一个w359的设备向下取到w340怎么办?

joke.png

其实不用太纠结,正常设备宽度350+,359和340差了屏幕宽度的1/17,也就是说如果50dp最多相差3dp,基本可以忽略。如果你不能接受这个说法,那么我会继续说服你,359-340也是极端情况了,哪里去找正好359的设备呢? 如果你还不服,那你去建立一个w350,甚至w355的吧,误差可以控制在1dp。
如果你真的打算这么做的话,那你一定是处女座!处女座!!

truth.png

处女座追求完美也没有错,至于w350,甚至w430+的dimens怎么产生的 其实很简单,网上有脚本,找来跑一下,或者直接一个for循环啊,比如wXXX的

  for(int i=1:i<500;i++){
    float value=XXX/360*i;
    Logger.d("<dimen name="dp"+i+">"+value+"dp</dimen>")

}

好了,篇幅原因,上篇到此为止,可能文中有些不准确或者错误的地方欢迎指出,大家一起进步!下个月25号见。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容