读书笔记--Android进阶之光

0、信息

创建时间:2019 年1 月 10 日

修改时间:2020 年 1 月 19 日

分类:读书笔记

整理:yoyiyi(soleil雪寂)

状态:已完成

仓库:Soleil-Notes

第1章 Android新特性

1.1. Android 5.0 新特性

  1. MD 设计风格、支持多种设备、全新的通知中心、Overview、设备识别解锁、RecyclerView、CardView

1.2. RecyclerView

  1. 分割线:ItemDecoration

1.1.4. 3种Notification

  1. 普通Notification
  2. 折叠式Notification(RemoteView)
notication.bigContentView = remoteViews
  1. 悬挂式Notification
builder.setFullScreenIntent()
  1. Notification 显示等级
1.VISIBILITY_PUBLIC
2.PRIVATE
3.SECRET 在pin、password等安全锁和没有锁的情况下才显示
4.build.setVisibility()

1.1.5. Toolbar与Palette

  1. 步骤
1.style 去掉 Actionbar
2.Toolbar 布局
  1. menu 覆写 onCreateOptionsMenu

1.1.6. Palette

  1. 提取颜色
Paletter.from(bitmap).generate(new Palette.PaletteAsyncListener())

1.2. Android6.0 新特性

  1. 应用权限
  2. 指纹支持
  3. Doze电量管理

1.2.2. 运行时权限机制

  1. 普通权限和危险权限
1.ActivityCompat.checkSelfPermission
2.onRequestPermissionsResult
  1. 权限框架
1.PermissionsDispatcher


1.3. Android7.0 新特性

  1. 多窗口
  2. Data Server 流量保护机制
  3. Java 8支持
  4. 后台省电
  5. 禁用多窗口:android:resizeableActivity=“false”
  6. 小于24:android:screenOrientation=“potraint”

第2章 Material Design

  1. 质感设计

2.2.Design Support Library 常用控件详解

  1. Snackbar 使用
  2. TextInputLayout
1.设置错误
1.1.setErrorEnabled(true)
1.2.setError("错误信息")
  1. FloatingActionButton
  2. TabLayout
  3. NavigationView
  4. CoordinatorLayout
app:layout_scrollFalgs="scrill|enterAlways"
  1. CollapsingToolbarLayout
  2. 自定义Behavior
1. 自定义View监听CoordinatorLayout里滑动
2. 定义View监听另一个View的状态变化,例如View的大小、位置和显示状态等

第3章 View体系与自定义View

3.1.View和ViewGroup

  1. 所有控件的基类
  2. ViewGroup 自继承 View

3.2.坐标系

  1. Android 坐标系:左上角的顶点作为Android坐标系的原点—getRawX()
  2. View坐标系
MotionEvent
1.getX--获取点击事件距离控件左边的距离,视图坐标。
2.getRawX--获取点击事件距离整个屏幕顶边的距离,绝对坐标。

3.3.View滑动

  1. layout()
//跟随手指移动的View
public class CustomerView extends View {
    private int lastX;
    private int lastY;

    public CustomerView(Context context) {
        this(context, null);
    }

    public CustomerView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = x;
                lastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                int offsetX = x - lastX;
                int offsetY = y - lastY;
                layout(getLeft() + offsetX,
                        getTop() + offsetY,
                        getRight() + offsetX,
                        getBottom() + offsetY);
                break;
            default:
                break;

        }
        return true;
    }
}

  1. offsetLeftAndRight()与offsetTopAndBottom()
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = x;
                lastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                int offsetX = x - lastX;
                int offsetY = y - lastY;
                offsetLeftAndRight(offsetX);
                offsetTopAndBottom(offsetY);
                break;
            default:
                break;

        }
        return true;
    }
}

  1. LayoutParams()
1. final LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) getLayoutParams();
params.leftMargin = getLeft() + offsetX();
...
setLayoutParams(params);

2. (ViewGroup.MarginLayoutParams)getLayoutParams()
params.leftMargin = getLeft() + offsetX();
  1. 动画
//1.
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:duration="1000"
     android:fillAfter="true">
    <translate
        android:fromXDelta="0"
        android:toXDelta="300"/>
</set>
this.setAnimation(AnimationUtils.loadAnimation(context,R.anim.translate));
//2.
ObjectAnimator.ofFloat(this, "translationX", 0, 300).setDuration(3000).start();
  1. scrollTo和scrollBy()
1.scrollTo:移动到一个具体坐标点
2.scrollBy:移动增量dx、dy
3.((View)getParent).scrollBy(-offsetX,offsetY)
4.注意:效果是瞬间完成的。
  1. Scroller
1.并不能实现View滑动,要配合View的computeScroll()
2.computeScroll()中不断让View进行重绘,计算滑动持续时间,算出View滑动位置,调用scrollTo()方法进行滑动。

3.4.属性动画

  1. 帧动画:
  2. View动画(视图动画):AlphaAnimation、Rotate、Translate、Scale–>不具备交互性
  3. ObjectAnimator
0.ObjectAnimator.ofFloat(view,"translationX",200)
1.translationX、translationY
2.rotaiton、rotationX、rotationY->旋转
3.PrivotX、PrivotY->旋转 缩放
4.alpha
5.x、y:View对象最终位置
  1. ValueAnimator
1.不提供动画效果,数值发生器
2.ValueAnimator的AnimatiorUpdateListener
3.动画监听
3.1.animator.addListener(new Animator.AnimatorListener)(star、repeat、end、cancel)
3.2.animator.addListener(new Animator.AnimatorListenerAdapter(){
    end // 只监听end
})
  1. 组合动画–AnimatorSet
1.play()
2.after(Animator):之后
3.after(Long):延迟
4.before(Animator):之前
5.with(Animator):同时

6.set.play(a1).with(a2).after(3)
7.set.playTogether(a1,a2) 同时执行
  1. 组合动画–PropertyValuesHolder
1.PropertyValuesHolder:多个动画一起执行
2.ObjectAnimator.ofPropertyValuesHolder(Object,PropertyValuesHolder...)
3.
PropertyValuesHolder holder = PropertyValuesHolder.ofFloat("scaleX", 1.0f, 1.5f);
ValueAnimator animator = ObjectAnimator.ofPropertyValuesHolder(holder);
animator.setDuration(1000).start();

7.在xml中使用属性动画

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:propertyName="scaleX"
    android:valueFrom="1.0"
    android:valueTo="1.0"
    android:valueType="floatType"
    >
</objectAnimator>

Animator animator = AnimatorInflater.loadAnimator(this.getContext(), R.animator.demo);
animator.setTarget(this);
animator.start();

3.6.View事件分发机制

3.6.1.源码解析Activity的构成

1.setContentView()->getWindow()(Window).setContentView()->getWindow()返回一个mWindow,实际在Activity的attach中创建一个PhoneWindow对象,PhonwWindow会创建DecorView作为窗口的根View,DecorView包含一个Titlle,一个ContentView
2.Activity->PhoneWindow->DecorView(TitleView+ContentView)

3.6.2.源码解析View的事件分发机制

1.把事件封装成MotionViewEvent,传递给View的层级
2.三个重要方法:dispatchTouchEvent(分发)onInterceptTouchEvent(拦截)onTouchEvent(消费)
3.OnTouchListener中的OnTouch()方法高于onTouchEvent(Event)

1.View事件分发机制

1.
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    ···
    //1.判断是否是Down事件 是一个新的事件序列
    if (actionMasked == MotionEvent.ACTION_DOWN) {
        cancelAndClearTouchTargets(ev);
        //mFirstTouchTarget 置空
        resetTouchState();
    }
    final boolean intercepted;
    
    //View没有拦截当前事件 交由子View处理
    if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
        //FLAG_DISALLOW_INTERCEPT 禁止ViewGroup拦截Down之外事件 通过requestDisallowInterceptTouchEvent
        final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
        if (!disallowIntercept) {
            intercepted = onInterceptTouchEvent(ev);
            ev.setAction(action);
        } else {
            intercepted = false;
        }
    } else {//ViewGroup 拦截了当前事件
        intercepted = true;
    }
// onInterceptTouchEvent 不会每次都调用
    
2.
 if (newTouchTarget == null && childrenCount != 0) {
   ···
    final View[] children = mChildren;
    //遍历ViewGroup子元素,如果子元素能够处理事件,交由子元素处理
    for (int i = childrenCount - 1; i >= 0; i--) {
        final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i,customOrder);
        final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
        if (!canViewReceivePointerEvents(child)
                                    || !isTransformedTouchPointInView(x, y, child, null)) {
            //判断触摸点位置是否在子View上,是否播放动画,不符合继续遍历                       
            ev.setTargetAccessibilityFocus(false);
                continue;
        }
        newTouchTarget = getTouchTarget(child);
        if (newTouchTarget != null) {
            newTouchTarget.pointerIdBits |= idBitsToAssign;
            break;
        }
        resetCancelNextUpFlag(child);
        //如果有子View,则调用子View的dispathTouchEvent,如果没有 直接super View中的dispatchOnTouchEvent(如果onTouchListener不为null,并且onTouch为true,事件被消费,)
        if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
            mLastTouchDownTime = ev.getDownTime();
            
1.View中的onTouchEvent()
只要View的CLICKABLE和LONG_CLICKABLE有一个为true,onTouchEvent消费这个事件

  1. 点击事件分发的传递规则
public boolean dispatchTouchEvent(MotionEvent ev){
boolean resule = false;
if(onInterceptTouchEvent(ev)) {
     resule = super.onTouchEvent(ev);
  }else{
      result = child.dispatchTouchEvent(ev);
  }
  return result;
}

1.自上而下分发,为true拦截,false不拦截
2.自下而上传递,底层View的onTouchEvent 为 false->往上传递
2.具体见下图
true
false
Activity
PhoneWindow
DecorView
ViewGroup
dispatchTouchEvent
onInterceptTouchEvent
super.onTouchEvent
child.dispatchTouchEvent 最终调用到子View的OnTouchEvent

View的工作流程

  1. 指的是measure、layout、draw
  2. DecorView 加载到Window中
1.Activity的startActivity
2.ActivityThread的handleLuanchActivity
3.handlLuanchActivity中performLuanchActivity来创建Activity(调用onCreate方法,完成DecorView创建)
4.handlLuanchActivity中handleResumeActivity(onResume)
5.handlLuanchActivity中得到DecorView和WM(接口继承ViewManager)
 ->WM中的addView方法
 ->(WindowManagerImpl)
 ->WindowManagerImpl中的addView
 ->WindowManagerGlobal中的addView方法
 ->创建ViewRootImpl,setView将DecorView传进去

3.ViewRootImpl的performTraversals

1.ViewTree开始View的工作流程
2.performMeasure、performLayout、performDraw
  1. 理解MeasureSpec
1.View的内部类,View规格尺寸(宽、高)
2.32int值,高2位代表SpecMode(测量模式),低30位代表SpecSize(测量大小)
3.MeasureSpec 受自身LayoutParams和父容器的MeasureSpec共同影响
4.DecorView中的MeasureSpec根据自身的LayoutParams和窗口大小决定的
模式 名称 简介
UNSPECIFIED 未指定模式 想要多大就多大
AT_MOST 最大模式 wrap_content
EXACTILY 精确模式 match_parent、具体值

3.7.3 View的measure流程

  1. measure 用来测量View的宽高,分为View的measure流程和ViewGroup的measure流程,ViewGroup的measure流程(完成自己的测量、遍历调用子元素的measure方法)
  2. View的measure方法
1. onMeasure -> setMeasureDimension(测量宽高)getDefaultSize(getSuggestedMinimumWidth)
2. getDefaultSize 中 AT_MOST 和 EXACTLY (wrap_content 和 match_parent)效果一样 所以继承 View 要重写 onMeasure 方法
3. getSuggestedMinimumWidth->如果View没有设置背景,返回mMinWidth,如果设置了,返回mMinWidth和Drawable最小宽度之间的最大值
  1. ViewGroup的measure方法
1. 不仅测量自身,还要遍历调用子view的measure方法
2. 没有定义onMeasure,定义了measureChildren
3. measureChildren -> measureChild() -> child.getLayoutParams获取LayoutParents属性,获取MeasureSpec并调用
子元素measure方法测量->getChildMeasureSpec
4. 定义了getChildMeasureSpec中如果父容器 MeasureSpec为AT_MOST,子元素的LayoutParams属性为WRAP_CONTENT->子元素也是AT_MOST,SpecSize为父容器SpecSize - padding,和子元素设置LayoutParams为MATCH_PARENT 效果一样,所以需要在LayoutParams属性为WRAP_CONTENT 指定默认 宽高

3.7.4.View的layout流程

1. 确定元素的位置,ViewGroup中的layout用来确定子元素位置,View中layout 用来确定自身位置
2. layout(l,t,t,b)->setFrame->onLayout()(View 和 ViewGroup 中均没有实现onLayout方法)

3.7.5 View的 draw 流程

1. 如果需要,绘制背景->drawBackgroup
2. 保存当前canvas层
3. 绘制view的内容-> onDraw(canvas)(空实现)
4. 绘制子view -> dispatchDraw(canvas)(空实现) ViewGroup->遍历调用 drawChild->调用View的draw方法,判断是否有缓存,没有正常绘制,有利用缓存显示
5. 如果需要,绘制view的褪色边缘,类似阴影效果
6. 绘制装饰,比如滚动条 -> onDrawForegroup-> 绘制ScrollBar以及其他装饰,并将它们绘制在视图内容上层

3.8.自定义View

  1. 自定义View->继承系统View(TextView)、继承View(注意padding、wrap_content)
  2. 自定义ViewGroup->继承系统ViewGroup(LinearLayout)、继承ViewGroup
  3. 自定义组合控件

3.8.4.自定义ViewGroup

  1. VelocityTracker 测量滑动速度
public class HorizontalView extends ViewGroup {
    private int lastX;
    private int lastY;

    private int lastInterceptX;
    private int lastInterceptY;
    private int currentIndex = 0; //当前子元素
    private int childWidth = 0;
    private Scroller mScroller;

    private VelocityTracker mTracker; //滑动速度

    public HorizontalView(Context context) {
        this(context, null);
    }

    public HorizontalView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public HorizontalView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mScroller = new Scroller(getContext());
        mTracker = VelocityTracker.obtain();
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childCount = getChildCount();
        int left = 0;
        View child;
        for (int i = 0; i < childCount; i++) {
            child = getChildAt(i);
            if (child.getVisibility() != View.GONE) {
                int width = child.getMeasuredWidth();
                childWidth = width;
                child.layout(left, 0, left + width, child.getMeasuredHeight());
                left += width;
            }
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        boolean intercept = false;
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                intercept = false;
                //还在执行滚动
                if (!mScroller.isFinished()) {
                    mScroller.abortAnimation();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                int dx = x - lastInterceptX;
                int dy = y - lastInterceptY;
                if (Math.abs(dx) - Math.abs(dy) > 0) {
                    intercept = true;
                } else {
                    intercept = false;
                }
                break;
            case MotionEvent.ACTION_UP:
                intercept = false;
                break;
            default:
                break;
        }
        lastX = x;
        lastY = y;
        lastInterceptX = x;
        lastInterceptY = y;
        return intercept;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //还在执行滚动
                if (!mScroller.isFinished()) {
                    mScroller.abortAnimation();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                int dx = x - lastX;
                scrollBy(-dx, 0);
                break;
            case MotionEvent.ACTION_UP:
                int distance = getScrollX() - currentIndex * childWidth;
                if (Math.abs(distance) > childWidth / 2) {
                    if (distance > 0) {
                        currentIndex++;
                    } else {
                        currentIndex--;
                    }
                } else {
                    mTracker.computeCurrentVelocity(1000); //获取水平速度
                    float xV = mTracker.getXVelocity();
                    if (Math.abs(xV) > 50) { //水平速度大于 50
                        if (xV > 0) {
                            currentIndex--;
                        } else {
                            currentIndex++;
                        }
                    }
                }
                currentIndex = currentIndex < 0 ? 0 : currentIndex > getChildCount() - 1 ? getChildCount() - 1 : currentIndex;
                smoothScrollTo(currentIndex * childWidth, 0);
                mTracker.clear();
                break;
            default:
                break;
        }
        lastX = x;
        lastY = y;
        return true;
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            postInvalidate();
        }
    }

    //弹性滑动指定位置
    public void smoothScrollTo(int dx, int dy) {
        mScroller.startScroll(getScrollX(), getScrollY(), dx - getScrollX(), dy - getScrollY(), 1000);
        invalidate();
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        //如果没有子元素,宽高设置 0
        if (getChildCount() == 0) {
            setMeasuredDimension(0, 0);
        } else if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {
            View childOne = getChildAt(0);
            int childWidth = childOne.getMeasuredWidth();
            int childHeight = childOne.getMeasuredHeight();
            setMeasuredDimension(childWidth * getChildCount(), childHeight);

            //如果宽度AT_MOST,则宽度为所有子元素宽度的和
        } else if (widthMode == MeasureSpec.AT_MOST) {
            int childWidth = getChildAt(0).getMeasuredWidth();
            setMeasuredDimension(childWidth * getChildCount(), heightSize);
            //高度AT_MOST 高度为第一个元素的高度
        } else if (heightMode == MeasureSpec.AT_MOST) {
            int childHeight = getChildAt(0).getMeasuredHeight();
            setMeasuredDimension(widthSize, childHeight);
        }


    }
}


第4章 多线程编程

4.1.线程基础

4.1.1 进程与线程

  1. 进程:系统进行资源分配和调度的基本单位
  2. 线程:操作系统调度的最小单元

4.1.2.线程的状态

1. New:新建
2. Runnbale:可运行
3. Blocked:阻塞
4. Waiting:等待、wait 方法
5. Timed waiting:超时等待
6. Terminated:终止

4.1.3.创建线程

  1. 继承Thread,重写run()
  2. 实现Runnbale,实现run()
  3. 实现Callable,重写call()–>提供返回值、能够抛出异常
public class DemoCallable implements Callable {
    @Override
    public String call() throws Exception {
        return "Hello";
    }

    private void test() {
        DemoCallable callable = new DemoCallable();
        ExecutorService service = Executors.newSingleThreadExecutor();
        Future future = service.submit(callable);
        try {
            System.out.println(future.get()); //阻塞,直到返回结果
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

4.1.4.理解中断

  1. interrupt 用来请求线程
  2. Thead.currentThread().isInterrupted() 判断线程是否中断
  3. 注意不要捕获InterruptException 不做处理
1.Thread.currentThread.interrupt()来设置中断状态
2.直接抛出异常

4.4.5.安全终止线程

  1. 使用 interrupt()
  2. 设置标志位

4.2.同步

4.2.1.重入锁与条件对象

  1. ReentrantLock
  2. 条件对象:Condition,一把锁对象拥有多个相关的条件对象。
1.condition.await() 阻塞当前线程,并放弃锁
2.signalAll、singnal

4.2.3.同步代码块

synchronized(obj)

4.2.4.volatile

线程A 本地内存     主内存      本地内存   线程B
  1. 原子序、有序性、可见性
  2. 作用:防止指令重排(保证有序性)、修改对其他线程可见,但是不保证原子性
  3. 使用:状态标志、双重检查模式(DCL)

4.3.阻塞队列

  1. 阻塞队列常用于生产者(往队列里头添加元素)和消费者场景(队列拿元素)
  2. 常见场景:1. 队列没有数据,消费者自动阻塞;2.队列填满数据,生产者自动阻塞。

4.3.2.Java中的阻塞队列

  1. ArrayBlockingQueue:数组组成的有界阻塞队列、FIFO、不保证线程公平访问队列
  2. LinkedBlockingQueue:链表组成有界阻塞队列、FIFO、维持一个数据缓冲队列
  3. PriorityBlockingQueue:支持优先排序的无界、默认升序
  4. DelayQueue:支持延迟获取元素的无界
  5. SynchronousQueue:不存储元素
  6. LinkedTransferQueue:链表组成无界
  7. LinkedBlockDeque:链表组成的双向
public class Blocking {
    private int queueSize = 20;
    private ArrayBlockingQueue<Integer> mQueue = new ArrayBlockingQueue<>(queueSize);

    public static void main(String[] args) {
        Blocking blocking = new Blocking();
        Consumer consumer = blocking.new Consumer();
        Producer producer = blocking.new Producer();
        producer.start();
        consumer.start();
    }


    class Consumer extends Thread {
        @Override
        public void run() {
            while (true) {
                try {
                    mQueue.take();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    class Producer extends Thread {
        @Override
        public void run() {
            while (true) {
                try {
                    mQueue.put(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

4.4.线程池

4.4.1 ThreaPoolExecutor

 ThreadPoolExecutor(int corePoolSize,  //核心线程数
        int maximunPoolsize,  //允许创建最大线程数
        long keepAliveTime,  //非线程闲置超时时间,设置allowCoreThreadTimeout也会作用在核心线程上
        TimeUnit unit,  // keepAliveTime 时间单位
        BlockingQueue<Runnable> workQueue, //任务队列
        ThreadFactory threadFactory,  //线程工厂
        RejectedExecutionHandler handler //饱和策略
)
RejectedExecutionHandler:
1.AbordPolicy:无法处理新任务
2.CallerRunsPolicy:用调用者线程处理新任务
3.DiscardPolicy:不能执行,删除
4.DiscardOldestPolicy:丢弃最近任务,并执行当前任务

4.4.2.线程池的处理流程和原理

  1. 提交任务,判断线程数是否达到核心线程数,没达到,就创建核心线程处理,达到,执行下一步
  2. 判断任务队列,没满,加入任务到任务队列,满了,执行下一步。
  3. 判断线程是够达到最大线程线程数,没有,创建非核心线程处理,达到了,执行饱和策略,默认抛出RejectedExecutionException

4.4.3.线程池种类

  1. FixedThreadPool:可重用固定线程数,只有核心线程
  2. CacheThreadPool:没有核心线程
  3. SingleThreadExecutor:单个工作线程
  4. ScheduledThreadPool:定时和周期、DelayedWorkQueue

4.5.AsyncTask的原理

泛型参数 核心方法 3.0 7.0
Params、Progress、Result onPreExecutor、doInBackgroup、onProgressUpdate、onPostExecute 核心线程5,最大线程128,时间1s,LinkedBlockingQueue、容量10,最多只能执行138个任务,139会执行饱和策略、并行执行 串行执行、SerialExecutor+THREAD_POOL_EXECUTOR(线程池)+Handler 、想要并行(task.executeOnExecutor)

第5章 网络编程与网络框架

5.1.网络分层

  1. 应用层(HTTP、FTP)、传输层(TCP、UDP)、网络层、数据链路层、物理层

5.2.三次握手

  1. TCP保证传输可靠性
第一次握手 第二次握手 第三次握手
建立连接,客户端发送连接请求报文段,SYN seq = x 服务器收到客户端SYN,设置 SYN seq=y,ACK = x +1 客户端收到服务端SYN+ACK
第一次
第一次握手:建立连接时,客户端发送syn包(seq=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。 [3] 
第二次
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(seq=k),即SYN+ACK包,此时服务器进入SYN_RECV状态。 [3] 
第三次
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
  1. 四次挥手
1) TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送。
(2) 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
(3) 服务器关闭客户端的连接,发送一个FIN给客户端。
(4) 客户端发回ACK报文确认,并将确认序号设置为收到序号加1

5.3.HTTP协议原理

  1. 应用层的面向对象协议。
  2. HTTP1.1、SPDY协议
  3. 特点:C/S、灵活、无状态

5.3.2.HTTP请求报文

  1. 请求行、请求报头、空行、请求数据
  2. GET、POST、HEAD、PUT、DELETE、TRACE、CONNECT、OPTIONS

5.3.3.响应报文

  1. 状态行、响应报头、空行、响应正文
  2. 100(收到请求)、200(请求成功)、300(重定向)、400(客户端错误)、500(服务器错误)
  3. 请求报头:Host、User-Agent、Accept、Accept-Encoding、Accept-Language、Transfer-Encoding
  4. 响应报头:Location、Server
  5. 实体报头:Content-Type、Content-Length、Content-Launguage、Content-Length、Expires、Last-Modified

5.4.HttpClient与HttpURLConnection

5.6.解析OkHttp

  1. OkHttpClient、Request、Call
  2. OkHttpClient.newCall(request)->RealCall->enqueue->Dispatcher(最终请求都是由此完成-enqueue)
  3. Dispatcher:主要控制并发的请求
  4. 拦截器->发送请求->HttpEngine->缓存(有:缓存系统,无:网络请求)->Response
  5. Okhttp的复用连接池,支持5个并发socket连接,keepALive时间为5分钟
  6. 自动回收连接:引用计数是否为0来实现自动回收连接。
  7. 连接池复用核心:Deque来存储连接,通过put、get等对Deque进行操作,判断连接对象StreamAllocation来进行自动回收连接

5.7.解析Retrofit

  1. 基于OkHttp实现的
  2. create、动态代理

第6章 设计模式

  1. 6原则:单一、开放封闭(扩展开发、修改关闭)、里式替换(使用基类地方能够使用子类)、依赖倒置(高层不依赖低层、抽象不依赖细节)、迪米特(最少知识)、接口隔离(一个类对另一个类依赖建立在最小接口上)
  2. 创建型设计模式、结构型设计模式、行为型设计模式

第7章 事件总线

第8章 函数响应式编程

第9章 注解与依赖注入框架

  1. 注解:是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取、并执行相应的处理。
  2. 分类:标准注解(Override、Deprecated、SuppressWarnings、SafeVarargs)、元注解(Taget、Inherited-注解可以被继承、Documented-文档、Retention-保留策略、Repeatable-多次使用)
  3. 运行时注解:反射(getDeclaredMethods、getAnnotation)
  4. 编译时注解:AbstractProcessor(AutoService)

9.2.依赖注入原理

  1. IOC:控制反转
  2. 依赖注入(DI):IOC容器在运行期间,动态将某种依赖注入到对象中。
  3. 构造方法注入、Setter方法注入、接口注入

ButterKnife

  1. ButterKnifeProcessor 注解处理器

第10章 应用框架设计

  1. MVC 模式:模型-视图-控制器
  2. MVP:Model、Presenter、View
  3. MVVM:Model、ViewModel、View

第11章 系统架构与MediaPlay框架

  1. 应用层、应用框架层、系统运行库层(C/C++、Android运行时库)、硬件抽象层(HAL)、Linux内核层
  2. http://androidxref.com 访问系统源码
  3. Source Insights
发布了12 篇原创文章 · 获赞 11 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_44947117/article/details/104043985