美文网首页
笔记合集

笔记合集

作者: 荞麦穗 | 来源:发表于2020-05-16 20:50 被阅读0次

1、线程
Thread Runnable
activeCount() 线程活跃数
currentThread()
getName()
getPriority()
getState() 返回线程状态
getDefaultUncaughtExceptionHandler()返回未捕获的异常终止线程时执行的默认异常处理程序。
getContextClassLoader()返回此Thread的上下文ClassLoader。
getThreadGroup()返回此Thread所属的ThreadGroup。
getStackTrace()返回StackTraceElement表示当前线程堆栈的数组。
holdsLock(Object object) 指示当前Thread是否在指定对象上具有监视器锁定。
interrupt() 向此发布中断请求Thread。
interrupted() 返回一个布尔值,指示当前Thread(currentThread())是否有挂起的中断请求(true)或不是(false)。
isInterrupted() 返回一个布尔值,指示接收方是否有挂起的中断请求(true)或不是(false)
isAlive()
isDaemon()
sleep(long time)
sleep(long millis,int nanos)导致发送此消息的线程在给定的时间间隔内休眠(以毫秒和纳秒为单位)。
start()

线程池
好处:线程重用,减少创建和销毁的性能开销,控制线程的并发,避免大量线程争夺CPU资源造成阻塞,对线程进行管理,比如定时执行,周期执行,取消执行
坏处:保持核心线程的存活,占用内存资源。
参数:ThreadPoolExecutor
int corePoolSize,//核心线程数,除非allowCoreThreadTimeOut被设置为true,否则它闲着也不会死
int maximumPoolSize,//最大线程数,活动线程数量超过它,后续任务就会排队
long keepAliveTime,//超时时长,作用于非核心线程(allowCoreThreadTimeOut被设置为true时也会同时作用于核心线程),闲置超时便被回收
TimeUnit unit,//枚举类型,设置keepAliveTime的单位,有TimeUnit.MILLISECONDS(ms)、TimeUnit. SECONDS(s)等
BlockingQueue<Runnable> workQueue,//缓冲任务队列,线程池的execute方法会将Runnable对象存储起来
ThreadFactory threadFactory //线程工厂接口,只有一个new Thread(Runnable r)方法,可为线程池创建新线程

Android 四类常见线程池
1、 FixThreadPool(一堆人排队上公厕)不回收闲置线程
public static ExecutorService newFixThreadPool(int nThreads){
return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());}
//使用Executors.newFixThreadPool(5).execute(r);

2、SingleThreadPool(公厕里只有一个坑)不用处理线程同步问题
public static ExecutorService newSingleThreadPool (int nThreads){
return new FinalizableDelegatedExecutorService ( new ThreadPoolExecutor (1, 1, 0, TimeUnit. MILLISECONDS, new LinkedBlockingQueue<Runnable>()) );}
//使用Executors.newSingleThreadPool ().execute(r);

3、CachedThreadPool(一堆人去一家很大的咖啡馆喝咖啡)大量耗时较少的工作
public static ExecutorService newCachedThreadPool(int nThreads){
return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit. SECONDS, new SynchronousQueue<Runnable>());}
//使用Executors.newCachedThreadPool().execute(r);

4、ScheduledThreadPool(4个里面唯一一个有延迟执行和周期重复执行的线程池)
private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,new DelayedWorkQueue());}
public ScheduledFuture<?> schedule(Runnable command,long delay, TimeUnit unit); // 定时执行
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit);//延时(initialDelay)周期(period)执行
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit);//延时周期执行
scheduleAtFixedRate()和scheduleWithFixedDelay()区别:
scheduleAtFixedRate:延时后周期执行
scheduleWithFixedDelay:周期延时执行

线程池管理:Executor ExecutorService 管理线程池中线程的存活,状态,操作
shutdown()启动有序关闭,其中先前提交的任务将被执行,但不会接受任何新任务。
shutdownNow()尝试停止所有正在执行的任务,停止等待任务的处理,并返回等待执行的任务列表。
isTerminated()返回true如果关闭后所有任务都已完成
isShutdown()返回true如果此执行程序已关闭

基本的线程创建使用:
int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();//核心线程数
int KEEP_ALIVE_TIME = 1;
TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>();
new ThreadPoolExecutor(NUMBER_OF_CORES,
NUMBER_OF_CORES*2,
KEEP_ALIVE_TIME,
KEEP_ALIVE_TIME_UNIT,
taskQueue, //缓冲队列(不添加容量,表示可以添加无限等待的任务。)
Executors.defaultThreadFactory(),//创建线程的工厂
new ThreadPoolExecutor.AbortPolicy());//线程阻塞时使用的handler

二、锁 synchronized 和 lock
synchronized java内置关键字,释放锁的情况1)线程执行完了代码块 2)线程执行发生异常,JVM自动释放锁
Lock 类,必须手动释放锁,否则会出现死锁,ReentrantLock(可重入锁)ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock(互斥:当线程获取到写锁后无法在获取读锁)
获取锁:lock()、tryLock()、tryLock(long time, TimeUnit unit)和lockInterruptibly()
释放锁:unLock()

可重入锁:锁具有可重入性,如synchronized和ReentrantLock,在锁方法内部调用同一锁方法,如果不是可重入锁,则祸造成死锁
可中断锁:请求锁的过程公可以中断,如lock中的lockInterruptibly()。synchronized不是
公平锁:公平锁即尽量以请求锁的顺序来获取锁,ReentrantLock和ReentrantReadWriteLock默认时不公平的,当构造函数内传入,public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
读写锁: 读写锁将对一个资源(比如文件)的访问分成了2个锁,一个读锁和一个写锁。ReentrantReadWriteLock()
使用:
Lock lock = ...;
if (lock.tryLock()) {
try {
// manipulate protected state
finally {
lock.unlock();
}
} else {
// perform alternative actions
}}
对象锁、方法锁和类锁
synchronized
在修饰代码块的时候需要一个reference对象作为锁的对象.
在修饰方法的时候默认是当前对象作为锁的对象.
在修饰类时候默认是当前类的Class对象作为锁的对象.
对象锁:
当一个对象中有synchronized 方法或者synchronized block的时候,调用此对象的同步方法或者同步块的时候,需要西先获取对象锁,如果此对象锁已被其他调用者调用,则进入阻塞等待锁的释放,java所有对象都有一个互斥锁,这个锁由JVM自动获取和释放,当线程进入此方法的时候获取该锁,当此方法正常结束返回或者抛出异常终止,JVM会自动释放此对象锁。这也是synchronized加锁的一个好处,抛出异常锁依然正常释放
// 对象锁:形式1(方法锁)
public synchronized void Method1()
{
System.out.println("我是对象锁也是方法锁");
try
{
Thread.sleep(500);
} catch (InterruptedException e)
{
e.printStackTrace();
}

}

// 对象锁:形式2(代码块形式)
public void Method2()
{
synchronized (this)
{
System.out.println("我是对象锁");
try
{
Thread.sleep(500);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}

}

方法锁:
Synchronized 关键字来修饰方法,每个类实例对应一把锁,每个synchronized方法必须获取类的实例的锁才能执行
synchronized public void getSync(){
synchronized (this){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

重载和重写
重载:让类一同意的方式处理不同类型数据的一种手段,多个具有不同参数或者类型的同名函数(返回类型随意,不以返回类型作为重载函数的区分标准)同时存在于同一个类中,是类中多态性的一种体现
重写:父类和子类之间的多态性,实质是对父类中的函数进行重新定义,体现:子类和父类的方法具有相同的名称,返回类型和参数,则为重写,访问的修饰权限不能小于父类,覆盖原有的方法。
重载规则:必须具有不同的参数列表; 可以有不同的返回类型;可以有不同的访问修饰符;可以抛出不同的异常。
重写规则:名称,参数列表,返回类型必须与被重写的方法相同,否则不能称其为重写而是重载;访问修饰符的限制一定要大于等于被重写方法的访问修饰符,异常只能与重写方法抛的异常相同或者重写方法异常的子类
重载与重写是 Java 多态性的不同表现。
重写是父类与子类之间多态性的表现,在运行时起作用(动态多态性,譬如实现动态绑定)
重载是一个类中多态性的表现,在编译时起作用(静态多态性,譬如实现静态绑定)。
构造函数可以被重载不能被重写!

封装:把数据和方法包装进类中,具体实现隐藏
数据存储:
寄存器:存储速度快,但数量有限,不能控制
堆栈:位于RAM(随机访问存储器)中,存储对象引用
常量存储:常放在代码内部或者存放在ROM(只读存储器)
堆:位于RAM中,通用的内存池,存放所有的Java对象,而且不需要知道他们的存货时间,GC自动回收。
存盘存储:存储持久化的流和对象

八大基本数据类型:都是有正负号的,无引用,直接放在堆栈中,更加高效

注解(元数据):形式化添加信息的方式,一定程度上把原数据和源代码结合起来
注解不支持继承只能嵌套
@Override 当前方法覆盖超类中的方法
@Deprecated 编译器会发出警告
@SuppressWarning 关闭不当的编译器警告信息

元注解:用在什么地方、方法或域
@Target(ElementType.CONSTRUCTOR)
1、CONSTRUCTOR :构造器
2、FIELD : 域声明
3、LOCAL_VARIABLE :局部变量声明
4、METHOD : 方法声明
5、PACKAGE :包声明
6、TYPE : 类,接口,enum声明

@Retention(RetentionPolicy.RUNTIME)
1、RUNTIME 运行时
2、SOURCE 源代码
3、CLASS 类文件

@Inherited 允许类型继承父类的注解
@DOCUMENTED 在javadoc中

注解处理器,apt自动生成
Apt:在操作java源文件时而不是编译后的类,apt会检查新生成的源文件中的注解,然后所有文件一同编译

数组:是效率最高的存储和随机访问对象引用序列的方式,线性序列,元素访问非常快,但是大小被固定,生命周期内不可变

范形:擦除会移除参数类型的信息
数组操作类:
Arrays工具类
asList(T…a)
binarySearch(byte[] a, byte key)二进制搜索算法搜索指定值的指定字节数组的范围
copyOf(boolean[] original, int newLength)使用false复制指定的数组,截断或填充,以使副本具有指定的长度。
copyOfRange(boolean[] original, int from, int to)将指定数组的指定范围复制到新数组中。
deepEquals(Object[] a1, Object[] a2)如果两个指定的数组彼此非常相等,则返回true。
hashCode(boolean[] a) 根据指定数组的内容返回哈希码。
sort(byte[] a)将指定的数组按升序排序。
toString(boolean[] a)返回指定数组内容的字符串表示形式。
Generator
CountingGenerator
Generated.array()

Object类

Public constructors

Object()

Public methods

equals()
getClass()
hashCode()
notify()
notifyAll()
toString()
wait(long mills, int nanos)
wait(long mills)
wait()

Protected methods

clone() 创建并返回此对象的副本
finalize() 当垃圾收集确定没有对该对象的更多引用时,由对象上的垃圾收集器调用

状态栏改变监听
View decorView = getWindow().getDecorView();
decorView.setOnSystemUiVisibilityChangeListener
(new View.OnSystemUiVisibilityChangeListener() {
@Override
public void onSystemUiVisibilityChange(int visibility) {
// Note that system bars will only be "visible" if none of the
// LOW_PROFILE, HIDE_NAVIGATION, or FULLSCREEN flags are set.
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
// TODO: The system bars are visible. Make any desired
// adjustments to your UI, such as showing the action bar or
// other navigational controls.
} else {
// TODO: The system bars are NOT visible. Make any desired
// adjustments to your UI, such as hiding the action bar or
// other navigational controls.
}
}
});

本地广播
1、安全,发送的广播不会扩展到程序外,其他程序也不能进入程序内部
发送广播:
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context);
Intent intent = new Intent("controller.fragment");
intent.putExtra("url", avatarBean.getData());
localBroadcastManager.sendBroadcast(intent);
接收广播:
private LocalBroadcastManager localBroadcastManager;
private IntentFilter intentFilter;
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String url = intent.getStringExtra("url");
ImageLoader.getInstance().bindImage(achieve_avatar, url);
}
};

localBroadcastManager = LocalBroadcastManager.getInstance(activity);
intentFilter = new IntentFilter("controller.fragment");
localBroadcastManager.registerReceiver(receiver, intentFilter);

localBroadcastManager.unregisterReceiver(receiver);

Scrollview 自动滑动
重写@Override
protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
return 0;
}

跨进程通信4种
1、Action 对应Activity

进程2被启动的PlayActivity
<activity
android:name=".PlayActivity"
android:launchMode="singleTask"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="net.blogjava.mobile.MYACTION" />
<data android:scheme="info" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
PlayActivity内部获取其他进程传过来的消息
if (getIntent().getData() != null){
String host = getIntent().getData().getHost();
Bundle bundle = getIntent().getExtras();
String value = bundle.getString("value");
Log.i("cxd", "initView: "+host+"/"+value);
}
进程1,启动其他进程的Activity
Intent intent = new Intent("net.blogjava.mobile.MYACTION",Uri.parse("info://调用其他应用程序的Activity" ));
intent.putExtra("value","调用成功");
startActivity(intent);
要点:1、Action 使用android:name属性指定
2、访问协议:使用<data/>中的android:scheme属性来指定,如果该属性值为”abc“,则Uri为:”abc:uir主体部分”
3、getIntent().getData().getHost()获取协议主体部分,通过Bundle获取传过来的值
4、可以使用startActivityForResult()来获取返回值

2、ContentProvider,ContentResolver 应用程序之间数据共享

SQLite、SharedPreferences都是仅限于被当前所创建的应用访问,而无法使它们的数据在应用程序之间交换数据
ContentProvider只是对外暴露数据,基本的数据存储还是SQLite,SharePreferences
继承ContentProvider重写方法onCreate(),query(),insert(),delete(),update(),getType(),对应数据的增删改查,返回数据类型
前缀固定: content://
通过authorities作为进程之间的沟通Key“content://com.cxd.ourproject.provider.MyContentProvider” uri 路径前部分
XML文件中
<provider
android:authorities="com.cxd.ourproject.provider.MyContentProvider"
android:name=".provider.MyContentProvider"
android:exported="true"/>

3、广播验证不通过
发送:
sendBroadcast(new Intent(“net.blog.broadcast.demo”));
接收:
onReceive(Content,content,Intent intent){
if(“net.blog.broadcast.demo”.equals(intent.getAction())){
Bundle bundle = intent.getExtras();
}
}
<receiver android:name="MyReceiver" >
<intent-filter>
<action android:name="net.blog.broadcast.demo" />
</intent-filter>
</receiver>
关闭状态依然可以接受广播

4、AIDL服务
所有将对象分解成原语的工作,操作系统可以识别这些原语并将它们编组到各进程中,以执行 IPC。采用 Messenger 的方法实际上是以 AIDL 作为其底层结构。Messenger 会在单一线程中创建包含所有客户端请求的队列,以便服务一次接收一个请求。如果您想让服务同时处理多个请求,则可直接使用 AIDL。在此情况下,您的服务必须具备多线程处理能力,并采用线程安全式设计。大多数应用“都不会”使用 AIDL 来创建绑定服务,因为它可能要求具备多线程处理能力,并可能导致实现的复杂性增加。因此,AIDL 并不适合大多数应用。

5、Messenger 让接口跨不同的进程工作,则可使用 Messenger 为服务创建接口。服务可以这种方式定义对应于不同类型 Message 对象的 Handler。此 Handler 是 Messenger 的基础,后者随后可与客户端分享一个 IBinder,从而让客户端能利用 Message 对象向服务发送命令。此外,客户端还可定义自有 Messenger,以便服务回传消息。执行进程间通信 (IPC) 的最简单方法,因为 Messenger 会在单一线程中创建包含所有请求的队列,这样您就不必对服务进行线程安全设计。
接口如何处理重复请求?RxAndroid 防抖动

Handler
postAtFrontOfQueue(Runnable r); 异步优先插入表头发送
sendMessageAtFrontOfQueue(Message msg);同步优先插入表头发送
postDelayed(Runnable r, long delayMillis);异步延时发送
postAtTime(Runnable r, long uptimeMillis);异步定时发送
queue.enqueueMessage(msg, uptimeMillis);
sendMessage()插入消息
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}

    synchronized (this) {
        if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, e.getMessage(), e);
            msg.recycle();
            return false;
        }

        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        if (p == null || when == 0 || when < p.when) {
            // New head, wake up the event queue if blocked.
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            // Inserted within the middle of the queue.  Usually we don't have to wake
            // up the event queue unless there is a barrier at the head of the queue
            // and the message is the earliest asynchronous message in the queue.
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }

        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

Loop消息循环处理
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;

    // Make sure the identity of this thread is that of the local process,
    // and keep track of what that identity token actually is.
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();

    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }

        // This must be in a local variable, in case a UI event sets the logger
        final Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " +
                    msg.callback + ": " + msg.what);
        }

        final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;

        final long traceTag = me.mTraceTag;
        if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
            Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
        }
        final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
        final long end;
        try {
            msg.target.dispatchMessage(msg);//处理消息
            end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        if (slowDispatchThresholdMs > 0) {
            final long time = end - start;
            if (time > slowDispatchThresholdMs) {
                Slog.w(TAG, "Dispatch took " + time + "ms on "
                        + Thread.currentThread().getName() + ", h=" +
                        msg.target + " cb=" + msg.callback + " msg=" + msg.what);
            }
        }

        if (logging != null) {
            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
        }

        // Make sure that during the course of dispatching the
        // identity of the thread wasn't corrupted.
        final long newIdent = Binder.clearCallingIdentity();
        if (ident != newIdent) {
            Log.wtf(TAG, "Thread identity changed from 0x"
                    + Long.toHexString(ident) + " to 0x"
                    + Long.toHexString(newIdent) + " while dispatching to "
                    + msg.target.getClass().getName() + " "
                    + msg.callback + " what=" + msg.what);
        }

        msg.recycleUnchecked();//回收msg
    }
}

子线程使用Handler
Looper.prepare();
looper = Looper.myLooper();
mHandler = new Handler(looper, new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Log.i("cxd", "handleMessage: "+msg.what);
return false;
}
});
mHandler.sendEmptyMessage(999999);
Looper.loop();
或者
mHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Log.i("cxd", "handleMessage: "+msg.what);
return false;
}
});
mHandler.sendEmptyMessage(999999);

View的绘制流程 [DecorView.java,PhoneWindow.java,ViewRootImpl.java]
ViewRootImpl.java
scheduleTraversals()->doTraversal()->performTraversals()->performMeasure()->mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
View.java
measure(int widthMeasureSpec, int heightMeasureSpec)->layout(int l, int t, int r, int b)->draw(Canvas canvas)

measure():测量
//调用onMeasure()进行测量
onMeasure(widthMeasureSpec, heightMeasureSpec);
//getDefaultSize(int size, int measureSpec);//根据specMode 确定大小
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
//设置测量尺寸,无需对边界[padding]进行处理
setMeasuredDimensionRaw(measuredWidth, measuredHeight);
private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) {
mMeasuredWidth = measuredWidth;
mMeasuredHeight = measuredHeight;
mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;}
layout():布置
boolean changed = isLayoutModeOptical(mParent) ?setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
//setOpticalFrame() 父布局可见边界,需要处理父布局和子布局的 padding值
if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
onLayout(changed, l, t, r, b);
. . .
//根据返回值及时通知 onLayout(changed, l, t, r, b); [观察者模式] 方法会在自定义view内部重写
RenderNode mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
//RenderNode持有View属性

android程序启动--->Activity加载--->View的绘制
ActivityThread ViewManager WindowManagerImpl WindowManagerGlobal ViewRootImpl
handleResumeActivity() addView(decor, l) addView(decor,l) addView()->root.setView() setView()->requestLayout()->scheduleTraversals()->doTraversal()->performTraversal()->开始绘制View
addView():保存 DecorView,ViewRootimpl,LayoutParams 等;

ViewGroup.java
dispatchDraw(Canvas canvas);

View的刷新
View.java
invalidate()->invalidate(boolean invalidateCache)->invalidateInternal()->p.invalidateChild(this, damage)

ViewParent.java ViewRootImpl.java
invalidateChild() invalidateChild()->invalidateChildInParent()->invalidateRectOnScreen(dirty)->scheduleTraversals()

Java 自动拆装箱 Integer <=> int 对象和基本数据类型之间的转化,会隐试的创建对象,避免在循环中使用创建大量的对象

抛异常:
throw new IllegalStateException("invalid orientation");

数据结构:Queue,Set,List,SortedSet,SortedMap.HashSet,TreeSet,ArrayList,LinkedList,Vector, SparseArray

Queue队列,继承Collection,和list和set同级
队列通常(但不一定)以FIFO(先进先出)方式对元素进行排序。例外的是优先级队列,它根据提供的比较器对元素进行排序,或者元素的自然排序,以及LIFO队列(或堆栈),它们对元素LIFO(后进先出)进行排序。无论使用什么顺序,队列的头部都是通过调用remove()或 删除的元素poll()。在FIFO队列中,所有新元素都插入队列的尾部。其他类型的队列可能使用不同的放置规则。每个Queue实现都必须指定其排序属性。

Deque 双端队列:线性集合,支持两端插入和移除元素。
Stack 堆:Stack类表示对象的后进先出(LIFO)堆栈。
Vector向量:一个可增长的对象数组,就像一个数组,包含下表,但是它的大小可以根据需要进行增长和收缩

内部代码块:有边界的执行一段代码,更好的管理元素的生命周期
1、普通代码块-也就是正常的方法
public void test(){
}
2、静态代码块:随着类的加载而被执行,给类进行初始化
static{
}
3、同步代码块
synchronized(this){
}
4、构造代码块:特定对象的初始化
{
}
1、父类>子类
2、静态代码块 > 构造代码块 > 构造函数
3、父类和子类的方法会先执行父类的,但是不是先执行完所有父类的,而是父类>子类,父类>子类 ···

Bitmap图片占用的内存大小,例:图片的大小 480x800
Bitmap.Config.ALPHA_8:没有色彩,只有透明度A-8,共8位,1字节
Bitmap.Config.RGB_565:A-4,R-4,G-4,B-4,共4+4+4+4=16位。2字节
Bitmap.Config.ARGB_4444:没有透明度,R-5,G-6,B-5,共5+6+5=16位。2字节
Bitmap.Config.ARGB_8888:A-8,R-8,G-8,B-8,共8+8+8+8=32位。4字节
例如:图片设置为:Bitmap.Config.ARGB_8888,则大小为
4808004/1024 = 1500kb 约等于1.46M

虚拟机JVM,DVM,ART区别
Dalvik虚拟机( Dalvik Virtual Machine ):
架构不同,DVM是基于寄存器的,基于寄存器的指令会比基于栈的指令要大,但是由于指令数量的减少
字节码不同;DVM会用dx工具将所有的.class文件转换为一个.dex文件:.java文件 –>.class文件-> .dex文件

JVM虚拟机:
基于栈则意味着需要去栈中读写数据,所需的指令会更多,这样会导致速度慢
Java类会被编译成一个或多个.class文件,打包成jar文件:.java文件 -> .class文件 -> .jar文件

ART(Android Runtime):Android 4.4发布的,用来替换Dalvik虚拟机,Android 5.0时,默认采用ART,DVM从此退出历史舞台
ART与DVM的区别
DVM中的应用每次运行时,字节码都需要通过即时编译器(JIT,just in time)转换为机器码,这会使得应用的运行效率降低。 而ART中,系统在安装应用时会进行一次预编译(AOT,ahead of time),将字节码预先编译成机器码并存储在本地
ART占用空间比Dalvik大(字节码变为机器码之后,可能会增加10%-20%),这就是“空间换时间大法”
预编译也可以明显改善电池续航,因为应用程序每次运行时不用重复编译了,从而减少了 CPU 的使用频率,降低了能耗

标签流容器-流式布局

优化工具
Android Lint 代码扫描工具 Analyze > Inspect Code
帮助发现并纠正代码结构质量的问题,正确性、安全性、性能、易用性、便利性和国际化方面是否需要优化改进
Android Device Monitor
Traceview,Hierarchy Viewer
Traceview
时间轴表格:每个线程的执行时间,细线的子项
配置表格:表示调用父方法和子方法所花费的时间,当点击方法的时候,可以查看调用的方法

Systrace
https://zhuanlan.zhihu.com/p/27331842
https://zhuanlan.zhihu.com/p/27535205
灰色:正在休眠。
蓝色:可运行(它可以运行,但是调度程序尚未选择让它运行)。
绿色:正在运行(调度程序认为它正在运行)。
红色:不可中断休眠(通常在内核中处于休眠锁定状态)。可以指示 I/O 负载,在调试性能问题时非常有用。
橙色:由于 I/O 负载而不可中断休眠。
使用命令:python systrace.py --time=5 -o mynewtrace.html sched gfx view wm
./systrace.py -t 10 sched freq idle am wm gfx view \ binder_driver hal dalvik camera input res
移动文件命令:sudo mv mynewtrace.html /Users/admin/Downloads/mynewtrace.html
创建文件:touch /Users/admin/Downloads/mynewtrace.html 保存退出:shift+ZZ

Layout Inspector 布局检查器

Android FindViewById support 快速的吧XML文件导入

Hierarchy Viewer 布局层次结构查看器
Mac 中配置使用
进入用户目录页面
cd ~
编辑环境变量文件
vim .bash_profile
加入

Hierarchy Viewer Variable

export ANDROID_HVPROTO=ddm
:WQ
source .bash_profile
重启 Android studio
三个彩色点的含义:
左侧点:渲染管道的绘制过程
中间点:代表布局阶段
右边点:代表执行阶段
彩色点与渲染管道的关系
绿色:表示视图呈现的速度比其他视图中的至少一半快。
黄色:表示视图渲染速度快于速度最慢的一半视图。
红色:表示视图是最慢的一半视图之一。

层次结构查看器测量每个节点相对于兄弟视图的性能,因此配置文件中总是有红色节点 - 除非所有视图执行相同 - 并且它并不一定意味着红色节点表现不佳(只是它是最慢的视图)在本地视图组中)
在应用程序性能出乎意料地降低的任何情况下,红色节点都是潜在的问题。在相对设置中,始终存在最慢的节点; 只需确保它是您期望的节点
如果具有20多个视图的树中的叶节点具有红色绘制阶段,则这是一个问题。检查您的onDraw()方法中是否存在不应存在的代码。

OpenGL ES Trace Options

Java 锁
公平锁是指多个线程按照申请锁的顺序来获取锁。
非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。
对于Java ReentrantLock而言,通过构造函数指定该锁是否是公平锁,默认是非公平锁。非公平锁的优点在于吞吐量比公平锁大。
对于Synchronized而言,也是一种非公平锁。由于其并不像ReentrantLock是通过AQS的来实现线程调度,所以并没有任何办法使其变成公平锁
可重入锁是指同步方法内部可以有同步块,即外部的锁进入内部后可以直接获取外部的锁 ReentrantLock和Synchronized都是可重入锁
自旋锁 采用循环的方式去尝试获取锁,线程不会阻塞

相关文章

网友评论

      本文标题:笔记合集

      本文链接:https://www.haomeiwen.com/subject/dciriqtx.html