notication.bigContentView = remoteViews
builder.setFullScreenIntent()
1.VISIBILITY_PUBLIC
2.PRIVATE
3.SECRET 在pin、password等安全锁和没有锁的情况下才显示
4.build.setVisibility()
1.style 去掉 Actionbar
2.Toolbar 布局
Paletter.from(bitmap).generate(new Palette.PaletteAsyncListener())
1.ActivityCompat.checkSelfPermission
2.onRequestPermissionsResult
1.PermissionsDispatcher
1.设置错误
1.1.setErrorEnabled(true)
1.2.setError("错误信息")
app:layout_scrollFalgs="scrill|enterAlways"
1. 自定义View监听CoordinatorLayout里滑动
2. 定义View监听另一个View的状态变化,例如View的大小、位置和显示状态等
MotionEvent
1.getX--获取点击事件距离控件左边的距离,视图坐标。
2.getRawX--获取点击事件距离整个屏幕顶边的距离,绝对坐标。
//跟随手指移动的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;
}
}
@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. final LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) getLayoutParams();
params.leftMargin = getLeft() + offsetX();
...
setLayoutParams(params);
2. (ViewGroup.MarginLayoutParams)getLayoutParams()
params.leftMargin = getLeft() + offsetX();
//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:移动到一个具体坐标点
2.scrollBy:移动增量dx、dy
3.((View)getParent).scrollBy(-offsetX,offsetY)
4.注意:效果是瞬间完成的。
1.并不能实现View滑动,要配合View的computeScroll()
2.在computeScroll()中不断让View进行重绘,计算滑动持续时间,算出View滑动位置,调用scrollTo()方法进行滑动。
0.ObjectAnimator.ofFloat(view,"translationX",200)
1.translationX、translationY
2.rotaiton、rotationX、rotationY->旋转
3.PrivotX、PrivotY->旋转 缩放
4.alpha
5.x、y:View对象最终位置
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.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:多个动画一起执行
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中使用属性动画
Animator animator = AnimatorInflater.loadAnimator(this.getContext(), R.animator.demo);
animator.setTarget(this);
animator.start();
1.setContentView()->getWindow()(Window).setContentView()->getWindow()返回一个mWindow,实际在Activity的attach中创建一个PhoneWindow对象,PhonwWindow会创建DecorView作为窗口的根View,DecorView包含一个Titlle,一个ContentView
2.Activity->PhoneWindow->DecorView(TitleView+ContentView)
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消费这个事件
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.具体见下图
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.View的内部类,View规格尺寸(宽、高)
2.32位int值,高2位代表SpecMode(测量模式),低30位代表SpecSize(测量大小)
3.MeasureSpec 受自身LayoutParams和父容器的MeasureSpec共同影响
4.DecorView中的MeasureSpec根据自身的LayoutParams和窗口大小决定的
模式 | 名称 | 简介 |
---|---|---|
UNSPECIFIED | 未指定模式 | 想要多大就多大 |
AT_MOST | 最大模式 | wrap_content |
EXACTILY | 精确模式 | match_parent、具体值 |
1. onMeasure -> setMeasureDimension(测量宽高)、getDefaultSize(getSuggestedMinimumWidth)
2. getDefaultSize 中 AT_MOST 和 EXACTLY (wrap_content 和 match_parent)效果一样 所以继承 View 要重写 onMeasure 方法
3. getSuggestedMinimumWidth->如果View没有设置背景,返回mMinWidth,如果设置了,返回mMinWidth和Drawable最小宽度之间的最大值
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 指定默认 宽高
1. 确定元素的位置,ViewGroup中的layout用来确定子元素位置,View中layout 用来确定自身位置
2. layout(l,t,t,b)->setFrame->onLayout()(View 和 ViewGroup 中均没有实现onLayout方法)
1. 如果需要,绘制背景->drawBackgroup
2. 保存当前canvas层
3. 绘制view的内容-> onDraw(canvas)(空实现)
4. 绘制子view -> dispatchDraw(canvas)(空实现) ViewGroup->遍历调用 drawChild->调用View的draw方法,判断是否有缓存,没有正常绘制,有利用缓存显示
5. 如果需要,绘制view的褪色边缘,类似阴影效果
6. 绘制装饰,比如滚动条 -> onDrawForegroup-> 绘制ScrollBar以及其他装饰,并将它们绘制在视图内容上层
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);
}
}
}
1. New:新建
2. Runnbale:可运行
3. Blocked:阻塞
4. Waiting:等待、wait 方法
5. Timed waiting:超时等待
6. Terminated:终止
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();
}
}
1.Thread.currentThread.interrupt()来设置中断状态
2.直接抛出异常
1.condition.await() 阻塞当前线程,并放弃锁
2.signalAll、singnal
synchronized(obj)
线程A 本地内存 主内存 本地内存 线程B
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();
}
}
}
}
}
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:丢弃最近任务,并执行当前任务
泛型参数 | 核心方法 | 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) |
第一次握手 | 第二次握手 | 第三次握手 |
---|---|---|
建立连接,客户端发送连接请求报文段,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) TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送。
(2) 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
(3) 服务器关闭客户端的连接,发送一个FIN给客户端。
(4) 客户端发回ACK报文确认,并将确认序号设置为收到序号加1。
略
略