快捷键:
提取方法:Ctrl+Alt+M 提取全局变量:Ctrl+Alt+F 搜索类:ctrl+N
断点调试时,遇到这个 端口号被占用
Connected to the target VM, address: 'localhost:8610', transport: 'socket'
短视频
原理:
- 编码与解码:视频压缩成文件还原成帧图像,h264。
- 封装格式
- 硬解码(gpu)、软解码(cpu)、多线程解码
- 关键帧:视频压缩当中比较重要的图像帧数据
Raw文件夹:一般大文件都存放在Raw和assets文件夹
Bundle的概念:Bundle类型的数据与Map类型的数据相似,都是以key-value的形式存储数据的
界面跳转:intent-fiter和Intent
Intent中文意思指“意图”,通常Intent的隐式启动和intent-filter连用,显示启动不需要intent_filter。
IOC原理:控制反转 https://www.jianshu.com/p/f96391af0357
观察者设计模式:观察者与被观察者 (以VideoView demo举例,观察者是界面,被观察者就是播放器)
Handler原理图:
setContentView原理:把自定义Layout加入id为content的ViewGroup里
findViewById:根据xml id值来映射成view对象
VideoView:对MediaPlayer的一层封装,只支持3gp和mp4格式的播放。
清单文件:权限 、四大组件、PMS(Package Manager Service)安全检查
VideoView全屏:videoView会根据视频大小来改变自身的大小,所以要自定义view。
style自定义属性的复用
Android中View和ViewGroup是组合设计模式之一(共23种)
自定义view的几种方式:
1.继承View完全自定义
对于继承View类的自定义控件来说,核心的步骤分别为尺寸测量与绘制,对应的函数为onMeasure、onDraw,这是因为View的子空间是视图树的叶子节点,不需要布局(针对为什么布局开发时有actionBar,但运行后app播放器仍然充满屏幕)
小技巧:查找类【Ctrl+N】
TextView类中
2.继承现有控件实现特定效果
3.继承ViewGroup实现布局类
这种方式主要用于自定义子视图的排列方式时,比如下拉刷新,上拉加载等。
ViewGroup具有容器作用:因为实现了两个接口ViewParent和ViewManager,其中后者定义了addView及removeView等对子视图操作的方法,重点实现onLayout方法,这个方法主要是用于子视图的排放。
public class FrameLayout extends ViewGroup 该类下有onLayout方法
EXACTLY模式
该类为精确模式。何时使用:
当我们将layout_width or layout_height 设置为具体数值时,如100dp或是match_parent,这是系统就是调用精确模式。
AT_MOST
最大值模式,当我们将layout_width or layout_height设置为wrap content时,系统调用的就是这个模式
此时的控件大小是随着子控件或者内容的变化而变化,只有不超出父控件允许的最大范围即可
UNSPECIFIED
只有在自定义控件时用到,没有具体的测量,view自己想要多大有多大
自定义计时器:用Handler的消息机制做数据的减法操作
TextView:
自定义Shape:不自定义可以使用图片,自定义shape用xml代码实现
颜色色值:#ffffffff由#加八位数字或字母组成,前两个ff为透明度(十六进制),后面六位ffffff为颜色代码,采用RGB配色(十六进制)
透明度参照表:
00%=FF(不透明) | 5%=F2 | 10%=E5 | 15%=D8 | 20%=CC |
25%=BF | 30%=B2 | 35%=A5 | 40%=99 | 45%=8c |
50%=7F | 55%=72 | 60%=66 | 65%=59 | 70%=4c |
75%=3F | 80%=33 | 85%=21 | 90%=19 |
95%=0c 100%=00 (全透明) |
解决硬编码:把代码里面的中文字提出到String.xml文件,一些常量可单独提出到常量类里面,注意未来界面整洁,维护,规范
dp px sp 之间的概念
px:像素单位 dp:安卓距离单位 sp:安卓字体大小单位
密度 | ldpi | mdpi | hdpi | xhdpi | xxhdpi |
密度值 | 120 | 160 | 240 | 320 | 480 |
代表分辨率 | 240*320 | 320*480 | 480*800 | 720*1280 | 1080*1920 |
当屏幕为mdpi时,1dp=1px,换算单位为dp=(dpi/160)px
1dp永远都等于1sp
Bundle的概念:Bundle 类型的数据与Map类型的数据相似,都是以key-value的形式存储数据的
界面跳转:intent-filter和Intent
Handler原理:
线程之间的通信(子线程处理一些结果,通过handler发送到主线程,主线程通过一些方法“handleMessage()”来获得数据)
死循环不会卡死:
这里涉及到Linux pipe/epoll机制,简单来说就是在主线程的messageQueue没消息时,便阻塞在loop的queue.next()中的nativePollOnce()方法里,此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生,通过往pipe管道写端写入数据来唤醒主线程工作。
断点调试
注意1!!!
//countDownTime一开始是0,需要在这里设置传入time
this.countDownTime = time;
注意2!!!当countDownTime == 0的时候,先把它取消掉,在还在进行onCreate()时,是自动取消Handler
如果说Activity还没有走完,Handler是否还会继续存在呢?添加cancel()
注意3!!!所以才需要手动调用一次
onCreate(),onDestory()都是系统调用的
SplashActivity添加
//界面销毁时,回调
@Override
protected void onDestroy() {
super.onDestroy();
timer.cancel();
}
Handler原理寻找
loop类loop()构造器
往下滑找到Looper()
创建Handler的时候,会去ThreadLocal里面去取这个Looper,这个Looper的构造方法创建MessageQueue()
为什么用ThreadLocal去取,而不是新建一个呢?
这就涉及系统源码,关于主线程Looper和MessageQueue在app刚启动的时候就已经创建出来了,它们是在ActivityThread类
快速双击shift,搜索ActivityThread.java,它是一个app程序的入口,搜索main(String[] args),一般操作系统都有这么一个main()
这里面有一个prepareMainLooper(),就相当于创建了一个Looper,还需要调用一个Looper.loop()
然后拿到个MessageQueue不断去遍历
这是个Message类,点进去,它里面有what,arg1,arg2这些标识
点击CustomCountDownTimer中post(),调用sendMessageDelayed()
它把Runnable这个对象封成了一个Message,这样就解释通了
根据handler原理图,我们发送一个Runable,实际上我们也封装了一个Message到消息队列里面,在app程序启动的时候,不断去循环MessageQueue
它是把Runnable这个对象封装在MesageQueue的callback这个成员变量里面。
它定义了一些code,发送不同消息的一些类型,然后去回调处理这个handleMessage
Activity的生命周期:就是通过ActivityThread发送一些消息,处理不同消息类型,去调用Activity的生命周期
上传至github
首先建立仓库
commit
push
公司项目多人开发需要建立分支,可参考https://www.cnblogs.com/myqianlan/p/4195994.html
开发的一个分支Feature完成后,再develop合并,经过测试完后,最后master(以及还有从master拉出来hotfix进bug修改发版,拉出Release分支用于打包)