kotlin返回与跳转

Kotlin 有三种结构化跳转表达式:

return 默认从最直接包围它的函数或者匿名函数返回。
break 终止最直接包围它的循环。
continue 继续下一次最直接包围它的循环。
所有这些表达式都可以用作更大表达式的一部分:

val s = person.name ?: return
这些表达式的类型是 Nothing 类型。

Break 与 Continue 标签
在 Kotlin 中任何表达式都可以用标签来标记。 标签的格式为标识符后跟 @ 符号,例如:abc@、fooBar@。 要为一个表达式加标签,我们只要在其前加标签即可。

loop@ for (i in 1..100) {
// ……
}
现在,我们可以用标签限定 break 或者 continue:

loop@ for (i in 1..100) {
for (j in 1..100) {
if (……) break@loop
}
}
标签限定的 break 跳转到刚好位于该标签指定的循环后面的执行点。 continue 继续标签指定的循环的下一次迭代。

返回到标签
Kotlin 中函数可以使用函数字面量、局部函数与对象表达式实现嵌套。 标签限定的 return 允许我们从外层函数返回。 最重要的一个用途就是从 lambda 表达式中返回。回想一下我们这么写的时候, 这个 return 表达式从最直接包围它的函数——foo 中返回:

//sampleStart
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return // 非局部直接返回到 foo() 的调用者
print(it)
}
println(“this point is unreachable”)
}
//sampleEnd

fun main() {
foo()
}
注意,这种非局部的返回只支持传给内联函数的 lambda 表达式。 如需从 lambda 表达式中返回,可给它加标签并用以限定 return。

//sampleStart
fun foo() {
listOf(1, 2, 3, 4, 5).forEach lit@{
if (it == 3) return@lit // 局部返回到该 lambda 表达式的调用者——forEach 循环
print(it)
}
print(“ done with explicit label”)
}
//sampleEnd

fun main() {
foo()
}
现在,它只会从 lambda 表达式中返回。通常情况下使用隐式标签更方便,因为该标签与接受该 lambda 的函数同名。

//sampleStart
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@forEach // 局部返回到该 lambda 表达式的调用者——forEach 循环
print(it)
}
print(“ done with implicit label”)
}
//sampleEnd

fun main() {
foo()
}
或者,我们用一个匿名函数替代 lambda 表达式。 匿名函数内部的 return 语句将从该匿名函数自身返回

//sampleStart
fun foo() {
listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {
if (value == 3) return // 局部返回到匿名函数的调用者——forEach 循环
print(value)
})
print(“ done with anonymous function”)
}
//sampleEnd

fun main() {
foo()
}
请注意,前文三个示例中使用的局部返回类似于在常规循环中使用 continue。

并没有 break 的直接等价形式,不过可以通过增加另一层嵌套 lambda 表达式并从其中非局部返回来模拟:

//sampleStart
fun foo() {
run loop@{
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@loop // 从传入 run 的 lambda 表达式非局部返回
print(it)
}
}
print(“ done with nested loop”)
}
//sampleEnd

fun main() {
foo()
}
当要返一个回值的时候,解析器优先选用标签限定的返回:

return@a 1
这意味着“返回 1 到 @a”,而不是“返回一个标签标注的表达式 (@a 1)”。

android中gradle编译error

  1. The binary version of its metadata is 1.7.1, expected version is 1.5.1
    原因:依赖中某些库使用 kotlin 1.7.1 编译,而工程指定为 1.5.1
    解决方式 1:
    升级 gradle 版本,或 kotlin 版本

方式 2:
降低库的版本,如:

1
2
3
4
5
6
7
subprojects { project ->
println "project name:" + project.name
configurations.all {
resolutionStrategy {
force "androidx.activity:activity:$androidx_activity_version"
}
}

adb用法

启动 App

adb shell monkey -p com.android.settings -c android.intent.category.LAUNCHER 1

列出 app

adb shell pm list packages

发送广播

adb root
adb shell am broadcast -a android.intent.action.BOOT_COMPLETED

android集成X5浏览器

参考博文

https://blog.csdn.net/qq_34205629/article/details/122375262

下载内核

android studio 打开 X5Demo(官方 demo),

  1. 点击”TBS 调试“
  2. 点击”安装线上内核“
  3. 控制台查看日志输入:
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
{
"BUGLY" : 0,
"DOWNLOADMAXFLOW" : 300,
"DOWNLOADURL" : "https://tbstx.imtt.qq.com/others/release/x5/tbs_core_046317_20221125231059_nolog_fs_obfs_arm64-v8a_release.tbs",
"DOWNLOAD_FAILED_MAX_RETRYTIMES" : 10,
"DOWNLOAD_MIN_FREE_SPACE" : 0,
"DOWNLOAD_SINGLE_TIMEOUT" : 1200000,
"DOWNLOAD_SUCCESS_MAX_RETRYTIMES" : 3,
"MSG" : "success, dcl:103846,url:102237",
"PKGMD5" : "0b8d4f9faecea88015064b34092ffd82",
"RESETDECOUPLECORE" : 0,
"RESETTODECOUPLECORE" : 0,
"RESETTOKEN" : 1,
"RESETX5" : 0,
"RESPONSECODE" : 1,
"RET" : 0,
"TBSAPKFILESIZE" : 52874442,
"TBSAPKSERVERVERSION" : 46317,
"TEMPLATESWITCH" : 0,
"UPLOADLOG" : 0,
"USEBACKUPVER" : 0,
"USEVIDEO" : 1,
"USEX5" : 1,
"USE_SECURITY" : 0
}

android镜像解压资源文件

工具准备

  1. unpackbootimg
  2. resource-tool
  3. dtc
  4. rk 烧录工具

编译 unpackbootimg

源码

https://github.com/huangzhenzeng/android-unpackbootimg

编译

只需要在 linux(需安装 gcc,make,一般是标配)或 windows(需要安装 mingw)的命令行执行 make,即可产生可执行文件 mkbootimg、unpackbootimg

resource-tool 工具

一般编译镜像后,将产生这个工具,目录为:
u-boot/tools/resource_tool/resource_tool

dtc 工具

一般编译镜像后,将产生这个工具,目录为:
kernel/scripts/dtc/dtc

rk 烧录工具

需到如下地址
https://www.t-firefly.com/doc/download/54.html
下载《RKDevTool》

分离镜像

window 下,打开“RKDevTool”,选中“高级”,然后导入固件,选择解压即可,如下图:

最终 output 目录,输出各个子分区,如下图:

解压 boot.img 镜像

boot 格式分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
因为boot.img的格式比较简单,它主要分为三大块(有的可能有四块)
+—————–+
| boot header | 1 page
+—————–+
| kernel | n pages
+—————–+
| ramdisk | m pages
+—————–+
| second stage | o pages
+—————–+
n = (kernel_size + page_size – 1) / page_size
m = (ramdisk_size + page_size – 1) / page_size
o = (second_size + page_size – 1) / page_size
0. all entities are page_size aligned in flash
1. kernel and ramdisk are required (size != 0)
2. second is optional (second_size == 0 -> no second)

linux 下输入命令:
mkdir output
unpackbootimg -I boot.img -O ./output
生成文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
├── boot.img-base (mkbootimg base参数)
├── boot.img-board
├── boot.img-cmdline (mkbootimg cmdline参数)
├── boot.img-dtb
├── boot.img-hash
├── boot.img-kerneloff
├── boot.img-oslevel
├── boot.img-osversion
├── boot.img-pagesize (mkbootimg pagesize参数)
├── boot.img-ramdisk.gz (根文件系统打包文件)
├── boot.img-ramdiskoff
├── boot.img-second (资源文件)
├── boot.img-secondoff
├── boot.img-tagsoff
├── boot.img-zImage (内核文件)

解压 boot.img-second 资源

执行命令:
mkdir out
./resource_tool --verbose --unpack --image=boot.img-second

生成文件如下:

1
2
3
├── logo.bmp
├── logo_kernel.bmp
└── rk-kernel.dtb

dtb 转 dts

执行命令:
./dtc -I dtb -O dts out/rk-kernel.dtb -o tmp.dts
生成 tmp.dts 文件,

最终通过 gedit 或文本编辑查看

ParcelFileDescriptor使用说明

文件描述符,是一种程序读写已打开文件、socket 的对象。

FileDescriptor 对象,它代表了原始的 Linux 文件描述符
ParcelFileDescriptor 对象,是原始文件描述符的一个复制,对象跟 fd 不同,但都是操作同一个底层文件流以及文件位置指针

简单的 ParcelFileDescriptor 使用——pipe

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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
public class DemoParcefliledescriptor extends AppCompatActivity {

private static final String TAG = "DemoPFD";

private static final String[] PERMISSIONS = {
Manifest.permission.WRITE_EXTERNAL_STORAGE,
};
private static final int PERMISSIONS_CODE = 3006;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo_null);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(PERMISSIONS, PERMISSIONS_CODE);
}

FileOutputStream outputStream = new FileOutputStream(getStreamFd());
try {
outputStream.write(99);
outputStream.write(98);
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}


private FileDescriptor getStreamFd() {
ParcelFileDescriptor[] pipes = null;

try {
pipes = ParcelFileDescriptor.createPipe();
new TransferThread(new ParcelFileDescriptor.AutoCloseInputStream(pipes[0])).start();
} catch (IOException e) {
e.printStackTrace();
}

return pipes[1].getFileDescriptor();
}

static class TransferThread extends Thread {
InputStream in;
FileOutputStream out;

TransferThread(InputStream in, FileOutputStream out) {
this.in = in;
this.out = out;
}

TransferThread(InputStream in) {
this.in = in;

File outFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/zlq_pdf");
Log.i(TAG, "File: " + outFile.getAbsolutePath());

try {
out = new FileOutputStream(outFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}

@Override
public void run() {
byte[] buf = new byte[1024*2];

int len;
try {
while((len=in.read(buf)) > 0) {
out.write(buf, 0, len);
Log.i(TAG, "out:" + len);

}

in.close();
out.flush();
out.getFD().sync();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}