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.INSTANCEmeans? 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?