码个蛋(codeegg)第 623 次推文

作者:厘米姑娘

博客:https://www.jianshu.com/p/3718766df5ba

本周知识清单如下,ps本周的感悟非常诚恳不容错过哦~

  • 颜色透明度计算

  • SpannableString类

  • 快速切换到主线程更新UI的三种方法

  • RecycleView的item动画

  • 使用Rxjava实现点击防抖动

  • Java基础之异常机制

  • 一些小感悟

1.颜色透明度计算

如果UI在设计图中标注的颜色是这样的#FF0000(10%不透明度),那就需要进行颜色透明度的计算。

a.颜色:

Android中颜色值通常遵循RGB/ARGB标准,使用时通常以“#”字符开头,以16进制表示。

  • RGB:红色(Red)、绿色(Green)、蓝色(Blue)

  • ARGB:透明度(Alpha)、红色(Red)、绿色(Green)、蓝色(Blue)

比如#FF99CC00:FF 是透明度,99是红色值,CC是绿色值,00是蓝色值

b.透明度

  • 透明度共分256阶,对应0~255。比如,透明=0阶,50%透明=127阶,不透明=255阶

  • 在计算机上对应16进制00~FF

  • 透明度+不透明度=100%。比如,透明度10%,也就是不透明度90%

c.计算步骤

假设,UI给出的颜色是#FFFFFF(40%透明度),计算步骤如下:

  • 如果给的是透明度,先将透明度转换成不透明度,即不透明度为60%

  • 不透明度255,即40%255=153

  • 将计算结果转换成16进制,即153的16进制是99

  • 最后拼接成ARGB格式,即最终的颜色值: #99FFFFFF

为了节约时间,这里直接给出最终计算结果,查表就好啦!

2.SpannableString类

有时候为了美观和醒目,会给一个TextView中显示的文字设置不同的大小或颜色等样式,笨方法是分别设置多个Textview,聪明方法当然就是用本节介绍的富文本工具SpannableString了!

a.方法

//设置字符串指定区间内的格式
setSpan(Object what, int start, int end, int flags)

参数含义:

what : 文本格式,如前景色、下划线、模糊、超链接等,常用几个:

  • ForegroundColorSpan前景色&BackgroundColorSpan背景色

  • RelativeSizeSpan相对大小&AbsoluteSizeSpan绝对大小(单位:像素px)

  • StrikethroughSpan中划线&UnderlineSpan下划线

  • SuperscriptSpan上标&SubscriptSpan下标

  • StyleSpan 可设置粗体new StyleSpan(Typeface.BOLD)、斜体new StyleSpan(Typeface.ITALIC)

start : 需要设置格式的字符串起始下标

end : 需要设置格式的字符串结束下标

flags : 标识start和end是否被包括,符号[和]表示包括,符号(和)表示不包括,四种属性:

  • Spanned.SPAN_INCLUSIVE_EXCLUSIVE: [起始下标,结束下标)

  • Spanned.SPAN_EXCLUSIVE_EXCLUSIVE :(起始下标,结束下标)

  • Spanned.SPAN_INCLUSIVE_INCLUSIVE :[起始下标,结束下标]

  • Spanned.SPAN_EXCLUSIVE_INCLUSIVE: (起始下标,结束下标]

更多效果见:SpannableString 你应该知道的那些效果显示(https://blog.csdn.net/u012551350/article/details/51722893)

b.示例

还记得之前说的占位符吗?详见[周记(二)](https://www.jianshu.com/p/7b9abda70c8f),这里配合占位符给出个小例子,来一招双剑合璧~

//string.xml
<string name="total">共 %1$d 元</string>//设置金额的颜色为白色,大小为36像素
public void setTotalText(int total) {SpannableString spannableString = new SpannableString(getResources().getString(R.string.total, total));ForegroundColorSpan color = new ForegroundColorSpan(Color.parseColor("#FFFFFF"));spannableString.setSpan(color, 2, 2 + String.valueOf(total).length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);spannableString.setSpan(new AbsoluteSizeSpan(36), 2, 2 + String.valueOf(total).length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);mTotalText.setText(spannableString);}

3.快速切换到主线程更新UI的三种方法

a.Activity.runOnUiThread(Runnable)

把更新UI的代码创建在Runnable中,并传给  Activity.runOnUiThread()如果当前线程是UI线程,那么会立即执行;反之,会调用UI线程handler.post()将其放入UI线程的消息队列中

new Thread(){public void run() {//此时在子线程((MainActivity) context).runOnUiThread(new Runnable() {@Overridepublic void run() {//此时已经回到主线程,注意要强转到主线程的MainActivity}});};
}.start();

b.View.post(Runnable)

  • 如果View已经attach到Window,直接调用UI线程的Handler发送Runnable到MessageQueue

  • 如果View还未attach到Window,将Runnable放入ViewRootImpl的RunQueue中,RunQueue会实现延迟执行Runnable任务,并且Runnable最终不会被加入到MessageQueue里,也不会被Looper执行,而是等到ViewRootImpl的下一个performTraversals时候,把RunQueue里的所有Runnable都拿出来并执行,接着清空RunQueue

mTextView.post(new Runnable() {@Override//可快速更新该viewpublic void run() {mTextView.setText("xxx");//也可以更新其他viewmIageView.setBackgroundResource(R.drawable.icon);}
});

还有View.postDelayed(Runnable, long),其中long表示延迟的毫秒数,示例如下。

//5秒倒计时跳转到下个页面
index=5;
mTextView.postDelayed(new Runnable() {@Overridepublic void run() {mTextView.setText("" + index);index--;if (index == 0) {Intent intent = new Intent(MainActivity.this, SecondActivity.class);startActivity(intent);} else {mTextView.postDelayed(this, 1000);}}}, 1000);

c.Handler.post(Runnable)&Handler.post(Runnable,long)有关Handler机制详见[要点提炼|开发艺术之消息机制](https://www.jianshu.com/p/1c79fb5296b6)

//假设在子线程,需要获取主线程的Looper和Queue
new Handler(Looper.getMainLooper()).post(new Runnable() {@Overridepublic void run() {//此时已经回到主线程}});

当然还可以用AsyncTask、IntentService、HandlerThread,详见[要点提炼|开发艺术之线程](https://www.jianshu.com/p/ab77a2e83c52),还有许多开源框架,因为这里强调快速,所以其他这些可自行了解~

4.RecycleView的item动画

临上线前一刻UI又想调整动画,因为RecycleView本身有给item设置一些增加和删除的动画效果,如果要自定义就需要重写一些方法了,之前在要点提炼|开发艺术之Animation介绍过Android的三种动画,所以不过是大同小异,这里给出一个自定义的增加动画小例子理解一下。

//设置动画开始前初始状态@Overrideprotected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {//设置锚点,这里以item的中心点为锚点放大holder.itemView.setPivotX(holder.itemView.getWidth() / 2);holder.itemView.setPivotY(holder.itemView.getHeight() / 2);holder.itemView.setAlpha(0);//初始状态为完全透明}//设置动画放大效果,这里的效果是先放大1.2倍再缩小到原样,透明度0到1@Overrideprotected void animateAddImpl(final RecyclerView.ViewHolder holder) {final DefaultAddVpaListener listener = new DefaultAddVpaListener(holder);ViewCompat.animate(holder.itemView)//为当前item开启一个动画.scaleX(1.2f)//x方向放大1.2倍.scaleY(1.2f)//y方向放大1.2倍.setDuration(300)//动画持续时间300ms.alpha(1)//动画结束时为完全不透明.setInterpolator(mInterpolator)//设置插值器.setListener(new ViewPropertyAnimatorListener(){//设置动画监听器,包括动画开始、结束和取消@Overridepublic void onAnimationStart(View view) {listener.onAnimationStart(view);}@Overridepublic void onAnimationEnd(View view) {//上一个动画结束后300ms再缩小item到原大小,持续时间200msViewCompat.animate(holder.itemView).scaleX(1f).scaleY(1f).setDuration(200)//动画持续时间200ms.setInterpolator(mInterpolator).setListener(new ViewPropertyAnimatorListener(){@Overridepublic void onAnimationStart(View view) {listener.onAnimationStart(view);}@Overridepublic void onAnimationEnd(View view) {listener.onAnimationEnd(view);}@Overridepublic void onAnimationCancel(View view) {listener.onAnimationCancel(view);}}).setStartDelay(300)//延迟300ms启动动画.start();}@Overridepublic void onAnimationCancel(View view) {listener.onAnimationCancel(view);}}).start();//启动动画}

这里只给了动画实现,至于怎么和Adapter配合到item上的全过程参考文章 :RecyclerView的动画实现(移除、添加、改变、移动)和自定义动画的实现(https://blog.csdn.net/superbiglw/article/details/53392877)。

5.使用Rxjava实现点击防抖动

之前测试提了个bug,是由快速点击Button导致的,听闻我的表情如下,为了周全考虑到用户各种习惯这操作也是很疯狂了。解决思路是给按钮点击添加防抖处理,在一定时间内无论点击多少次都只调用一次事件,这里用了Rxjava去实现,文章贴下Android RxJava 实战系列:功能防抖(https://blog.csdn.net/uisoul/article/details/79114856)。

传统办法是进行前后两次点击时间间隔判断,如果大于设定的时间间隔再执行点击事件,代码如下:

public abstract class OnMultiClickListener implements View.OnClickListener {public static final int MIN_CLICK_DELAY_TIME = 1000;private long lastClickTime = 0;@Overridepublic void onClick(View v) {long currentTime = Calendar.getInstance().getTimeInMillis();if (currentTime - lastClickTime > MIN_CLICK_DELAY_TIME) {lastClickTime = currentTime;onMultiClick(v);}}public abstract void onMultiClick(View v);//具体点击事件
}

6.Java基础之异常机制

当一个程序出现错误时,可能是以下三种错误:

  • 语法错误:如缺少必要的标点符号、关键字输入错误、数据类型不匹配等,在编译器对程序进行编译的过程中,会把检测到的语法错误以提示的方式列举出来,故又称为编译错误。

  • 运行时错误:如空指针异常,数组越界,除数为零、数据库连接失败等,迫使程序终止,有特定的发生条件。

  • 逻辑错误:在语法上是有效的,但是在逻辑上是错误的,此类问题不好调试。

这里说的Java异常处理机制主要是指处理运行时错误。

a.Throwable继承层次结构,可见分成两大类Error和Exception。

Error(错误):指程序无法恢复的异常情况,表示运行应用程序中较严重的问题。

  • 发生于虚拟机自身、或者在虚拟机试图执行应用时,如Virtual MachineError(Java虚拟机运行错误)、NoClassDefFoundError(类定义错误)。

  • 属于不可查异常,即不强制程序员必须处理,即使不处理也不会出现语法错误。

Exception(异常):指程序有可能恢复的异常情况,表示程序本身可以处理的异常。又分两大类:

1:RuntimeException(运行时异常):由程序自身的问题导致产生的异常。

  • 如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)。

  • 属于不可查异常。

2:非运行时异常:由程序外部的问题引起的异常。

  • 除了RuntimeException以外的异常,如FileNotFoundException(文件不存在异常)。

  • 属于可查异常,即强制程序员必须进行处理,如果不进行处理则会出现语法错误。

附:常见的异常及其含义如图

b.异常处理机制

(1)捕捉异常:由系统自动抛出异常

try 捕获异常:用于监控,若发生异常,会抛出异常类所产生的对象并立刻结束执行,并转向异常处理catch块。

catch 处理异常:若抛出的异常对象属于catch内所定义的异常类,则进入catch中的对应代码段继续运行程序,反之进入finally块。常用方法:

  • e.getMessage():返回异常对象的一个简短描述

  • e.toString():获取异常对象的详细信息

  • e.printStackTrace():在控制台上打印异常对象和它的追踪信息

finally 最终处理:无论是否捕获或处理异常,finally块里的语句都会被执行。在以下4种特殊情况下,finally块才不会被执行:

  • 在finally语句块中发生了异常

  • 在前面的代码中用了System.exit()退出程序

  • 程序所在的线程死亡

  • 关闭CPU

try {  // 可能会发生异常的程序代码
} catch (异常类1  异常变量) {  // 捕获并处理try抛出的异常类型Type1
} catch (异常类2  异常变量) {  // 捕获并处理try抛出的异常类型Type2
} finally {  // 无论是否发生异常,都将执行的语句块
}

注意:

一个try、catch、finally之间不能插入其它代码

catch可有多个,try和finally只能有一个

try后面必须至少跟着catch和finally其中的一个

(2)抛出异常:在方法中将异常对象显性地抛出,之后异常会沿着调用层次向上抛出,交由调用它的方法来处理。

  • throws:声明抛出的异常,位置在方法名后、异常类型前

  • throw:抛出异常,一般在方法体内部

(3)自定义异常:继承Execption类或其子类,实现步骤如下:

  • 声明自定义异常类并继承Exception,可重写方法如getMessage()

  • 在方法头用throws声明该方法可能抛出的异常

  • 在方法体的适当位置创建自定义异常类对象,并用throw将异常抛出

  • 调用该方法时,对可能产生的异常进行捕获,并处理异常

//1.自定义的异常类
class MyException extends Exception { String message; public MyException(String ErrorMessagr) { super(ErrorMessagr) ;}public String getMessage() {return message;}}public class Demo {public static void main(String[] args) {//4.调用方法时捕获和处理try {test();} catch (MyException e) {System.out.println(e.getMessage());e.printStackTrace();}}//2.在方法头声明可能出现的异常public static void test() throws MyException{try {int i = 10/0;System.out.println("i="+i); } catch (ArithmeticException e) {//3.在适当情况下抛出异常throw new MyException("This is MyException"); }}
}

推荐阅读:java程序错误类型及异常处理(https://www.cnblogs.com/liaoliao/p/5009150.html)

7.一些小感悟

转瞬一周又过去了,项目终于发版上线了,新的一期需求评审也如期而至,感觉一切都在渐入佳境,收获也沉甸甸的,越发觉得不枉此行。(这是感悟略长的节奏啊...)

上周有幸赶上同事们每半年的绩效考核,于是旁听了整个项目前端组的述职大会,几个小时下来,感悟颇深。想起大一曾修过一门有关职业规划的课程,让我意识到大学千万不能荒度,要有计划地准备和积累求职的筹码和资本,不要最后才发现简历一无所有,这门课深刻的影响了我整个大学,我想大概这次述职大会也或多或少地影响我未来的职业生涯吧。

首先是述职的内容,分成两个部分,第一部分是对上期工作的回顾,包括做了什么、有什么价值,遇到并解决的问题、影响取得业绩的障碍、上期做的好的地方,做的不好的地方以及个人成长收获;第二部分是下期工作计划,包括工作内容、个人成长计划以及给团队建议(如业务、技术、文化等)。

听罢不禁感慨身边的牛人真的很多,有的人能保质保量的完成业务需求,并且通过一定的关键指标和数据来衡量和评价,比如线上报错统计、各种异常现象数目统计、用户访问量等等;有的人有良好的开发流程规范,有整理和产出各类研发文档的好习惯;有的人注重代码质量,不断重构代码、优化性能、奉行『异常的考虑要大于功能的实现』;有的人在工作之余仍不忘学习,比如深入理解公司框架源码、维护个人wiki并发表高质量的技术文章、积极主动进行组内知识分享、加入公司读书协会并坚持打卡取得多本赠书奖励......

其中一个小姐姐的有个细节显得与众不同,就是她提前就准备好了答辩稿并使用PPT的演讲者模式,使得整个答辩很流畅自如。可能因为自己本身商科出身也有些答辩经历,自认为答辩前要准备好的不仅是一个质量高的PPT,还需要有答辩稿配合、并进行一定的语速和仪态练习,虽然无关于开发技术,但真的会增添不少亮色,给人很好的听觉体验。

这阵子也在陆陆续续进行code review,因为有个梳理整个项目业务逻辑的任务,所以很认真的边听边想边做记录,全程只有一个感受--『不明觉厉』,大家都全神贯注的检查每个实现,不放过任何一个可能存在的异常,或者提出更好的解决思路。虽然指出的很多关键点我都有所闻,但由于缺少项目实践,没有学以致用,所以很难一下子联系到某个场景,越发感觉自己任重而道远。

最后不得不再次夸奖一番我风格迥异的同事们,真的是个很可爱的团队呢。严肃内敛、务实又靠谱和平易近人、认真又负责的两位宝爸--组长和导师,工作严谨爱钻研、生活却不失浪漫的的话题达人超哥,热爱运动、喜欢分水果、开朗风趣、才艺俱佳的颜值担当田丰大哥哥,还有稳重憨厚、技术全能、我的学习榜样杨宇大哥哥,他就是那种每天早上背单词、早来一小时看英文技术书、GitHub各种自写的千stars的开源框架、只看美剧来学英文、前后端通吃、脑瓜里各种知识百宝库、却是和我年龄最近的那个人。有这些的小伙伴,实习都是件很开心的事啊!

近期文章:

  • 《每日一道面试题》 第二期

  • 腾讯面试我竟倒在一个警察抓小偷题上

  • Flutter 入门指北之手势处理和动画

今日问题:

你实习期间,遇到的最有意义的问题是?~

快来码仔社群解锁新姿势吧!社群升级:Max你的学习效率

我方卧底发自美团的真实Android资料相关推荐

  1. ”面霸“夏派卧底阿里、百度、美团等大厂带来面试题及答案

    面试,难还是不难?最终结果好还是不好?取决于面试者的底蕴(气场+技能).心态和认知以及沟通技巧.而一些主流的大型互联网公司面试(阿里巴巴.京东.美团.滴滴)更是需要你在面试时展现出自己的能力,从而获得 ...

  2. 2017派卧底去阿里、京东、美团、滴滴带回来的面试题

    转载自 2017派卧底去阿里.京东.美团.滴滴带回来的面试题及答案 一,阿里巴巴面试题 二,京东面试题 三,美团面试题 四,滴滴面试题 五,本次卧底面试得到的结论 通过面试题来看,可以看出目前互联网公 ...

  3. 我发现不少培训班的就业辅导老师,简直是面试官的卧底——再论培训班学员的就业方式(java方向)

    我最近在帮一些朋友做java方面的就业辅导,其中有些朋友是经过培训班加持后入行java的.由于我本人做过一些大厂和外企的java技术面试官,我发现其中一些朋友的简历甚至根本没法通过小公司的筛选,而且不 ...

  4. 卧底“刷量”卖家,有关微信公众号“刷量”的五个劲爆事实

    今天,公众号"刷量"工具瘫痪的消息被爆出后,迅速成为了朋友圈刷屏的新主题,吃瓜群众基本分为两拨,一拨纯属"看热闹不嫌事大"的,一拨与媒体利益相关或曾经利益相关的 ...

  5. linux卡利系统设置密码,Kail Linux2019.04更新:新增“卧底模式” 模拟Win10界面

    12月3日消息 Kail Linux 通常是从事安全和渗透工作人士喜爱的操作系统,预置的龙徽标桌面也让该操作系统看起来非常独特.然而多数人已经习惯windows 或者macOS 操作系统,因此在办公室 ...

  6. 2019 年美团点评高级 Android 开发寒冬跳槽涨薪经验掏心分享

    2019 年美团点评高级 Android 开发寒冬跳槽涨薪经验掏心分享 目录 个人简介 笔者的简要介绍 跳槽涨薪要考虑的方面有哪些? 你是正在拿着卖白菜的钱,操着卖白粉的心吗? 你真得觉得是时候跑路了 ...

  7. 我在亚马逊商城卧底的日子

    英文原文:My week as an Amazon insider 亚马逊这世界上最大的网路公司,近来却不断有质疑他们对待员工方式不合理的声音传出,也有员工因为压力过大传出精神出问题的消息.到底在这家 ...

  8. 卧底骗子群,我不仅赚了钱,还学到了这些套路

    前段时间,在朋友圈看到有人发免费领纸的活动.当然,直觉告诉我,这要么是骗子,要么就是哪家的拉新活动. 本来是打算跳过的,但好奇害死猫,还是没忍住.毕竟作为产品经理,还是想知道他们的套路究竟是怎样的. ...

  9. 美团猫眼电影android模块化实战--可能是最详细的模块化实战

    转载请注明出处: 美团猫眼电影android模块化实战–可能是最详细的模块化实战 地址:http://www.jianshu.com/p/d372cc6802e5 目录 1 写这篇博客的初衷 首先一句 ...

最新文章

  1. 快乐数(最终要变成1)
  2. python--常用模块:collections 、time、random
  3. 3000块你请不到一个农民工,只能请到一个大学生
  4. leetCode-第四题求两个数组的中位数
  5. 深度学习、机器学习、机器人操作系统、人工智能学习资源
  6. python解释器有哪几种_Python解释器种类以及特点?
  7. 一文搞懂JVM架构和运行时数据区,全网最新
  8. Linux下改动Oracle数据库字符集命令
  9. Inject Dll 过程
  10. tkinter Scale滑块
  11. Python终端输出中文
  12. Jquery实现滚动到底部加载更多(最原始)
  13. imagenet ILSVRC2012下载及其matlab处理方法
  14. 人力资源管理专业知识与实务(中级)
  15. bbys_tu_2016
  16. arm开发板烧写linux系统,ARM开发板烧写linux系统的步骤
  17. PHP 中的 use function是什么意思
  18. Linux下ps命令
  19. 【python 图像识别】图像识别从菜鸟走向大神系列1
  20. java中引用数据类型有哪几种

热门文章

  1. 基于CentOs7的moodle平台搭建历程
  2. 如何检测内存泄漏(转)
  3. Win10一更新,我的GT730显卡驱动就异常
  4. 企立方:拼多多商家运营思路
  5. 豆瓣FM-Hacker——豆瓣FM播放列表补全计划
  6. python划分有限元网格_有限元网格划分和细化
  7. 如何使用手机在线抠图工具进行一键抠图?
  8. Scikit-learn 秘籍 第四章 使用 scikit-learn 对数据分类
  9. Arduino Mind+编程 轮询读取多个软串口数据的方法讨论
  10. 【商业信息】GB 11643—1999 公民身份号码