This question is driven by my curiosity alone, so I would like to receive a full answer, rather than simple "yes" or "no".
Let's consider this piece of code:
// Is stored in util files and used to omit annoying (this as? Smth)?.doSmth()
inline fun <reified T> Any?.cast(): T? {
return this as? T
}
class PagingOnScrollListener(var onLoadMore: (currentPage: Int, pageSize: Int) -> Unit) : RecyclerView.OnScrollListener() {
constructor() : this({ _, _ -> Unit })
private var loading = false
private var currentPage = 0
private var latestPageSize = -1
var visibleThreshold = VISIBLE_THRESHOLD_DEFAULT
var pageSize = PAGE_SIZE_DEFAULT
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val linearLayoutManager = recyclerView.linearLayoutManager
val totalItemCount = linearLayoutManager.itemCount
val lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition()
if (!loading && totalItemCount - lastVisibleItem <= visibleThreshold
&& latestPageSize !in 0 until pageSize) {
currentPage++
loading = true
onLoadMore(currentPage, pageSize)
}
}
private inline val RecyclerView.linearLayoutManager
get() = layoutManager?.cast<LinearLayoutManager>()
?: throw IllegalStateException("PagingOnScrollListener requires LinearLayoutManager to be attached to RecyclerView!")
companion object {
private const val VISIBLE_THRESHOLD_DEFAULT = 4
private const val PAGE_SIZE_DEFAULT = 10
}
}
When I use "Show Kotlin Bytecode" tool in AndroidStudio, and then click "Decompile" button, I see this java code (I deleted some irrelevant stuff):
public final class PagingOnScrollListener extends RecyclerView.OnScrollListener {
private boolean loading;
private int currentPage;
private int latestPageSize;
private int visibleThreshold;
private int pageSize;
@NotNull
private Function2 onLoadMore;
private static final int VISIBLE_THRESHOLD_DEFAULT = 4;
private static final int PAGE_SIZE_DEFAULT = 10;
public PagingOnScrollListener(@NotNull Function2 onLoadMore) {
Intrinsics.checkParameterIsNotNull(onLoadMore, "onLoadMore");
super();
this.onLoadMore = onLoadMore;
this.latestPageSize = -1;
this.visibleThreshold = 4;
this.pageSize = 10;
}
public PagingOnScrollListener() {
this((Function2)null.INSTANCE);
}
public void onScrolled(@NotNull RecyclerView recyclerView, int dx, int dy) {
Intrinsics.checkParameterIsNotNull(recyclerView, "recyclerView");
super.onScrolled(recyclerView, dx, dy);
int $i$f$getLinearLayoutManager = false;
RecyclerView.LayoutManager var10000 = recyclerView.getLayoutManager();
if (var10000 != null) {
Object $this$cast$iv$iv = var10000;
int $i$f$cast = false;
var10000 = $this$cast$iv$iv;
if (!($this$cast$iv$iv instanceof LinearLayoutManager)) {
var10000 = null;
}
LinearLayoutManager var10 = (LinearLayoutManager)var10000;
if (var10 != null) {
LinearLayoutManager linearLayoutManager = var10;
int totalItemCount = linearLayoutManager.getItemCount();
int lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
if (!this.loading && totalItemCount - lastVisibleItem <= this.visibleThreshold) {
int var11 = this.pageSize;
int var12 = this.latestPageSize;
if (0 <= var12) {
if (var11 > var12) {
return;
}
}
int var10001 = this.currentPage++;
this.loading = true;
this.onLoadMore.invoke(this.currentPage, this.pageSize);
}
return;
}
}
throw (Throwable)(new IllegalStateException("EndlessOnScrollListener requires LinearLayoutManager to be attached to RecyclerView!"));
}
}
Here we can see some strange code:
1.
// in constructor:
Intrinsics.checkParameterIsNotNull(onLoadMore, "onLoadMore");
super();
Java requires super
call to be the first statement in the constructor body.
2.
this((Function2)null.INSTANCE);
which corresponds to constructor() : this({ _, _ -> Unit })
What null.INSTANCE
means? Why is there no anonymous object as was intended?
this(new Function2() {
@Override
public Object invoke(Object o1, Object o2) {
return kotlin.Unit.INSTANCE;
}
});
3.
No @Override
annotation on method onScrolled
. Was it too hard to add an annotation to the method with override
modifier? However the @NonNull
and @Nullable
annotations are present.
4.
int $i$f$getLinearLayoutManager = false;
Boolean
value is being assigned to int
variable? Why this line is present here? This variable has no usage. Why it declares a variable that isn't going to be used?
5.
RecyclerView.LayoutManager var10000 = recyclerView.getLayoutManager();
if (var10000 != null) {
Object $this$cast$iv$iv = var10000; // what's the purpose of this assignment?
int $i$f$cast = false;
var10000 = $this$cast$iv$iv; // Incompatible types. RecyclerView.LayoutManager was expected but got Object.
...
6.
if (!this.loading && totalItemCount - lastVisibleItem <= this.visibleThreshold) {
int var11 = this.pageSize;
int var12 = this.latestPageSize;
if (0 <= var12) {
if (var11 > var12) {
return;
}
}
...
}
Why don't make it simpler with this?
if (!this.loading && totalItemCount - lastVisibleItem <= this.visibleThreshold && (0 > this.latestPageSize || this.pageSize < this.latestPageSize))
7.
// Unhandled exception: java.lang.Throwable.
throw (Throwable)(new IllegalStateException("EndlessOnScrollListener requires LinearLayoutManager to be attached to RecyclerView!"));
Why it casts IllegalStateException
to Throwable
if we know that IllegalStateException extends Throwable
? What's the purpose?
Is that really the code that is being performed in production or just Java Decompiler can't figure out all that stuff?