自动扩容:
LinkedList<String> queue = new LinkedList<>();
queue.push("1");
queue.push("2");
queue.push("3");
System.out.println(queue.pop());
System.out.println(queue.pop());
System.out.println(queue.pop());
LinkedList<String> deque = new LinkedList<>();
deque.offerFirst("1");
deque.offerFirst("2");
deque.offerFirst("3");
System.out.println(deque.pollLast());
System.out.println(deque.pollLast());
System.out.println(deque.pollLast());
ThreadLocal 是一个关于创建线程局部变量的类。
public T get() {
Thread t = Thread.currentThread(); //code 1
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
public void set(T value) {
Thread t = Thread.currentThread(); //code 2
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
/**
* Variant of set() to establish initialValue. Used instead
* of set() in case user has overridden the set() method.
*
* @return the initial value
*/
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
ThreadLocalMap是什么
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
private Entry[] table;
//省略部分代码
}
ThreadLocal在Looper中的应用
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {//code 1
throw new RuntimeException("Only one Looper may be create per thread");
}
sThreadLocal.set(new Looper(quitAllowed));// code 2
}
1.通过二分法查找数据。
2.不适合存储大数据。
3.比起HashMap,执行效率慢,查找通过二分法,添加和删除需要插入和删除数组中的条目。
为了提高性能,SparseArray在删除时做了一个优化,不会实际删除项,而是将需要删除的对象做一个标记。
public class SingleTon {
//需要注意的是volatile
private static volatile SingleTon mInstance;
private SingleTon() {
}
public static SingleTon getInstance() {
if (mInstance == null) {
synchronized (SingleTon.class) {
if (mInstance == null) {
mInstance=new SingleTon();
}
}
}
return mInstance;
}
}
?三种种实现方式:wait 和 notify、await 和 signal、BlockingQueue。?
public class StorageWithWaitAndNotify {
private final int MAX_SIZE = 10;
private LinkedList<Object> list = new LinkedList<Object>();
public void produce() {
synchronized (list) {
while (list.size() == MAX_SIZE) {
System.out.println("仓库已满:生产暂停");
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
list.add(new Object());
System.out.println("生产了一个新产品,现库存为:" + list.size());
list.notifyAll();
}
}
public void consume() {
synchronized (list) {
while (list.size() == 0) {
System.out.println("库存为0:消费暂停");
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
list.remove();
System.out.println("消费了一个产品,现库存为:" + list.size());
list.notifyAll();
}
}
}
import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
class StorageWithAwaitAndSignal {
private final int MAX_SIZE = 10;
private ReentrantLock mLock = new ReentrantLock();
private Condition mEmpty = mLock.newCondition();
private Condition mFull = mLock.newCondition();
private LinkedList<Object> mList = new LinkedList<Object>();
public void produce() {
mLock.lock();
while (mList.size() == MAX_SIZE) {
System.out.println("缓冲区满,暂停生产");
try {
mFull.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
mList.add(new Object());
System.out.println("生产了一个新产品,现容量为:" + mList.size());
mEmpty.signalAll();
mLock.unlock();
}
public void consume() {
mLock.lock();
while (mList.size() == 0) {
System.out.println("缓冲区为空,暂停消费");
try {
mEmpty.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
mList.remove();
System.out.println("消费了一个产品,现容量为:" + mList.size());
mFull.signalAll();
mLock.unlock();
}
}
public class StorageWithBlockingQueue {
private final int MAX_SIZE = 10;
private LinkedBlockingQueue<Object> list = new LinkedBlockingQueue<Object>(MAX_SIZE);
public void produce() {
if (list.size() == MAX_SIZE) {
System.out.println("缓冲区已满,暂停生产");
}
try {
list.put(new Object());
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("生产了一个产品,现容量为:" + list.size());
}
public void consume() {
if (list.size() == 0) {
System.out.println("缓冲区为空,暂停消费");
}
try {
list.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消费了一个产品,现容量为:" + list.size());
}
}
ViewRootImpl.java
WindowManagerGlobal.java
WindowManagerService.java
PhoneWindow.java
Window, WindowManager和WindowManagerService之间的关系
比较一下requestLayout和invalidate方法
requestLayout和invalidate区别
View的绘制流程是从Activity的 onResume 方法开始执行的。 首先我们找到 onResume 在哪儿执行的,
// ActivityThread.java
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) {
// 1 执行 onResume 流程
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
// 2 执行 View 的流程
wm.addView(decor, l);
}
不一定
如果通过恢复onResume, 则可以; 若不是恢复,则不可以;
在 onResume() 中 handler.post(Runnable) 是无法正确的获取不到 View 的真实宽高
在requestLayout中会检查线程
dispatchTouchEvent : 事件分发逻辑
事件分发逻辑,返回值boolean类型. true表示该View或ViewGroup处理了事件, 反之返回false.
dispatchTouchEvent与onTouchEvent的区别在于,默认情况下前者的返回值依赖于后者的返回值, 而且前者的侧重点在于制定事件分发的流程,后者侧重点在于View或者ViewGroup是否处理该事件.
onInterceptTouchEvent: 是否拦截事件(ViewGroup)
是ViewGroup专属的方法.当返回值为true表示ViewGroup需要拦截该事件. 这里有两种情况:
onTouchEvent:是否处理事件
父容器通过重写 onInterceptTouchEvent 方法并返回true 达到拦截事件的目的。
onTouchEvent如果返回false onClick还会执行么?
onClick是在 onTouchEvent 方法内部执行的,所以onClick是否执行,与 onTouchEvent 方法的返回值显然是没关系的。
责任链模式的缺点:
滑动卡顿解决方案
recyclerView.setHasFixedSize(true);
recyclerView.setNestedScrollingEnabled(false);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this) {
@Override
public boolean canScrollVertically() {
return false;
}
};
综合解决方案
ScrollView
LinearLayout/RelativeLayout
RecyclerView
@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
super.onMeasure(recycler, state, widthSpec, heightSpec);
// 重新实现RecyclerView高度的计算,使得其能够在ScrollView中表现出正确的高度.
}
public class RecyclerScrollView extends ScrollView {
private int slop;
private int touch;
public RecyclerScrollView(Context context) {
super(context);
setSlop(context);
}
public RecyclerScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
setSlop(context);
}
public RecyclerScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setSlop(context);
}
/**
* 是否intercept当前的触摸事件
*
* @param ev 触摸事件
* @return true:调用onMotionEvent()方法,并完成滑动操作
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
// 保存当前touch的纵坐标值
touch = (int) ev.getRawY();
break;
case MotionEvent.ACTION_MOVE:
// 滑动距离大于slop值时,返回true
if (Math.abs((int) ev.getRawY() - touch) > slop) return true;
break;
}
return super.onInterceptTouchEvent(ev);
}
/**
* 获取相应context的touch slop值(即在用户滑动之前,能够滑动的以像素为单位的距离)
*
* @param context ScrollView对应的context
*/
private void setSlop(Context context) {
slop = ViewConfiguration.get(context).getScaledTouchSlop();
}
}
Inflate 是通过反射xml标签中的类开创建view的,这个反射过程相对比较耗时,因此它比直接在java中创建View的效率要高。
一般H5的加载流程:
从流程上看存在的直观的问题:
主流的解决方案有:
交互方式总结
mWebview.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
return false;
}
});
mWebview.loadUrl("https://www.baidu.com/");
private void dimBackground(final float from, final float to) {
final Window window = getWindow();
ValueAnimator valueAnimator = ValueAnimator.ofFloat(from, to);
valueAnimator.setDuration(500);
valueAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
WindowManager.LayoutParams params = window.getAttributes();
params.alpha = (Float) animation.getAnimatedValue();
window.setAttributes(params);
}
});
valueAnimator.start();
}
变暗: dimBackground(1.0f, 0.5f);
变亮: dimBackground(0.5f, 1.0f);
ListView缓存
在整个滑动的过程中,离开屏幕的Item立即被回收至缓存ScrapView,滑入屏幕的Item则会优先从缓存ScrapView中获取,只是ListView与RecyclerView的实现细节有差异。
ListView与RecyclerView缓存级别的对比
是否需要回调createView | 是否需要回调bindView | 生命周期 | 备注 | |
---|---|---|---|---|
mActiveViews | 否 | 否 | onLayout函数周期内 | 用于屏幕itemView快速复用 |
mScrapViews | 否 | 是 | 与mAdapter一致,当mAdapter被更换时,mScrapViews即被清除 |
ListView获取缓存的流程:
RecyclerView(四级缓存):
是否需要createview | 是否需要调用bindView | 生命周期 | 备注 | |
---|---|---|---|---|
mAttachedScrap | 否 | 否 | onLayout函数周期中 | 用于屏幕内itemview快速复用 |
mCachedViews | 否 | 否 | 与mAdapter一致,当mAdapter被更换时,mCachedViews即被缓存至mRecyclerPool | 默认上限为2,即缓存屏幕外2个itemview |
mViewCachedExtension | 否 | 否 | 不直接使用,需要用户再制定,默认不实现 | |
mRecyclerPool | 否 | 是 | 与自身生命周期一致,不再被引用时即被释放 | 默认上限为5, 技术上可以实现所有RecyclerPool共用同一个 |
真正带你搞懂 RecyclerView 的缓存机制,再也不怕面试被虐了
【Android】RecyclerView 缓存机制,真的很难理解?到底是几级缓存?
让你彻底掌握RecyclerView的缓存机制
RecyclerView.java
Android学习小计:ViewPager2中的Fragment懒加载实现方式
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
for (int i = 0; i < image_id.length; i++) {
this.getChildAt(i).layout(i * getWidth(), t, (i + 1) * getWidth(), b);
}
}
ORM映射关系设计与详解
如何自己去设计一套数据库框架
Room框架的设计策略
Room框架的基本使用
Android Jetpack 学习之 Room 框架
【Jetpack】Room 中的销毁重建策略 ( 创建临时数据库表 | 拷贝数据库表数据 | 删除旧表 | 临时数据库表重命名 )
Jetpack Room 使用及原理解析
【Android Jetpack】Room数据库的使用及原理详解
Jetpack之Room
【Jetpack】Room + ViewModel + LiveData 综合使用 ( 核心要点说明 | 组合方式 | 代码示例 )
什么是Navigation
Navigation三大件
Navigation与Fragment
Navigation的高级用法
导航图数据如何加载?如何管理?
NavController如何进行跳转控制
Navigation如何管理回退栈
Navigation对于Fragment/show-hide的处理探索
框架设计中的高级反射技术
手写实现隔离层完成框架切换
hilt使用与实现原理分析
使用jetpack新技术hilt实现深度解耦
paging选择的及思想方案及处理(paging的业务分析)
paging的基础使用
paging的设计原理
WorkManager后台服务管理神器分析
WorkManager与保活分析
WorkManager源码解析
对于WorkManager在项目中应用下的思考
区域:
除了程序计数器,其他的部分都会发生OOM
Java内存模型规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存,线程的工作内存中保存了该线程中是用到的变量的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存。不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量的传递均需要自己的工作内存和主存之间进行数据同步进行。
原子性:
可见性:
有序性:
volatile
它所修饰的?变量?不保留拷贝,直接访问主内存中的。
synchronize
当它用来修饰?一个方法或者一个代码块?的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
Looper.java
Handler.java
MessageQueue.java
因为应用在启动的过程中就已经初始化了一个主线程Looper。每个java应用程序都是有一个main方法入口,Android是基于Java的程序也不例外,Android程序的入口在ActivityThread的main方法中,代码如下:
// 初始化主线程Looper
Looper.prepareMainLooper();
...
// 新建一个ActivityThread对象
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
// 获取ActivityThread的Handler,也是他的内部类H
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
...
Looper.loop();
// 如果loop方法结束则抛出异常,程序结束
throw new RuntimeException("Main thread loop unexpectedly exited");
}
可以看到,main方法中会先初始化主线程Looper,新建ActivityThread对象,然后再启动Looper,这样主线程的Looper在程序启动的时候就跑起来了。并且,我们通常认为 ActivityThread 就是主线程,事实上它并不是一个线程,而是主线程操作的管理者。
ActivityThread.java
因为当Looper处理完所有消息的时候会进入阻塞状态,当有新的Message进来的时候会打破阻塞继续执行。
在loop方法中,找到要处理的Message需要调用下面的一段代码来处理消息:
msg.target.dispatchMessage(msg);
所以是将消息交给了msg.target来处理,那么这个target是什么呢,通常查看target的源头可以发现:
private boolean enqueueMessage(MessageQueue queue,Message msg,long uptimeMillis) {
msg.target = this;
return queue.enqueueMessage(msg, uptimeMillis);
}
在使用Hanlder发送消息的时候,会设置msg.target = this,所以target就是当初把消息加到消息队列的那个Handler。
使用不同线程的Looper处理消息。我们知道,代码的执行线程,并不是代码本身决定,而是执行这段代码的逻辑是在哪个线程,或者说是哪个线程的逻辑调用的。每个Looper都运行在对应的线程,所以不同的Looper调用的dispatchMessage方法就运行在其所在的线程了。
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
循环加锁,配合阻塞唤醒机制。我们发现,MessageQueue其实是【生产者-消费者】模型,Handler不断地放入消息,Looper不断地取出,这就涉及到死锁问题。如果Looper拿到锁,但是队列中没有消息,就会一直等待,而Handler需要把消息放进去,锁却被Looper拿着无法入队,这就造成了死锁,Handler机制的解决方法是循环加锁,代码在MessageQueue的next方法中:
Message next() {
...
for (;;) {
...
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
...
}
}
}
epoll
Handler的阻塞唤醒机制是基于Linux的阻塞唤醒机制。这个机制也是类似于handler机制的模式。在本地创建一个文件描述符,然后需要等待的一方则监听这个文件描述符,唤醒的一方只需要修改这个文件,那么等待的一方就会收到文件从而打破唤醒。
所谓同步屏障,其实就是一个Message,只不过它是插入在MessageQueue的链表头,且其target==null。 而Message加急消息就是使用同步屏障实现的。同步屏障用到了postSyncBarrier()方法。
public int postSyncBarrier() {
return postSyncBarrier(SystemClock.uptimeMillis());
}
private int postSyncBarrier(long when) {
synchronized (this) {
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;
Message prev = null;
Message p = mMessages;
// 把当前需要执行的Message全部执行
if (when != 0) {
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
// 插入同步屏障
if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
}
可以看到,同步屏障就是一个特殊的target,即target==null,我们可以看到他并没有给target属性赋值,那这个target有什么用呢?
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
如果遇到同步屏障,那么会循环遍历整个链表找到标记为异步消息的Message,即isAsynchronous返回true,其他的消息会直接忽视,那么这样异步消息,就会提前被执行了。同时,,同步屏障不会自动移除,使用完成之后需要手动进行移除,不然会造成同步消息无法被处理。
前面说过,当MessageQueue没有消息的时候,就会阻塞在next方法中,其实在阻塞之前,MessageQueue还会做一件事,就是检查是否存在IdleHandler,如果有,就会去执行它的queueIdle方法。
HandlerThread源码
public class HandlerThread extends Thread {
@Override
public void run() {
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
}
可以看到,HandlerThread是一个封装了Looper的Thread类,就是为了让我们在子线程里面更方便的使用Handler。这里的加锁就是为了保证线程安全,获取当前线程的Looper对象,获取成功之后再通过notifyAll方法唤醒其他线程,那哪里调用了wait方法呢?答案是getLooper方法。
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
常用的跨进程通信有:共享内存、管道、消息队列、Socket。虽然都能实现跨进程通信,但需要拷贝两次。Binder通过mmap实现,通过映射内存实现一次拷贝,大大提高了跨进程通信效率。
为什么 Android 要采用 Binder 作为 IPC 机制?
面试官:为什么 Android 要采用 Binder 作为 IPC 机制?
用户空间是分配给用户进程的内存区域。内核空间是操作系统内核运行的区域。
物理地址是指计算机中实际硬件内存芯片上的地址。虚拟地址通过使用页表或段表等机制,将虚拟地址映射到物理地址。
使用mmap
mmap是一种内存映射文件的方法
“页”(Page)是操作系统中用于管理内存的基本单位之一。它是一块连续的内存区域,具有固定的大小。操作系统使用页作为内存管理的基本单元,来管理进程的虚拟内存和物理内存之间的映射关系。
回答:1M-8K
Intent传输数据的大小受Binder的限制,上限是1M。不过这个1M并不是安全的上限,Binder可能在处理别的工作,安全上限是多少这个在不同的机型上也不一样。
一次Binder通信最大可以传输多大的数据?
intent传递数据大小限制
会生成一个Stub内部类,实现跨进程的通信。
在Android系统中,每个进程的Binder线程数默认最大是16。但每个版本可能会有不同的结果。
回答:
回答: BinderProxy是Native层创建的,Java层并没有新建入口. BinderProxy的关键函数是transact, Java层通过该函数进行Binder通信.
首先,BinderProxy是Native层新建的,Java层并没有BinderProxy的新建入口。
其次,BinderProxy的关键函数是transact,java层的Binder客户端通过该函数进行Binder通信。
而该函数本质上也是调用的native层接口,具体来说,BinderProxy通过调用native层的transactNative方法来进行Binder通信。
此外,值得一提的是,“BpBinder” 和 BinderProxy 其实是一个东西:远程 binder 实体,只不过一个在Native层、一个在Java层,“BpBinder” 内部持有了一个 binder 句柄值 handle。
因此,可以说Java层的Binder实体与BinderProxy的实例化及使用都是依赖于Native层的,两者之间存在着紧密的联系和交互。
当客户端发起一个Binder请求时,系统会为该请求分配一个唯一的标识符(即Binder Token),并将该标识符和请求数据一起传递给Binder驱动。
init进程是用户空间的第一个进程,其进程号为1.
在Android系统中,init进程是用户空间的第一个进程,其进程号为1。它在系统启动流程中扮演着重要的角色,该流程大致为:BootRom > Bootloader > Kernel > Init > Zygote > SystemServer > Launcher。
当bootloader启动后,会启动kernel,kernel启动完后,在用户空间启动init进程。然后,init进程通过读取和解析init.rc中的相关配置来启动其他相关进程以及其他操作。例如,我们熟悉的Zygote孵化器进程就是由init进程启动的。
总的来说,init进程在初始化过程中会启动很多重要的守护进程,因此,了解 Init 进程的启动过程将有助于我们更好地理解 Android系统。
init进程启动后,会读取init.rc文件. 将需要启动的系统服务放到该文件中,会随着init的启动而启动
Zygote进程是一种非常重要的进程,它是由Linux的初始进程(init)启动的。Zygote进程是所有Android应用进程的父进程,包括SystemServer和各种应用程序进程都是通过Zygote进程fork出来的。
虽然Socket和Binder有不同的优缺点,而在Zygote进程中使用Socket可以更好地满足Zygote进程的需求。
每个应用在运行时都会加载自己所需的系统资源和类,而不会重复加载整个系统的资源和类。
PMS是包管理器服务, 负责管理应用程序的安装、卸载、权限授予和查询等相关任务
承担了管理应用程序生命周期、任务栈、进程、Activity启动等重要职责。
通过注册,系统可以正确地管理和调度应用程序的各个组件,确保正确地时机被启动.
通过在AndroidManifest.xml文件中声明Activity,系统可以正确地管理和调度应用程序的各个组件,确保它们能够在正确的时机被启动、与其他组件正确地交互,并能够被系统和其他应用程序正确地识别和使用。这也是Android应用程序架构的一部分,确保应用程序的组件能够协同工作。
主要涉及4个类:
主要类 | 说明 |
---|---|
ActivityRecord | 存在历史栈的一个实例,代表一个Activity。Activity在AMS中的存在形式,ActivityRecord保存了Activity的信息。 |
TaskRecord | Activity栈,内部维护一个ArrayList |
ActivityStack | 并不是一个Activity栈,真正意义上的Activity栈是TaskRecord,这个类是负责管理各个Activity栈,内部维护一个ArrayList |
ActivityStackSupervisor | 内部持有一个ActivityStack,而ActivityStack内部也持有ActivityStackSupervisor,相当于ActivityStack的辅助管理类 |
ActivityStack 管理 TaskRecord ,TaskRecord 管理 ActivityRecord。
知识点梳理 - AMS 的介绍及知识点
AMS之Activity栈管理(上篇)
Android ActivityManagerService(AMS)的Activity管理
AMS (3): AMS 如何管理Activity?
Android AMS 原理解读
“一文读懂”系列:AMS是如何动态管理进程的?
PMS/AMS/WMS原理解析
回答:
调用startAdtivity时候,通过Instrument类调用AMS中的startActivity,
然后通过一系列的检查后, 就会创建一个ActivityRecord,用来保存Activity信息,
检查是否已经创建了该进程,
然后调用生命周期
调用 Activity 的 startActivity 方法来启动目标 Activity
接着就会调用到 Instrunmentation 的 execStartActivity 方法,通过获取 ATMS 的 binder 代理对象,然后调用到 ATMS 的 startActivity 中去
调用到 ATMS 中后,会执行到ActivityStarter 的 execute 方法,内部最终执行到了 executeRequest ,接着就会进行一些校验和判断权限,包括进程检查,intent检查,权限检查等,后面就会创建 ActivityRecord ,用来保存 Activity 的相关信息,
然后就会根据启动模式计算 flag ,设置启动 Activity 的 Task 栈。
在 ActivityTaskSupervisor 中检查要启动的 Activity 进程是否存在,存在则向客户端进程 ApplicationThread 回调启动 Activity,否则就创建进程。
会调到 ActivityThread 后在 TransactionExecute 中开始执行system_server回调回来的事务,处理各种回调,切换到对应的生命周期
最后又回调到 ActivityThread 的 handleLaunchActivity 来启动 Activity。在其中调用了 performLaunchActivity 方法。
在 performLaunchActivity 中通过反射创建 Activity 实例,如果没有 Application 则先进行创建,然后再调用Activity 的 attach 方法进行初始化,最后回调 activity 的 onCreate 方法。
Android 深入研究之 ? Activity启动流程+Activity生命周期?
从一个APP启动另一个APP的Activity的方法
Android | Activity 启动流程分析
Android 性能优化必知必会(2020-4-27日更新)
startService 和bindService 区别?
Android中动画大致分为3类:帧动画、补间动画(Tween Animation)、属性动画(Property Animation)。
补间动画与属性动画的区别:
测量时间:
两个工具:systrace&Traceview
使用AspectJ测量时间
优化启动技巧:
线下监控:
线上监控:
Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
if (mStartFrameTime == 0) {
mStartFrameTime = frameTimeNanos;
}
long interval = frameTimeNanos - mStartFrameTime;
if (interval > MONITOR_INTERVAL_NANOS) {
double fps = (((double) (mFrameCount * 1000L * 1000L)) / interval) * MAX_INTERVAL;
mFrameCount = 0;
mStartFrameTime = 0;
} else {
++mFrameCount;
}
Choreographer.getInstance().postFrameCallback(this);
}
});
检测:
setho
Android进程保活招数概览
进程保活
【腾讯Bugly干货分享】Android 进程保活招式大全
2018年Android的保活方案效果统计
Android 10 低内存应用白名单和应用保活
android10 保活 安卓10保活 转载
android10进程保活
android 10 应用保活 android应用保活方案 转载
Android App保活的方式
public class AccountHelper {
//authenticator.xml 中配置 的accountType值
private static final String ACCOUNT_TYPE = "com.cby.processkeeplive";
/**
* 添加Account,需要"android.permission.GET_ACCOUNTS"权限
*
* @param context
*/
@SuppressLint("MissingPermission")
public static void addAccount(Context context) {
AccountManager accountManager = (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
Account[] accountsType = accountManager.getAccountsByType(ACCOUNT_TYPE);
if (accountsType.length > 0) {
Log.e("cby", "账户已经存在");
return;
}
//给这个账户类型添加账户 cby cby007
Account account = new Account("cby", ACCOUNT_TYPE);
//需要"android.permission.AUTHENTICATE_ACCOUNTS"权限
accountManager.addAccountExplicitly(account, "cby007", new Bundle());
}
/**
* 设置账户同步,即告知系统我们需要系统为我们来进行账户同步,只有设置了之后系统才会自动去
* 触发SyncAdapter#onPerformSync方法
*/
public static void autoSyncAccount() {
Account account = new Account("cby", ACCOUNT_TYPE);
//设置可同步
ContentResolver.setIsSyncable(account, AppUtils.getDefault().getPackageName() + ".provider", 2);
//设置自动同步
ContentResolver.setSyncAutomatically(account, AppUtils.getDefault().getPackageName() + ".provider", true);
//设置同步周期参考值,不受开发者控制完全由系统决定何时同步,测试下来最长等了差不多几十分钟才同步一次,不同系统表现不同
ContentResolver.addPeriodicSync(account, AppUtils.getDefault().getPackageName() + ".provider", new Bundle(), 1);
}
}
public class AuthenticationService extends Service {
private AccountAuthenticator mAuthenticator;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mAuthenticator.getIBinder(); // 返回操作数据的Binder
}
@Override
public void onCreate() {
super.onCreate();
mAuthenticator = new AccountAuthenticator(this);
}
/**
* AbstractAccountAuthenticator 是用于实现对手机系统设置里“账号与同步”中Account的添加、删除和验证等一些基本功能。
*/
class AccountAuthenticator extends AbstractAccountAuthenticator {
public AccountAuthenticator(Context context) {
super(context);
}
@Override
public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
return null;
}
@Override
public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {
return null;
}
@Override
public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException {
return null;
}
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
return null;
}
@Override
public String getAuthTokenLabel(String authTokenType) {
return null;
}
@Override
public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
return null;
}
@Override
public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException {
return null;
}
}
}
public class SyncContentProvider extends ContentProvider {
@Override
public boolean onCreate() {
return false;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
return null;
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
}
public class SyncService extends Service {
private SyncAdapter mSyncAdapter;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mSyncAdapter.getSyncAdapterBinder();
}
@Override
public void onCreate() {
super.onCreate();
mSyncAdapter = new SyncAdapter(getApplicationContext(), true);
}
static class SyncAdapter extends AbstractThreadedSyncAdapter {
public SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
}
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
//todo 账户同步 工作
Log.e("cby","同步账户");
//与互联网 或者 本地数据库同步账户
}
}
}
public class GuardJobService extends JobService {
@Override
public boolean onStartJob(JobParameters params) {
Log.e(Constant.TAG, "开启job");
//如果7.0以上 轮询
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
startGuardJob(this);
}
boolean isLocalRun = isServiceWork(this, LocalService.class.getName());
boolean isRemoteRun = isServiceWork(this, RemoteService.class.getName());
if (!isLocalRun || !isRemoteRun) {
LocalService.start(this);
RemoteService.start(this);
}
return false;
}
@Override
public boolean onStopJob(JobParameters params) {
return false;
}
@SuppressLint("MissingPermission")
public static void startGuardJob(Context context) {
if (context != null) {
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
// setPersisted 在设备重启依然执行
JobInfo.Builder builder = new JobInfo.Builder(10, new ComponentName(context
.getPackageName(), GuardJobService.class
.getName())).setPersisted(true);
//小于7.0
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
// 每隔1s 执行一次 job
builder.setPeriodic(1_000);
} else {
// 延迟执行任务
builder.setMinimumLatency(1_000);
}
jobScheduler.schedule(builder.build());
}
}
// 判断服务是否正在运行
public boolean isServiceWork(Context mContext, String serviceName) {
boolean isWork = false;
ActivityManager manager = (ActivityManager) mContext
.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningServiceInfo> serviceInfoList = manager.getRunningServices(100);
if (serviceInfoList.size() <= 0) {
return false;
}
for (int i = 0; i < serviceInfoList.size(); i++) {
String serviceClassName = serviceInfoList.get(i).service.getClassName();
if (serviceClassName.equals(serviceName)) {
isWork = true;
break;
}
}
return isWork;
}
}
public class ForegroundService extends Service {
private static final int SERVICE_ID = 1;
public static void start(Context context) {
context.startService(new Intent(context, ForegroundService.class));
}
@Override
public IBinder onBind(Intent intent) {
return new KeepLiveService();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (Build.VERSION.SDK_INT < 18) {
// 开启前台服务
startForeground(SERVICE_ID, new Notification());
} else if (Build.VERSION.SDK_INT < 26) {
// 开启前台服务
startForeground(SERVICE_ID, new Notification());
// 移除通知栏消息
startService(new Intent(this, InnerService.class));
} else {
// 8.0 以上
@SuppressLint("WrongConstant")
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (manager != null) {
NotificationChannel channel = new NotificationChannel("channel", "cby", NotificationManager.IMPORTANCE_MIN);
manager.createNotificationChannel(channel);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channel.getId());
startForeground(SERVICE_ID, builder.build());
}
}
return super.onStartCommand(intent, flags, startId);
}
public static class InnerService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startForeground(SERVICE_ID, new Notification());
stopForeground(true);
stopSelf();
return super.onStartCommand(intent, flags, startId);
}
}
private class KeepLiveService extends IKeepLiveService.Stub {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
}
}
public class LocalService extends ForegroundService {
public static void start(Context context) {
Intent intent = new Intent(context, LocalService.class);
context.startService(intent);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
bindService(new Intent(this, RemoteService.class), connection, Context.BIND_IMPORTANT);
return super.onStartCommand(intent, flags, startId);
}
ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
}
@Override
public void onServiceDisconnected(ComponentName name) {
// 远程进程被 kill ,拉活
Log.d(Constant.TAG, "远程进程被 kill ,拉活");
startService(new Intent(LocalService.this, RemoteService.class));
bindService(new Intent(LocalService.this, RemoteService.class), this, Context.BIND_IMPORTANT);
}
};
}
public class RemoteService extends ForegroundService {
public static void start(Context context) {
Intent intent = new Intent(context, RemoteService.class);
context.startService(intent);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
bindService(new Intent(this, LocalService.class), connection, Context.BIND_IMPORTANT);
return super.onStartCommand(intent, flags, startId);
}
ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
}
@Override
public void onServiceDisconnected(ComponentName name) {
// 远程进程被 kill ,拉活
Log.d(Constant.TAG, "主进程被 kill ,拉活");
startService(new Intent(RemoteService.this, LocalService.class));
bindService(new Intent(RemoteService.this, LocalService.class), this, Context.BIND_IMPORTANT);
}
};
}
public class KeepLiveManager {
private static final KeepLiveManager ourInstance = new KeepLiveManager();
private WeakReference<KeepLiveActivity> reference;
private KeepLiveReceiver receiver;
public static KeepLiveManager getInstance() {
return ourInstance;
}
private KeepLiveManager() {
}
public void register(Context context) {
if (receiver == null) {
receiver = new KeepLiveReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
context.registerReceiver(receiver, filter);
}
}
public void unRegister(Context context) {
if (receiver != null) {
context.unregisterReceiver(receiver);
}
}
public void setKeepLiveActivity(KeepLiveActivity activity) {
reference = new WeakReference<>(activity);
}
public void start(Context context) {
KeepLiveActivity.launch(context);
}
public void stop(Context context) {
if (reference != null && reference.get() != null) {
reference.get().finish();
}
}
}
public class KeepLiveActivity extends AppCompatActivity {
public static void launch(Context context) {
Intent intent = new Intent(context, KeepLiveActivity.class);
context.startActivity(intent);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Window window = getWindow();
// 设置左上角
window.setGravity(Gravity.TOP | Gravity.LEFT);
WindowManager.LayoutParams params = window.getAttributes();
// 坐标
params.x = 0;
params.y = 0;
// 设置 1 像素
params.width = 1;
params.height = 1;
window.setAttributes(params);
KeepLiveManager.getInstance().setKeepLiveActivity(this);
}
}
public class KeepLiveReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
// 屏幕熄灭,开启 KeepLiveActivity
KeepLiveManager.getInstance().start(context);
} else {
KeepLiveManager.getInstance().stop(context);
}
}
}
内存抖动:
内存不断分配对象, GC不断回收. 短时间大量的循环,导致内存抖动.
导致内存的卡顿.
甚至会引起OOM.
内存泄露:
无法回收对象
可作为GC Roots的对象包括:
static HashMap
AS自带工具
使用第三方工具:
LeakCanary
KOOM
创建Activity之前计算内存占用, 释放后Activity的内存占用,进行比较
原理:
弱引用对象在其包装对象被回收后(弱引用对象创建时,传入了引用队列),该弱引用对象会被加到引用队列中(ReferenceQueue)。
通过在ReferenceQueue中检测是否有目标对象的弱引用对象存在,即可判断目标对象是否被回收。
......
Activity mActivity;
......
ReferenceQueue<Activity> mQueue = new ReferenceQueue<>();
WeakReference<Activity> mWeakReference = new WeakReference<>(mActivity, mQueue);
......
RecyclerView与ListView 对比:缓存机制
RecyclerView比ListView多两级缓存,支持多个离屏ItemView缓存,支持开发者自定义缓存处理逻辑,支持所有RecyclerView共用同一个RecyclerViewPool(缓存池)。
具体来说:
ListView(两级缓存):
RecyclerView(四级缓存):
ListView和RecyclerView缓存机制基本一致:
Dispatcher ,分发器就是来调配请求任务的,内部会包含一个线程池。可以在创建 OkHttpClient 时,传递我们自己定义的线程池来创建分发器。
这个Dispatcher中的成员有:
//异步请求同时存在的最大请求
private int maxRequests = 64;
//异步请求同一域名同时存在的最大请求
private int maxRequestsPerHost = 5;
//闲置任务(没有请求时可执行一些任务,由使用者设置)
private @Nullable Runnable idleCallback;
//异步请求使用的线程池
private @Nullable ExecutorService executorService;
//异步请求等待执行队列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//异步请求正在执行队列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
//同步请求正在执行队列
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
因为同步请求不需要线程池,也不存在任何限制。所以分发器仅做一下记录
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
当正在执行的任务未超过最大限制64,同时 runningCallsForHost(call) < maxRequestsPerHost 同一Host的请求不超过5个,则会添加到正在执行队列,同时提交给线程池。否则先加入等待队列。
加入线程池直接执行没啥好说的,但是如果加入等待队列后,就需要等待有空闲名额才开始执行。因此每次执行完一个请求后,都会调用分发器的 finished 方法
//异步请求调用
void finished(AsyncCall call) {
finished(runningAsyncCalls, call, true);
}
//同步请求调用
void finished(RealCall call) {
finished(runningSyncCalls, call, false);
}
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
//不管异步还是同步,执行完后都要从队列移除(runningSyncCalls/runningAsyncCalls)
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
if (promoteCalls) promoteCalls();
//异步任务和同步任务正在执行的和
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
// 没有任务执行执行闲置任务
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
需要注意的是 只有异步任务才会存在限制与等待,所以在执行完了移除正在执行队列中的元素后,异步任务结束会执行 promoteCalls() 。很显然这个方法肯定会重新调配请求。
private void promoteCalls() {
//如果任务满了直接返回
if (runningAsyncCalls.size() >= maxRequests) return;
//没有等待执行的任务,返回
if (readyAsyncCalls.isEmpty()) return;
//遍历等待执行队列
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
//等待任务想要执行,还需要满足:这个等待任务请求的Host不能已经存在5个了
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
在满足条件下,会把等待队列中的任务移动到 runningAsyncCalls 并交给线程池执行。所以分发器到这里就完了。逻辑上还是非常简单的。
用户是不需要直接操作任务分发器的,获得的 RealCall 中就分别提供了 execute 与 enqueue 来开始同步请求或异步请求。
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
//调用分发器
client.dispatcher().executed(this);
//执行请求
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
//请求完成
client.dispatcher().finished(this);
}
}
异步请求的后续同时是调用 getResponseWithInterceptorChain() 来执行请求
@Override
public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
//调用分发器
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
如果该 RealCall 已经执行过了,再次执行是不允许的。异步请求会把一个 AsyncCall 提交给分发器。
AsyncCall 实际上是一个 Runnable 的子类,使用线程启动一个 Runnable 时会执行 run 方法,在 AsyncCall 中被重定向到 execute 方法:
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
//线程池执行
@Override
protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain();
//.......
} catch (IOException e) {
//......
} finally {
//请求完成
client.dispatcher().finished(this);
}
}
}
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
@Override
public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
同时 AsyncCall 也是 RealCall 的普通内部类,这意味着它是持有外部类 RealCall 的引用,可以获得直接调用外部类的方法。可以看到无论是同步还是异步请求实际上真正执行请求的工作都在getResponseWithInterceptorChain() 中。这个方法就是整个OkHttp的核心:拦截器责任链。但是在介绍责任链之前,我们再来回顾一下线程池的基础知识
前面我们提过,分发器就是来调配请求任务的,内部会包含一个线程池。当异步请求时,会将请求任务交给线程池来执行。那分发器中默认的线程池是如何定义的呢?为什么要这么定义?
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(
0, //核心线程
Integer.MAX_VALUE, //最大线程
60, //空闲线程闲置时间
TimeUnit.SECONDS, //闲置时间单位
new SynchronousQueue<Runnable>(), //线程等待队列
Util.threadFactory("OkHttp Dispatcher", false) //线程创建工厂
);
}
return executorService;
}
一般而言,我们都会借助一些框架来完成这个网络交互,OkHttp就是一个能够帮助我们完成网络通信的框架之一。借助OkHttp能否完成Http1.x、Http2.0以及WebSocket的通信。
你真的了解RxJava的线程切换吗?
Android:随笔——RxJava的线程切换
高频面试–RxJava线程切换的原理
RxJava的线程切换
RxJava3.0线程切换原理
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();
#LruCache
Map<T, Y> cache = new LinkedHashMap<>(100, 0.75f, true);
Glide中通过RequestManagerFragment,内部创建的无UI的Fargment完成生命周期监听。它在RequestManagerRetriever类的getRequestManagerFragment()被调用。相关源码
final Map<android.app.FragmentManager, RequestManagerFragment> pendingRequestManagerFragments = new HashMap<>();
private RequestManagerFragment getRequestManagerFragment(@NonNull final android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible) {
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);//获取Fragment
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
pendingRequestManagerFragments.put(fm, current);//保存到map集合
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();//添加到Actvity中
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
音视频开发成长之路与音视频知识总结
音视频开发流程(音视频开发教程)
音视频开发系列1:音视频开发基本概念
一文搞懂音视频开发技术点及职业发展方向
69 篇文章带你系统性的学习音视频开发(收藏起来假期看)
总结区别:
原理:在程序的运行状态中,动态获取程序信息及动态调用对象的功能成为Java的反射机制
如何获取一个Class对象
如何操作一个Class对象
谈谈Java反射:从入门到实践,再到原理
Java反射原理
Java反射机制原理探究
深入理解java反射原理
双亲委派机制是指当一个类加载器收到类加载请求时,它会先将该请求委派给它的父类加载器去尝试加载。只有当父类加载器无法加载该类时,子类加载器才会尝试加载。
优缺点:
优点: 1. 避免重复加载; 2. 安全性; 3.扩展性;
缺点: 1. 灵活性受限; 2. 破坏隔离性 3.不适合动态更新;
反射涉及动态解析的类型,因此无法执行某些Java虚拟机优化
反射提高了Java程序的灵活性和扩展性,降低耦合性,提高自适应能力。
import java.lang.annotation.*;
// 1.CONSTRUCTOR:用于描述构造器
// 2.FIELD:用于描述域
// 3.LOCAL_VARIABLE:用于描述局部变量
// 4.METHOD:用于描述方法
// 5.PACKAGE:用于描述包
// 6.PARAMETER:用于描述参数
// 7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
// @Target说明了Annotation所修饰的对象范围
@Target(ElementType.TYPE)
public @interface Table {}
@Target(ElementType.FIELD)
@interface NoDBColumn {}
// 取值(RetentionPoicy)有:
// 1.SOURCE:在源文件中有效(即源文件保留)
// 2.CLASS:在class文件中有效(即class保留)
// 3.RUNTIME:在运行时有效(即运行时保留)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented // 用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,
@interface Column {}
// @Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。
@Inherited
@interface Greeting {}
深入理解Java:注解(Annotation)自定义注解入门
public class Generic<T> {
private T key;
public Generic(T key) {this.key = key;}
public T getKey() {return key;}
}
//定义一个泛型接口
public interface Generator<T> {
public T next();
}
class FruitGenerator<T> implements Generator<T>{
@Override
public T next() {
return null;
}
}
public class FruitGenerator implements Generator<String> { /*TODO*/ }
public <T> T genericMethod(Class<T> tClass)throws InstantiationException ,
IllegalAccessException{
T instance = tClass.newInstance();
return instance;
}
public <T> void printMsg( T... args){
for(T t : args){
Log.d("泛型测试","t is " + t);
}
}
public class StaticGenerator<T> {
....
....
/**
* 如果在类中定义使用泛型的静态方法,需要添加额外的泛型声明(将这个方法定义成泛型方法)
* 即使静态方法要使用泛型类中已经声明过的泛型也不可以。
* 如:public static void show(T t){..},此时编译器会提示错误信息:
"StaticGenerator cannot be refrenced from static context"
*/
public static <T> void show(T t){/*TODO*/}
}
java 泛型详解-绝对是对泛型方法讲解最详细的,没有之一
Java 泛型上下界(上下限)
形变分为三个区域:不变, 协变, 逆变
class StudentSetGets<IO> {
private var item: IO? = null
fun set(value: IO) { /*TODO*/ }
fun get() = item
}
class MyStudentGet<out T>(_item: T) {
private val item = _item
fun get(): T = item
}
class MyStudentSet<in T>() {
fun set(value: T) = /*TODO*/
}
原理就是存放线程的池子
一文读懂Java多线程原理
class SomeThread extends Thread {
public void run();
}
SomeThread().start()
class SomeRunnable implements Runnable {
public void run() { //do something here }
}
Runnable oneRunnable = new SomeRunnable();
Thread oneThread = new Thread(oneRunnable); o
neThread.start();
//1.创建Callable接口的实现类,并实现call()方法
public class SomeCallable01 implements Callable {
@Override
public Integer call() throws Exception {
return 0;
}
}
public static void main(String[] args) {
//2.创建Callable实现类的实例
SomeCallable01 ctt = new SomeCallable01();
//3.使用FutrueTask类进行包装Callable对象,FutureTask对象封装了Callable对象的call()方法的返回值
FutureTask<Integer> ft = new FutureTask<>(ctt);
//开启ft线程
for(int i = 0;i < 21;i++)
{
System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);
if(i==20)//i为20的时候创建ft线程
{
//4.使用FutureTask对象作为Thread对象的target创建并启动新线程
new Thread(ft,"有返回值的线程FutureTask").start();
}
}
//ft线程结束时,获取返回值
try
{
//5.调用FutureTask对象的get()方法获取子线程执行结束后的返回值。
System.out.println("子线程的返回值:"+ft.get());//get()方法会阻塞,直到子线程执行结束才返回
} catch (InterruptedException e)
{
e.printStackTrace();
} catch (ExecutionException e)
{
e.printStackTrace();
}
}
private static void createCachedThreadPool() {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int index = i;
executorService.execute(() -> {
// 获取线程名称,默认格式:pool-1-thread-1
System.out.println(DateUtil.now() + " " + Thread.currentThread().getName() + " " + index);
// 等待2秒
sleep(2000);
});
}
}
private static void createFixedThreadPool() {
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int index = i;
executorService.execute(() -> {
// 获取线程名称,默认格式:pool-1-thread-1
System.out.println(DateUtil.now() + " " + Thread.currentThread().getName() + " " + index);
// 等待2秒
sleep(2000);
});
}
}
因为线程池大小是固定的,这里设置的是3个线程,所以线程名只有3个。因为线程不足会进入队列等待线程空闲,所以日志间隔2秒输出。
private static void createScheduledThreadPool() {
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(3);
System.out.println(DateUtil.now() + " 提交任务");
for (int i = 0; i < 10; i++) {
final int index = i;
executorService.schedule(() -> {
// 获取线程名称,默认格式:pool-1-thread-1
System.out.println(DateUtil.now() + " " + Thread.currentThread().getName() + " " + index);
// 等待2秒
sleep(2000);
}, 3, TimeUnit.SECONDS);
}
}
因为设置了延迟3秒,所以提交后3秒才开始执行任务。因为这里设置核心线程数为3个,而线程不足会进入队列等待线程空闲,所以日志间隔2秒输出。
private static void createSingleThreadPool() {
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
executorService.execute(() -> {
// 获取线程名称,默认格式:pool-1-thread-1
System.out.println(DateUtil.now() + " " + Thread.currentThread().getName() + " " + index);
// 等待2秒
sleep(2000);
});
}
}
因为只有一个线程,所以线程名均相同,且是每隔2秒按顺序输出的。
public ThreadPoolExecutor(
int corePoolSize, // 核心线程数,线程池中始终存活的线程数。
int maximumPoolSize, // 最大线程数,线程池中允许的最大线程数。
long keepAliveTime, // 存活时间,线程没有任务执行时最多保持多久时间会终止。
TimeUnit unit, // 单位,参数keepAliveTime的时间单位,7种可选。
BlockingQueue<Runnable> workQueue, // 一个阻塞队列,用来存储等待执行的任务,均为线程安全,7种可选。
ThreadFactory threadFactory, // 线程工厂,主要用来创建线程,默及正常优先级、非守护线程。
RejectedExecutionHandler handler // 拒绝策略,拒绝处理任务时的策略,4种可选,默认为AbortPolicy。
) { // 省略...}
workQueue: 7种选择
handler: 4种拒绝策略
执行策略:
(1)当线程数小于核心线程数时,创建线程。
(2)当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
(3)当线程数大于等于核心线程数,且任务队列已满:
若线程数小于最大线程数,创建线程。
若线程数等于最大线程数,抛出异常,拒绝任务。
线程池在内部实际上构建了一个生产者消费者模型,将线程和任务两者解耦,并不直接关联,从而良好的缓冲任务,复用线程。线程池的运行主要分成两部分:任务管理、线程管理。
任务管理部分充当生产者的角色,当任务提交后,线程池会判断该任务后续的流转:
(1)直接申请线程执行该任务;
(2)缓冲到队列中等待线程执行;
(3)拒绝该任务。线程管理部分是消费者,它们被统一维护在线程池内,根据任务请求进行线程的分配,当线程执行完任务后则会继续获取新的任务去执行,最终当线程获取不到任务的时候,线程就会被回收。
Java线程池实现原理及其在美团业务中的实践
CAS的全称为Compare-And-Swap,直译就是对比交换。
CLH(Craig,Landin,and Hagersten)队列是一个虚拟的双向队列(虚拟的双向队列即不存在队列实例,仅存在结点之间的关联关系)。AQS是将每条请求共享资源的线程封装成一个CLH锁队列的一个结点(Node)来实现锁的分配。
// 在后台队列中执行任务
DispatchQueue.global().async {
// 执行任务的代码
DispatchQueue.main.async {
// 在主队列中更新UI等
}
}
// 创建NSOperation对象
let operation = BlockOperation {
// 执行任务的代码
}
// 创建NSOperationQueue并添加任务
let operationQueue = OperationQueue()
operationQueue.addOperation(operation)
// 创建并启动线程
let thread = Thread {
// 执行任务的代码
}
thread.start()
let semaphore = DispatchSemaphore(value: 1)
// 等待信号
semaphore.wait()
// 信号通知
semaphore.signal()
let group = DispatchGroup()
// 将任务添加到组中
DispatchQueue.global().async(group: group) {
// 任务1
}
DispatchQueue.global().async(group: group) {
// 任务2
}
// 在所有任务完成时执行操作
group.notify(queue: .main) {
// 所有任务完成后执行的代码
}
反作弊sdk
打点sdk