java输出的规则_每日一问 关于 R.java 的生成规则,你知道多少?

最终打包出来的那些资源id,是会重新分配的(同一个资源生成的id,就算不在同一个R.class里,打包出来时也是相同的)。

做了个测试:

app依赖了模块test;

test模块中的string.xml有个test_value;

在test模块中引用(com.test.R),看到这个test_value的id值是-1900002;

而在app中(com.app.R)引用时,id值为-1900023;

这时候可以看出,相同的资源,id确实是不同。

打包成apk后,把它拖进AS里,点开classes.dex:

首先找到app包名下的R$string,右键查看字节码,发现test_value的id值由原来的-1900023,变成了0x7f10005d;

接着找test模块包名下的R$string,查看字节码发现id值一样是0x7f10005d;

由此看来,id值在打包成apk的时候,确实是重新分配了,而且同一个资源的id值,也统一了。

源码分析

那它究竟是如何重新分配这些id值的呢?

上一次也分析过https://www.wanandroid.com/wenda/show/8985,很多任务都是在ApplicationTaskManager里的createTasksForVariantScope方法中创建的。

那现在再来看一下这个方法:

@Override

public void createTasksForVariantScope(

@NonNull final VariantScope variantScope,

@NonNull List variantScopesForLint) {

......

// Add a task to create the BuildConfig class

createBuildConfigTask(variantScope);

// Add a task to process the Android Resources and generate source files

createApkProcessResTask(variantScope);

......

}

可以看到,创建BuildConfig任务之后,接着调用了一个createApkProcessResTask方法,看上面注释,是用来处理资源和生成源码文件的。一步步点进去看看:

createApkProcessResTask() ->

createProcessResTask() ->

createNonNamespacedResourceTasks() ->

GenerateLibraryRFileTask.doFullTaskAction() ->

GenerateLibRFileRunnable.run() ->

SymbolExportUtils.processLibraryMainSymbolTable()

看看这个processLibraryMainSymbolTable方法:

fun processLibraryMainSymbolTable() {

......

val tablesToWrite = processLibraryMainSymbolTable()

// Generate R.java files for main and dependencies

tablesToWrite.forEach { SymbolIo.exportToJava(it, sourceOut, false) }

......

}

看中间的注释,可以确定下面一句就是生成R.java的了,它会为tablesToWrite里面的每一个item都生成一个R文件,看一下这个tablesToWrite怎么来的:

internal fun processLibraryMainSymbolTable(): List {

// Merge all the symbols together.

// We have to rewrite the IDs because some published R.txt inside AARs are using the

// wrong value for some types, and we need to ensure there is no collision in the

// file we are creating.

val allSymbols: SymbolTable = mergeAndRenumberSymbols(

finalPackageName, librarySymbols, depSymbolTables, platformSymbols

)

val mainSymbolTable = if (namespacedRClass) allSymbols.filter(librarySymbols) else allSymbols

// Generate R.txt file.

Files.createDirectories(symbolFileOut.parent)

SymbolIo.writeForAar(mainSymbolTable, symbolFileOut)

val tablesToWrite =

RGeneration.generateAllSymbolTablesToWrite(allSymbols, mainSymbolTable, depSymbolTables)

return tablesToWrite

}

妈耶!看开头的注释:"We have to rewrite the IDs",也就是必须重写这些id的意思了,再看一下它接下来调用的mergeAndRenumberSymbols方法:

fun mergeAndRenumberSymbols(): SymbolTable {

......

// the ID value provider.

val idProvider = IdProvider.sequential()

......

}

可以看到调用了IdProvider的sequential方法,点开看下:

fun sequential(): IdProvider {

return object : IdProvider {

private val next = ShortArray(ResourceType.values().size)

override fun next(resourceType: ResourceType): Int {

val typeIndex = resourceType.ordinal

return 0x7f shl 24 or (typeIndex + 1 shl 16) or (++next[typeIndex]).toInt()

}

}

}

emmm,0x7f开头的id值,确实是对应的我们开头打包后的那个test_value的id值(0x7f10005d)。

到这里基本可以确定,最终打包的资源id,就是通过这个IdProvider的匿名子类来重新创建的,而且同一个资源所对应的id,也是一样的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值