Open MaosanDao opened 5 years ago
微信公众号文章:
读后感:
1.Android消息处理机制的本质:一个线程开始无限循环模式持续监听并依次处理其他线程给它发的消息。
2.在Android主线程中使用Handler,则是直接持有了该线程的looper,再由源码可知,looper可以拿取到 MessageQueue,所以Handler可以直接往里面发送消息。这也是为什么在子线程中创建Handler需要 自行启动Looper和退出Looper循环了。
3.只要在主线程中创建了Handler,则主线程就持有了这个Handler,因为在发送Message的时候,handler 实施会以msg.target = mHandler的方式传递进去。
为什么要用Handler进行UI的更新?
因为,非UI线程中操作UI的变化为不合法的(假如多个线程控制UI,那么线程安全呢?),只有在UI线程才能操作UI的变化。所以这里就需要使用Handler了。因为Handler在主线程创建,那么它就可以向主线程中发送和处理消息。 即,你在子线程发送Message消息给主线程处理,然后处理完成后,就会回调到UI线程了,那时候,你就可以操作UI了。
扩展:为什么不能在子线程中更新UI?
UI控件非线程安全,在多线程中并发访问可能会导致UI控件处于不可预期的状态。 而不对UI控件的访问加上锁机制的原因有: 1.上锁会让UI控件变得复杂和低效。 2.上锁后会阻塞某些进程的执行。
***
- [ ] [Android常用图片加载库介绍及对比](https://mp.weixin.qq.com/s/YwUyetlYau4YKSoZXifA3A)
- [ ] [金三银四,来一波Android面试(附答案)](https://mp.weixin.qq.com/s/3DJOu7V-7LOEevFg_pXHWw)
一个内推老哥的面试题:
[x] Android事件冲突的处理
[x] 自定义View的过程(详细)
[ ] ButterKnife的原理
[ ] 应用的启动白屏处理
[x] View的工作绘制流程(绘制原理)
[x] 自定义View需要注意的事项
[ ] RxJava线程切换的原理
[x] Activity A 到 Activity B的生命周期(B是否透明)
[ ] Activity的启动过程
[ ] 线程池的大解析(参数、使用,核心线程和最大线程的配置)
[x] Intent的理解和匹配规则
[ ] Intent的携带数据大小?有限制,怎么解决?
两种情况,B是否透明:
1.透明
相对于A来说,onCreate - onStart -onResume - onPause
相对于B来说,onCreate - onStart - onResume
2.不透明 相对于A来说,onCreate - onStart -onResume - onPause -onStop 相对于B来说,onCreate - onStart - onResume
***
### View的绘制流程
一般的View绘制流程为3个大部分: 1.onMeasure -- 测量大小 2.onLayout -- 绘制的位置 3.onDraw -- 绘制的内容
其中,在第一步中,我们需要知道要绘制的View在父布局中的大小,而这个大小是由specSize和specMode一起来确定,他们的规则是:
SpecMode: 如果是EXACTLY,则它的大小则为SpecSize的大小,开发者可以自定义 如果是AT_MOST,则它的大小最大为SpecSize,开发者可以自定义 如果是UNSPECFIED,则它的大小是不受限制的,开发者可以随意定制
onLayout则是需要通过自定义去指定子View的位置。方法为onLayout(x,x,x,x,x)。
onDraw方法中,是通过Canvas去实现特定的绘制逻辑。
***
### 自定义View需要注意的事情
```java
//1.让View支持wrap_content
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//处理WAP_CONTENT
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(200,200);
}else if (widthSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(200, heightSize);
}else if (heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(widthSize, 200);
}
}
//2.让View支持padding
//直接继承View的控件,如果不在onDraw方法中处理padding 那么padding属性是无法起作用的
//直接继承ViewGroup的控件,需要处理padding和子元素的margin对其的影响,否则这两个属性也无效
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
//获取padding,然后根据实际情况处理就好
mPaddingLeft = getPaddingLeft();
mPaddingRight = getPaddingRight();
mPaddingTop = getPaddingTop();
mPaddingBottom = getPaddingBottom();
mWidth = getWidth() - mPaddingLeft - mPaddingRight;
mHeight = getHeight() - mPaddingTop - mPaddingBottom;
}
//3.尽量不要在View中使用Handler,因为它本身就提供了post的方法。
//4.要及时停止View中的动画和线程
//5.需要处理嵌套滑动的问题
//6.不要在onDraw中新建过多的对象,因为onDraw的执行频率比较快,这样子会引起内存抖动
一般的自定义View的体现方式有以下几种:
1.继承View重写onDraw方法
主要用于实现不规则的效果,即这种效果不方便通过布局的组合方式来实现。相当于就是得自己“画”了。采用这种方式需要自己支持wrap_content,padding也需要自己处理。
2.继承ViewGroup派生特殊的Layout
主要用于实现自定义的布局,看起来很像几种View组合在一起的时候,可以使用这种方式。这种方式需要合适地处理ViewGroup的测量和布局,并同时处理子元素的测量和布局过程。
3.继承特定的View,比如TextView
这种方法主要是用于扩展某种已有的View,增加一些特定的功能。这种方法比较简单,也不需要自己支持wrap_content和padding。
4.继承特定的ViewGroup,比如LinearLayout
和第三种类似,主要也是在原有的基础上扩展功能。
自定义View的过程,一般通过三大流程去做:
onMeasure - onLayout - onDraw
一般我们可以通过两种思路去解决:
1.从父View的角度 --- 自定在父View中通过逻辑判断是否需要将这个事件进行分发
重写父View的OnInterceptTouchEvent方法,如果父View需要拦截,那么就拦截。如果父View不需要拦截,那么就交给子View去解决。
当然这是需要看情况自行判断的。
2.从子View的角度 --- 关键方法为:requestDisallowInterceptTouchEvent(true/false)
从子View着手,父View先不要拦截任何事件,所有的事件传递给子View,如果子View需要此事件就消费掉,不需要此事件的话就交给父View 处理。
实现思路如下:
重写子View 的 dispatchTouchEvent 方法,在 Action_down 动作中通过方法 requestDisallowInterceptTouchEvent(true)先请求父View不要拦截事件,这样保证子View能够接受到Action_move事件,再在Action_move动作中根据自己的逻辑是否要拦截事件,不要的话再交给父View处理。
主要是通过以上两种思路去实现的,具体的情况可以看标题的原文。
String不可改变对象,一旦创建就不能修改
String str="aaa";
str="bbb";
以上代码虽然改变了str,但是执行过程是回收str,把值赋给一个新的str。
StringBuffer创建之后,可以去修改,
StringBuilder也可修改,执行效率高于StringBuffer,不安全。
当字符赋值少使用String 字符赋值频繁使用StringBuilder 当多个线程同步操作数据,使用StringBuffer
- [ ] RecyclerView和ListView的区别
缓存上:前者缓存的是View+ViewHolder+flag,不用每次调用findViewById,后者则只是缓存View。
刷新数据方面:前者提供了局部刷新,后者则全部刷新
- [x] Android性能优化
布局优化:减少布局层级,使用ViewStub提高显示速度,布局服用,尽可能少使用warp_content, 删除空间中无用的属性,避免过度绘制移除window默认背景,按需显示展位图, 自定义View优化,使用canvas.clipRect()识别可见区域。
启动速度:采用分布加载,异步加载,延期加载提高应用初始化速度,采用线程初始化数据等, 合理的刷新机制。
内存方面:防止内存泄露,使用一些第三方工具检测解决。
代码优化:遵循Java生命周期。
安装包优化:删除无用资源,优化图片,代码混淆,避免重复库存在,插件化。
[ ] HTTPS的工作原理 参考文章:https原理通俗了解
[ ] 数据怎么压缩和怎么保证数据的安全
[ ] 锁的种类,什么是自旋锁,ReentrantLock?
[ ] ClassLoader双亲为委派实现原理
[ ] Java中集合的原理和扩容相关
[ ] 程序死锁的原因和解决方案
[x] transient关键字的作用
需要添加的:
2019.04.02
[ ] 快速排序
[ ] AsyncTask源码分析
20
9