检查性能

由于负责系统稳定性和性能监控的同事离职了,所以领导希望我来与剩下的同事一起负责这个事,那没法了,学吧~

使用tcpdump抓包

最近搞PKI,遇到问题经常不明所以,后来找同事帮忙抓包才定位到原因,瞬间感觉学习抓包的重要。

OkHttp的SSL握手溯源

最近研究PKI,想实现私钥不出TEE这个需求,需要确认okhttp中SSL认证的实现,结果说看看源码吧,让我好一顿找阿,特此记录一下过程。

ubuntu22.04上不能使用adb

今天重新安装了ubuntu20.04LTS,安装了IDEA后发现不能用adb连接车机,报错: 1 no permissions (missing udev rules? user is in the plugdev group) 在这里找到了解决办法,感

手把手教你自定义HAL层

最近工作要求,涉及到了HAL层开发,让我这个刚刚从上层转底层的小白无所适从,根本不知道怎么入手,从网上搜集了大堆的文章,照着做没有一个能成,前前后后一个月了,今天终于成功了,特此记录一下,希望能帮到其他像我一样高转低的同行吧。

Ubuntu无法进入桌面

今天又弄了一下fcitx5,并且配置了go环境变量,然后重启了一下电脑,到了登录页面,输入密码,竟然又退到登录页面,无论如何也进不去桌面。

vscode+gradle+kotlin

最近事多,整天瞎忙,都是沟通、开会、填表格和填坑,今天想休息休息,打算有空再写写后端服务,把自己的网盘和图床先弄好。思来想去,自己一个人的项目,时间少,所以尽量还是要方便维护,那么就不要用JAVA了,罗里吧嗦的,可惜Dart这边没什么好的框架,要不然一个语言全站了,最终还是选择了kotlin,但是又不想用idea,于是我瞄向了vscode…

Logcat

今天是我过得非常不爽的一天,因为今天说了『我不会』『我不懂』『我看不明白』,从哥2017年自学安卓到现在,从一点不会到基本不百度,我还没说过这些话。今天真是太刺激了,从上层转底层真的这么费劲吗,还是说年纪大了学不动了?都不是,是我一开始学系统底层还没找到要领,同时又事物缠身,分身无术。仔细想想还是先从常用工具入手,别他妈让我抓个log都这么费劲。

属性动画

前段时间面试滴滴的时候,跟面试官聊了一下属性动画,上来就问:你看过源码吗?我说没看过,然后他表示属性动画并不是真正的改变view的属性,原因是一个例子:在constraintlayout中,通过相互约束定义纵向的一列view,然后通过属性动画,让第一个view平移,你认为下面的view是否会跟着动?他的结论是从系统设计上,谷歌就不可能允许跟着动的情况,因为我们指定动画的目标就是第一个view,所以平移操作也应该局限在第一个view中,而不应该影响其他的view。我当时觉得他太牛逼了,能从源码想到设计思想,后面我还靠他这个结论去忽悠过其他人,而其他人也觉得我很牛逼,哈哈哈。今天心血来潮,自己写个demo测一下,通过属性动画去改view的x位置,结果下面的view真的没有跟着动,可是接下来的表现却让我瞠目结舌。

登录安全

最近打算自己开发独立App,那么首先考虑的就是账号密码的网络传输安全,也就是所谓的登录安全。

冒泡法

冒泡法可以用来找队列中的最大值,也可以通过多次冒泡对集合进行排序。

IntentService

面试题:场景需要在子线程中依次执行多个子任务,要保证任务时序,所有子任务执行完毕该线程自动退出,怎么实现?

Android系统启动流程

按下电源键,首先从加载并运行BootLoader; BootLoader拉起linux内核; linux内核启动后会加载init.rc文件,并启

Hugo的图片处理

用了Hugo这一段时间,一直搞不明白图片怎么存放比较好,也一直弄不清楚Leaf BundleBranch Bundle有什么区别,今天有点时间,终于搞清楚了,并且图片也成功在Github-pages上显示出来了,特此记录一下吧!

树莓派安装docker-compose

过年这几天鼓捣一下树莓派,结果各种麻烦,尤其是安装docker-compose,明明docker安装很顺畅,为啥这货就这么麻烦呢?

树莓派挂载移动硬盘

过年这几天鼓捣一下树莓派,结果各种麻烦。。。尤其是在挂载exFat格式的移动硬盘的时候,明明临时挂载是没有问题的,但是一旦做了开机自动挂载的话,就连系统都启动不了了。经过不懈的百度,终于解决了问题,特此记录一下。

DiskLruCache

之前已经了解过,OkHttp默认添加CacheInterceptor来处理缓存,而后者是依靠DiskLruCache来实现硬盘缓存读写,所以我先去看了一下Android内置的LruCache原理,是依靠java的LinkedHashMap的LRU排序算法实现的,最后我准备详细看看DiskLruCache是怎么基于硬盘缓存实现LRU的。

LruCache

LRU这个算法就是把最近一次使用时间离现在时间最远的数据删除掉,而实现LruCache将会频繁的执行插入、删除等操作,我们就会想到使用LinkedList,但是我们又要基于Key-Value来保存数据,这个时候我们就会想起HashMap,但是HashMap不能像linkedList那样保留数据的插入顺序,如果要使用HashMap的话可以使用它的一个子类LinkedHashMap。

BridgeInterceptor

RealCall中的传值 1 2 3 ... interceptors.add(new BridgeInterceptor(client.cookieJar())); ... RealCall在创建这个拦截器的时候只传递了一个cookieJar。 作用 这个类的注释如下: Bridges from application code to

CacheInterceptor

RealCall中的传值 1 2 3 ... interceptors.add(new CacheInterceptor(client.internalCache())); ... RealCall在创建这个拦截器的时候只传递了一个cookieJar。 作用 这个类的注释如下: Serves requests from the cache

ConnectInterceptor与StreamAllocation

ConnectInterceptor 连接拦截器 作为第二个实际生效的拦截器,ConnectInterceptor 的代码非常简单。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

RetryAndFollowUpInterceptor

RealCall中的传值 1 2 3 4 5 6 private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) { this.client = client; this.originalRequest = originalRequest; this.forWebSocket = forWebSocket; this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket); } RealCall初始化时,会创建这个RetryAndFol

StreamAllocation

初始化调用 1 2 3 4 5 6 7 8 9 10 public final class RetryAndFollowUpInterceptor implements Interceptor { ... @Override public Response intercept(Chain chain) throws IOException { ... // 初始化数据流分配器 StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),createAddress(request.url()), call, eventListener, callStackTrace); StreamAllocation是在Re

Crash监控

Crash(应用崩溃)是由于代码异常而导致 App 非正常退出,导致应用程序无法继续使用,所有工作都停止的现象。发生 Crash 后需要重新启动应用(有些情况会自动重启),而且不管应用在开发阶段做得多么优秀,也无法避免 Crash 发生,特别是在 Android 系统中,系统碎片化严重、各 ROM 之间的差异,甚至系统Bug,都可能会导致Crash的发生。在 Android 应用中发生的 Crash 有两种类型,Java 层的 Crash 和 Native 层 Crash。这两种Crash 的监控和获取堆栈信息有所不同。

搭建pub私服及上传package

事情的起因是,在工作项目中,一开始只有我一个人研发,为了方便,我封装了一个网络访问层。但是随着团队规模的拓展,陆续加入了其他人,时间紧项目重,所以后续的伙伴没有时间来问我这个框架怎么使用,所以他们直接上手改了我的封装!但是后期架构要求加入oauth2.0机制,所以需要全局处理token的有效认证,并且自动刷新token。为了满足这一需求,我需要重新编写网络层,同时为了避免伙伴修改我的抽象,我想到了本文的主题——搭建个pub.dev私服吧!

About

关于我

linux目录结构

/bin: bin 是 Binaries (二进制文件) 的缩写, 这个目录存放着最经常使用的命令。 /boot: 这里存放的是启动 Linux 时使用的一些核心文件,包括一些连接文件以

Android自定义ViewGroup

自定义ViewGroup与自定义View不同,一般不需要重写onDraw,而是需要重写onLayout。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

ClassLoader学习.md

用途 读取.class文件的字节码并加载成内存形式的类对象。 边解释边执行 JVM并不是一次性加载全部的类,而是需要用到才会去加载。比如加载了类,

Java IO

字节流 标准用法: 1 2 3 4 5 6 7 8 9 10 11 12 DataOutputStream out = new DataOutputStream(//负责数据类型 new BufferedOutputStream

JVM内存结构

JDK、JVM、Jre之间的关系 JVM 只负责把.class文件翻译成操作系统可识别的语句。 Jre 提供Java程序的运行环境 JDK 提供工具 JVM的三大区域

FlutterJsonBeanFactory原理

创建类 1 2 3 4 5 class StudentEntity with JsonConvert<StudentEntity> { @JSONField(name: "name") late String name; } 使用 1 2 3 4 5 6 7 8 9 10 11 //序列化 Map<String, dynamic> json = StudentEntity(name: "走两步试试").toJson(); //

Apk打包和安装流程

.apk文件的组成 apk文件其实就是个压缩包,里面包含: classes.dex编译后的代码文件,安卓的可执行文件 resource.arsc 编译后的资源文件(raw)

Apk反编译流程

.apk文件的组成 apk文件其实就是个压缩包,里面包含: classes.dex文件 resource 打包流程 aapt编译打包资源文件,生成R.java。 编译

从ReentrantLock看AQS原理

ReentrantLock的使用 1 2 3 4 5 6 ReentrantLock lock = new ReentrantLock(); try { lock.lock(); } finally { lock.unlock(); } AQS原理概述 1 private volatile int state; 维护了一个int state作为状态机,CLH队

对SpringGateway+Security+OAuth2.0的认识

RV是什么 1 2 3 public class RecyclerView extends ViewGroup implements ScrollingView{ ... } 就是个ViewGroup,并且遵循了ScrollingView接口,所以支持滑动。 那么,既然是VG,那么我

SharedPreferences解读

SharedPreferences解读 SharedPreferences是我们平时常用的简单储存工具。优点就是用起来方便,而且线程安全,甚至

Android内存泄露专题

原因 短生命周期对象持有长生命周期对象的强引用,造成短生命周期对象在不需要使用时不能被回收。 静态变量导致 1 2 3 4 5 6 7 8 9 10 11 12 13 public class MainActivity extends AppCompatActivity {

研读自贸港政策

中共中央 国务院印发海南自由贸易港建设总体方案 中共中央 国务院印发《海南自由贸易港建设总体方案》 新华社北京6月1日电 中共中央、国务院印发了《海南

View的前前后后

setContentView 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 @Override public void setContentView(View v) { ensureSubDecor(); ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content); contentParent.removeAllViews(); contentParent.addView(v); mAppCompatWindowCallback.getWrapped().onContentChanged(); } @Override public void setContentView(int resId) { ensureSubDecor(); ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content); contentParent.removeAllViews(); LayoutInflater.from(mContext).inflate(resId, contentParent); mAppCompatWindowCallback.getWrapped().onContentChanged(); } @Override public void setContentView(View v, ViewGroup.LayoutParams lp) { ensureSubDecor(); ViewGroup contentParent =

View的工作原理

三大流程 measure 用来测量View的宽高; layout 用来确定View在父容器中的放置位置; draw 负责绘制。 在ActivityThread中,当Activity创

View事件体系

位置参数 主要位置参数 View的位置主要由它的四个顶点(相对父容器)来决定: getLeft() getTop() getRight() getBottom() 用于移动的参数 x/y View左上角相对父容器的坐标; translationX/translationY View

Java线程安全

并发三大特性 原子性 操作要么成功,要么失败,中途不可被中断。 可见性 共享变量的变更立即可见。 有序性 程序执行依照代码的先后顺序来执行。 JMM模型 J

Java线程

状态 new 新建 Runnable 可运行 Blocaked 阻塞 Waiting 等待 Timed waiting 计时等待 Terminated 终止 核心方法 void start()启动 void run()调用内部Runnable的run()。 public static void sleep(long mil

Java线程池

阻塞队列 BlockingQueue 生产者&消费者模型 队列的意义: 生产者与消费者解耦 平衡生产与消费速度 可应用于消息中心 默认实现: 队列 界限 特点 ArrayBlockingQueue 有 一个由数组结构

HandlerThread解读

用法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 // 步骤1:创建HandlerThread实例对象 // 传入参数 = 线程名字,作用 = 标记该

AsyncTask解读

使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 public class MainActivity extends

ThreadLocal解读

从Set方法入手 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); } ThreadLocalMap getMap(Thread t) { return t.threadLocals; } 从这里可

Parcelable解读

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 class Data implements Parcelable

Binder解析

Binder是什么 进程间通讯机制 系统驱动 Binder.java跨进程能力 为何要多进程 申请更多内存 安全性隔离 Binder的优势 机制 性能 特点 安全

Android中Message的一辈子

初始化 1 2 3 Looper.prepare(); Handler mHandler = new Handler(Looper.myLooper()); Looper.loop(); Looper.prepare()源码: 1 2 3 4 5 6 private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); } Looper的

MessageQueue解读

回顾 handler发送消息: 1 2 3 4 5 6 7 8 9 10 private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, long uptimeMillis) { msg.target = this; msg.workSourceUid = ThreadLocalWorkSource.getUid(); if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis);//最后调用的是

Handler的原理

Handler的原理 内存共享方案,并且通过加锁避免线程之间的相互干扰。 为何不用wait/notify 答案: 通过阅读main()函数,会发现主

Handler解读

构造方法 1 2 3 4 5 6 public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; } 构造方法中可以看到,handler持有Looper的MessageQueu

Message解读

创建 我们都知道创建Message的时候有两种方式: 构造方法创建(不推荐)。 Message.obtain();(推荐). 为了防止OOM,我们一

Looper解读

类图 prepare 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public static void prepare() { prepare(true); } private static void prepare(boolean quitAllowed) { // 如果线程已经有了Looper就会报错 if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); }

GraphQL-Java(零)从SpringBoot服务端开始

引入依赖 1 2 3 4 5 6 7 dependencies { implementation 'com.graphql-java:graphql-java:14.1' // NEW implementation 'com.graphql-java:graphql-java-spring-boot-starter-webmvc:1.0' // NEW implementation 'com.google.guava:guava:26.0-jre' // NEW implementation 'org.springframework.boot:spring-boot-starter-web' testImplementation 'org.springframework.boot:spring-boot-starter-test' } 定义Schema 在src/main/resources中创建schema.gra

GraphQl-Java(三)Execution

Queries 如果想要在schema里跑个查询,需要用对应的参数创建一个新的GraphQL object,然后执行execute()。该方法会返回一个Ex

GraphQl-Java(一)Schema

引入依赖 版本列表 Gradle 1 2 3 4 5 6 7 repositories { mavenCentral() } dependencies { compile 'com.graphql-java:graphql-java:15.0' } Maven 1 2 3 4 5 <dependency> <groupId>com.graphql-java</groupId> <artifactId>graphql-java</artifactId> <version>15.0</version> </dependency> Schema——大纲 创建一个Schema有两种方式: 推荐SDL(sp

HashMap速记

版本差异 版本 特点 JDK1.7 数组+单向链 JDK1.8 数组+单向链+红黑树 jdk1.7中,数组是HashMap的主体,而链表是为了解决哈希冲突而存在的。当链表过长

Java的GC机制

由于我对GC的理解一直不好,总是记不住,所以本篇博客完全撸了一颗苹果的博客,十分感谢原作者! 什么是垃圾 Java进程运行后,如果某个类型(方法

Java趣味题

java是引用传递还是值传递? 结论,Java就是值传递,只不过在传递引用类型的时候,会把对象的引用地址当作值来传递。 首先声明一个引用类型: 1

对SpringGateway+Security+OAuth2.0的认识

趁着下载Keycloak的时候,记录一下自己对SpringCloud中的用户鉴权系统的认识。 OAuth2.0 四种授权模式 模式 refresh_token 用途 authorization_code true 允许用户通过第三方应

CAS原理和问题

死锁 死锁是指多个的线程在执行过程中,由于竞争资源或者由于批次通信而造成的一种阻塞现象。若无外力作用,他们都将无法推进下去。 悲观锁与乐观锁 悲观

synchornized关键字

反编译指令 1 javap -v XXX.class 监视器对象Monitor 原理 当synchronized加载代码块上,JVM会执行两条指令: 加锁:MonitorEnter 解

序列化

序列化:Object => String 反序列化:String => Object 核心原理 序列化是把对象转成字符串的过程,那么转换之后的字符串,就保存在文件中,所以Java