1.基础原理:
编码解码: 视频压缩成文件还原成帧图像 h.264
封装格式:mp4,avi等
硬解与软解:cpu,gpu
关键帧:视频压缩中比较重要的图像帧数据
1.程序主入口
AndroidMenifest.xml
intent-filter意图过滤器
<activity android:name=\".MainActivity\" android:theme=\"@style/FullScreen\"><intent-filter><action android:name=\"android.intent.action.MAIN\" /><category android:name=\"android.intent.category.LAUNCHER\" /></intent-filter></activity>
theme只对当前activity有作用
theme在application的话,对所有activity均有作用
以最小为准
2.Activity生命周期
3.视图相关
1.xml
ConstraintLayout 继承自ViewGroup
ViewGroup继承自View
public abstract class ViewGroup extends View implements ViewParent, ViewManager
View和ViewGroup是组合设计模式,23种设计模式之一。
match_parent:子view大小等于父view的大小
2.VideoView
VideoView :
对MediaPlayer的一层封装,只支持3gp和mp4格式的播放。
继承自SufarceView
videoview的全屏问题:
videoview会根据视频文件的大小来改变自身的大小,所以要自定义view。
##6. Bundle
与Map类型数据相似,以key-value的形式存储数据
界面被销毁后,是否能还原之前的状态
3.setContentView方法
把自定义layout加入id为content的ViewGroup中
4.activity中设置播放的视频路径
mVideoView.setVideoURI(Uri.parse(\"android.resource://\"+getPackageName()+ File.separator+R.raw.splash));
播放器的状态:闲置,准备,播放
mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {@Overridepublic void onPrepared(MediaPlayer mp) {mp.start();}});
mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {mp.start();}});
观察者设计模式:
观察者是界面,被观察者是播放器。
5.自定义theme
全屏
<item name=\"android:windowFullscreen\">true</item>
无标题栏
<style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.NoActionBar\">
6.自定义View的几种方式
1.继承自View类。
核心步骤为尺寸测量与绘制,对应函数为onMeasure、onDraw。
VideoView中只有onMeasure方法,没有onDraw方法
2、继承现有控件实现特定效果
3、继承ViewGroup实现布局类
主要用于自定义子视图的排列方式时,比如下拉刷新、上拉加载等。ViewGroup为什么具有容器的作用?因为实现了两个接口 ViewParent和ViewManager,其中后者定义了addView及removeView等对子视图操作的方法,
重点实现onLayout方法,主要是用于子视图的排版。
public class FullScreenVideoView extends VideoView {public FullScreenVideoView(Context context) {super(context);}用于在Activity中直接new出来的对象public FullScreenVideoView(Context context, AttributeSet attrs) {super(context, attrs);}用于xml文件中定义的布局的new。支持自定义属性。public FullScreenVideoView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}也是用于xml文件中,也支持自定义属性,同时支持style样式
为了全屏重写测量方法系统的onMeasure方法会根据兼容性更改大小@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int width = getDefaultSize(0,widthMeasureSpec);int height = getDefaultSize(0,heightMeasureSpec);setMeasuredDimension(width,height);// super.onMeasure(widthMeasureSpec, heightMeasureSpec);}
7.测量模式
EXACTLY模式
该模式为精确模式。什么时候用到的是这种模式呢?当我们将layout_width or layout_height 设置为具体数值的时候,如100dp 或者是match_parent 的时候。这时系统就是调用的精确模式
AT_MOST
该模式为最大值模式。当我们将layout_width or layout_height设置为wrap_content 的时候,系统调用的就是该模式。此时控件大小是随着子控件或者内容的变化而变化的,只要不超出父控件允许的最大范围即可
UNSPECIFIED
这个模式一般只有在我们自定义控件的时候才会用到,它代表没有具体的测量模式,view自己想多大就多大。
8.xml中的部分属性
<color name=\"colorPrimary\">#6200EE</color>
颜色色值:
#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(全透明)
dp px sp 之间的概念:
px:像素单位,dp:安卓距离单位,sp:安卓字体大小单位
当屏幕为mdpi时,1dp = 1px,换算单位为 dp = (dpi/160)px。
1dp永远都等于1sp。
dp不随手机字体大小变化而变化
sp跟随系统
控件位置
相对父控件
android:layout_marginTop=“50dp”
9.自定义shape
弧度
<corners android:radius=\"20dp\"/>
背景
<solid android:color=\"@color/colorBlack\"/>
边框
<stroke android:width=\"1dp\" android:color=\"@color/colorffffff\"/>
4.倒计时类的实现
1.需要实现哪些功能?
1、实时回调,倒计时至几秒
2、支持动态传入倒计时的总时间
3、每过一秒总秒数减一
4、总时间倒计时为0时要回调完成的状态
2.用到观察者设计模式。
//具体实现@Overridepublic void run() {if (isRun){if(CountDownHandler!=null){CountDownHandler.onTicker(countdowntime);}if(countdowntime == 0) {cancel();if (CountDownHandler != null) {CountDownHandler.onFinish();}}else{countdowntime = time--;handler.postDelayed(this,1000);}}}
//开始倒计时public void start(){isRun = true;handler.post(this);}
//跳出循环,终止public void cancel(){isRun = false;handler.removeCallbacks(this);}
//观察者回调借口 (IOC 数据回调)public interface IcountDownHandler{//倒计时回调void onTicker(int time);//完成时回调void onFinish();}}
3.用Handler的消息机制做数据的减法操作
5. Handler
1.原理图
2.MessageQueen和 Looper
Looper
Handler 源码中,
mLooper = Looper.myLooper();
在进入到Looper的源码中
/*** Return the Looper object associated with the current thread. Returns* null if the calling thread is not associated with a Looper.*/public static @Nullable Looper myLooper() {return sThreadLocal.get();}
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
ThreadLocal相当线程同步的池子,取出放回
MessageQueue
在looper的构造方法中,创建了MessageQueue
final MessageQueue queue = me.mQueue;
private Looper(boolean quitAllowed) {mQueue = new MessageQueue(quitAllowed);mThread = Thread.currentThread();}
3.ActivityThread源码中的Handler
main方法中
Looper.prepareMainLooper();
Looper.loop();
Looper.loop()
final MessageQueue queue = me.mQueue;
for (;;) {Message msg = queue.next(); // might blockif (msg == null) {// No message indicates that the message queue is quitting.return;}
在此处遍历的是Message类型的数据
而postDelayed的是Runnable类型的数据
进入到postDelayed的源码
public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {return sendMessageDelayed(getPostMessage(r), delayMillis);}
将Runnable封装成Message
查看getPostMessage,放进callback成员变量里面
private static Message getPostMessage(Runnable r) {Message m = Message.obtain();m.callback = r;return m;}
app启动时创建looper不断去循环MessageQueen
H类
class H extends Handler
处理handler消息
public void handleMessage(Message msg) {
Activity生命周期是通过ActivityThread类,发送一些消息,处理不同的消息类型,调用Activity的生命周期。
6 Activity的跳转
在AndroidManifest中,隐式启动
<intent-filter><action android:name=\"android.intent.action.MAIN\" /><category android:name=\"android.intent.category.LAUNCHER\" /></intent-filter>
将Action放进intent里面,
匹配字符串\”android.intent.action.MAIN\”
在项目当中,可以用显式启动
startActivity(new Intent(SplashActivity.this,MainActivity.class));
SplashActivity 继承自AppCompatActivity
AppCompatActivity的继承可以深入到contex类