前言

Kotlin 中的协程是无栈协程(话说 Kotlin 能实现有栈线程吗🤔),网上很多文章都说无栈协程一般都是通过状态机实现的,刚开始听到这个状态机的时候觉得有点玄乎,今天反编译一下 Kotlin 代码,看看这个状态机到底是个什么鬼。

反编译 Kotlin

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
fun main() {
runBlocking {
val result = fun1()
println(result)
}
}

suspend fun fun1(): Int {
var localInt = 0

localInt += fun2()

localInt += fun3()

return localInt
}

suspend fun fun2(): Int {
return 1
}


suspend fun fun3(): Int {
delay(1000)
return 1
}
阅读全文 »

什么是跨源请求?

先看看什么是同源 URL:

如果两个 URL 的协议端口(如果有指定的话)和主机都相同的话,则这两个 URL 是同源的。这个方案也被称为“协议/主机/端口元组”,或者直接是“元组”。(“元组”是指一组项目构成的整体,具有双重/三重/四重/五重等通用形式。)

当网站的 URL 和网站发出请求的 URL 是非同源的,我们便说这个请求是跨源请求。

请求为什么不能跨源?

假如 A 是银行网站,你在 A 网站上进行了登录,A 网站将 token 保存在浏览器的 cookies 中。接下来你收到了一封钓鱼网站 B 发来的邮件,并点开了其中的连接,然后 B 网站在你不知情的情况下调用 A 网站的转账接口,将你在这家银行的钱全转进他的帐户里。由于转账接口的域名是 A 网站的,因此这个请求会把浏览器保存的 A 网站 cookies 也一并带上去,于是该请求就能顺利通过 A 网站服务器的身份验证,然后你💰就没了 : (。

阅读全文 »

前言

心血来潮打开了尘封已久的 switch,发现软件更新实在太慢,上网找了几种常用的加速方法,各有优劣,但最终都被 pass:

  • 更改 DNS 服务器,缺点是网速提升有限,大概在 34 Mbps 左右,大概提升 1 ~ 2 Mbps 左右 ,相对 switch 几百 M 几个 G 的游戏来说,依然是龟速。唯一的好处是不用借助其他设备。
  • 买加速器。对于喜欢折腾的人来说,花钱永远是最后的选择,况且我自己有梯子,干嘛花这个冤枉钱。
  • 把电脑上的代理通过局域网分享给 switch,然而发现网速的提升依然不高,虽然后来发现是 USB 无线网卡的问题,但不管怎样,电脑一直保持开机状态,就是为了给 swtich 做代理,总感觉不太优雅。

我心想要是能在路由器上跑代理就好了,不过现在的路由器不支持装插件,而且是公用的,不太适合去折腾。这时候突然想起了我还有个同样在吃灰的树莓派,如果能把这台树莓派变成一台软路由,再在这个软路由上跑代理,岂不美哉?于是上网搜索 “如何在树莓派上装软路由”,不出所料,搜出了一堆教程。一番学习后,最后选择了 OpenWrt 这款软路由固件,一是因为它插件比较多,有更多可玩性,二是用户量大,教程多,遇到问题容易找到解决方案。

话不多说,开干。

阅读全文 »

P199: “默认情况下,如果可执行文件是动态连接的,那么 GCC 会使用 PIC 的方法来产生可执行文件的代码段部分,以便于不同的进程能够共享” 但我用 GCC 去编译 32 位可执行文件,加 -fPIC 和不加 -fPIC,编出的指令是有差别的:

-fPIC 对生成指令的影响

阅读全文 »

学习 vfork 的时候,看到这篇文章中的一个例子,觉得很有趣,就拷贝下来自己跑了一下,其中的例子差不多是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void fun1() {
vfork();
printf("%d\n", getpid());
}

void fun2() {
_exit(0);
}

int main() {

fun1();

printf("%d goes 1\n", getpid());

fun2();

printf("%d goes 2\n", getpid());

return 0;
}
阅读全文 »

前言

这两天为了破解到期魔百盒看了好多帖子,最终成功破解了。为了让大家少走弯路,只看一篇帖子就能完成破解,我汇总了一下这两天学习到的东西,并分享下我的破解经历,希望对大家有所帮助。

盒子型号

首先说下盒子型号是 CM201-2 长虹代工 (CH),具体信息见图片:

盒子信息

板子上的硬件信息是:CPU 型号是 HI3890MV300,闪存是 emmc。机型编码和牌照方不同应该没太大关系,因为网上那些教程和我的都不一样,但我也刷机成功了。大家可以先尝试一下,如果不行再说。

阅读全文 »

View 的焦点机制

约定:文章中的 View 有时是指狭义的 View.class,有时指的是 View.class 和 ViewGruop.class 的统称,具体含义根据上下文而定

和焦点相关的 xml 属性

在 xml 中,有两个比较重要的属性和焦点有关,它们是 focusable 和 focusableInTouchMode。前者决定这个 View 是否可获取焦点,如果它的值为 false,那么它就和焦点无缘了;后者决定这个 View 在触屏模式下是否可获取焦点,如果它的值为 false,那么即使 focusable 的值为 true,在触屏模式下它也无法获取焦点。比如 Button,如果我们通过外接键盘进行操作,我们会发现 Button 是可以获得焦点的,但是在触屏模式下,Button 是不可获取焦点的。所以我们可以知道 Button 的 focusable 属性默认为 true,而 focusableInTouchMode 属性为 false。

阅读全文 »

Android LaunchMode 总结

Android 中的 LaunchMode 是一个比较基础的知识点,关于这块之前每次都是先用现学,然后学了之后又忘了,现在把 LaunchMode 的规律记录下来以备后用。

需要了解的知识点

在讲 LaunchMode 之前,需要了解一下几点知识:

  1. task 有属性 affinity,Activity 有属性 taskAffinity
  2. 可以存在两个 affinity 一样的 task;
  3. 一个 Activity 的 taskAffnity 默认值为 package name,如果有指定值就会设为指定值
    阅读全文 »

Android 事件分发规律总结

定义

事件序列:手指接触屏幕开始到离开屏幕为止产生的事件为一次事件序列。

规律一

从父视图的角度来看,无论他的子视图是 View 还是 ViewGroup,对父视图来说都是透明的。它只知道如果当 ACTION_DOWN 事件传给子视图后子视图的 dispatchTouchEvent () 返回 true,说明子视图想要处理这个事件,那么以后的事件就都交给它,不管以后子视图的 dispatchTouchEvent() 返回的是 true 还是 false; 如果 ACTION_DOWN 事件传给子视图后子视图返回的是 false,那么以后的事件再也不会传给子视图(子视图没有处理 ACTION_DOWN 就视作它不想处理该事件序列)。如果一个子视图的 dispatchTouchEvent() 在处理 ACTION_DOWN 时返回 true ,只要父视图没有拦截事件, 那么该事件序列中的后续事件都会传入该视图中,也就是传入该视图的 dispatchTouchEvent() 方法中,就算手指的触摸区域已经超出了该视图的范围。并且对于该事件序列的之后所有事件,即使该视图的 dispatchTouchEvent() 返回 false 事件也同样会继续传入该视图,唯一的影响是会将该事件原路返回,最终落到 activity.onTouchEvent() 中。因此建议如果消耗了该事件,除非有特殊情况需要处理,最好不要返回 false,否则上级视图以为下面的视图没有处理事件从而自己处理。

阅读全文 »

Glide 之磁盘缓存

Glide 提供了灵活的磁盘缓存策略,用户可以定义自己的缓存策略,只需要实现 DiskCache 接口即可。Glide 中已经有两个 DiskCache 实现,一个是 DiskCacheWrapper,这个类什么都没干,就是一个空壳,用来包装其他的 DiskCache 实现类;另一个类是 DiskLruCaheWrapper,它是基于 DiskLruCache 实现的。接下来从 DiskLruCahce 分析一下 Glide 的磁盘缓存。

阅读全文 »