1. hexo环境安装
在macOS上安装homebrew
- 命令
1
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
- 官网:https://brew.sh/
- 命令
通过homobrew安装node.js
- 命令
1
brew install node
- 参考:https://formulae.brew.sh/formula/node
- 命令
在macOS上安装homebrew
1 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" |
通过homobrew安装node.js
1 | brew install node |
无论通过Handler的哪个post函数发消息,最终都会来到sendMessageAtTime,基于android.os.SystemClock#uptimeMillis时间,最终以SystemClock.uptimeMillis()+delayMillis的结果作为入队列和消息执行的基准。
消息入队列是通过MessageQueue#enqueueMessage函数,when表示消息执行的时间,通过下方源码可知如果当前消息队列为空,或者when等于0,或者新消息的when小于头消息的when,则直接将新消息替换为头消息。否则按照when的值将消息插入到队列的合适位置中。
1 | boolean enqueueMessage(Message msg, long when) { |
即消息队列,以单链表的方式存储和管理着Message。在Andrid 2.3以前,只有Java世界的居民有资格向MessageQueue中添加消息以驱动Java世界的正常运转,但从Android 2.3开始,MessageQueue的核心部分下移至Native层,让Native世界的居民也能利用消息循环来处理他们所在世界的事情。因此MessageQueue心系Native和Java两个世界,担任着两个世界沟通的桥梁。下面即将从“存消息”和“取消息”两个动作详细分析Native和Java是怎么交流合作的。不过开始之前我们先扫清楚一些MessageQueue的细节知识点。
Handler的主要作用是将一个任务切换到某个指定的线程中去执行,常见的就是在子线程中发消息通知主线程更新UI。通过Handler发送消息到处理消息的过程,从应用层来看很简单(但其实底层有完善的机制作为支撑),所以我们就从sendMessage入手开始分析。
无论Handler通过post还是sendMessage发消息,最终都会来到sendMessageAtTime,接着调用MessageQueue的enqueueMessage将Message消息按照执行时间入队列。另一边Looper的loop是个死循环,会不停的问MessageQueue要新消息,等拿到消息后会通过dispatchMessage进行分发,此时就将消息切换到了创建Looper所在的线程中执行,最后来到Handler的handleMessage中。
技术栈 : LifeCycle + LiveData + ViewModel + Coroutine + Navigation + Kotlin
以拿取最新照片列表为例
这是JVM系列的第一篇,所以简单介绍下该系列的大纲,如下图所示:
该系列文章绝大部分的素材来源是《深入理解Java虚拟机2》这本书,整个系列可以看做是学习笔记,自己是先通读了一遍该书,然后整理脑图,按照上面的大纲再逐篇整理。主要目的是理解虚拟机中一些高深又晦涩的概念,以及虚拟机底层运行的一些基本“常识”,打好这块的基础,以便后续更容易掌握Android平台上的热修复、插件化以及Hook技术等的一些原理。
JVM系列之对象-Part1创建
JVM系列之对象-Part2布局
JVM系列之对象-Part3定位
JVM系列之对象-Part4是否还活着?
JVM系列之GC-Part1收集算法
JVM系列之GC-Part2收集器
JVM系列之GC-Part3GC分类
JVM系列之GC-Part4内存分配与回收策略
JVM系列之类加载-Part1类文件结构
JVM系列之类加载-Part2类加载机制
JVM系列之类加载-Part3字节码执行引擎
JVM系列之高效并发-Part1内存模型
JVM系列之高效并发-Part2Java与线程
JVM系列之高效并发-Part3线程安全与锁优化
描述 | 命令 |
---|---|
清除屏幕 | clear |
重新初始化终端 | reset |
查看当前目录 | pwd |
将当前目录下的子文件&子目录平铺在控制台 | ls ls -ll |
往控制台输出信息 | echo 'test content' echo 'test content' > test.txt |
在当前目录下新建一个文件 | touch [文件名] |
查看对应文件的内容 | cat [文件的url] |
编辑文件 | vim [文件的url] - 按i键进入插入模式 - 按esc键进行命令执行 * q! 强制退出(不保存) * wq 保存退出 * set nu 设置行号 |
新建文件夹 | mkdir [文件目录] |
将对应目录下的子孙文件&子孙目录平铺在控制台 | find [目录名] |
将对应目录下的文件平铺在控制台 | find [目录名] -typef |
删除文件 | rm [文件名] |
删除文件夹 | rm -r [文件目录] |
重命名 | mv [源文件] [重命名文件] |
查看历史命令 | history |
退出 | exit |
描述 | 命令 |
---|---|
在当前目录新建一个git代码库 | git init |
新建一个目录,将其初始化为git代码库 | git init [project-name] |
下载一个项目和它到整个代码历史 | git clone [url] |
描述 | 命令 |
---|---|
显示当前的git配置 | git config --list |
编辑git配置文件 | git config -e [--global] |
设置提交代码时的用户信息 | git config [--global] user.name "[name]" git config [--global] user.email "[email address]" |
描述 | 命令 |
---|---|
添加当前目录的所有文件到暂存区 | git add . |
删除工作区文件,并且将这次删除放入暂存区 | git rm [file1] [file2] … |
停止追踪指定文件,但该文件会保留在工作区 | git rm --cached [file1] |
改名文件,并且将这个改名放入暂存区 | git mv [file-original] [file-renamed] |
广告模块引入了很多三方sdk,这里的问题体现在google的admob上,期望是将admob升级到18.3.0版本,结果主工程中由于引入了firebase,具体来讲就是admob和firebase都引入了google的基础服务gms,但版本没统一导致了Duplicate class的错误。
期望将admob升级到18.3.0版本
1 | com.google.android.gms:play-services-ads:18.3.0 |
这个版本里面使用了
1 | com.google.android.gms:play-services-measurement-base:17.1.0 |
我们项目中还使用了两个google的服务框架,分别如下(已是最高版本了):
1 | com.google.android.gms:play-services-gcm:17.0.0 |
这两个包里面使用了com.google.android.gms:play-services-measurement-base:17.0.0,导致工程现在编译时报错:
1 | Duplicate class com.google.android.gms.internal.measurement.zzio found in modules classes.jar (com.google.android.gms:play-services-measurement-base:17.1.0) and classes.jar (com.google.android.gms:play-services-measurement:17.0.0) |
解决方法:将admob18.3.0降到18.0.0,因为这个版本里面是play-services-measurement-base:17.0.0
成功缓存2个mtg广告,但显示第2个时失败报错:is not ready(can’t show because load fail),报错的详细日志:
1 | onShowFailure[mintegral_interstitial_ad] unitId is xxx, errorMessage is mtg interstitial video ad is not ready, errorCode is -2020007。 |
抓包+日志定位确定isNotReady有两种可能,①广告素材视频没下载完 ②广告间隔时间太长,offer过期。