While statement causing freeze/crash in LibGDX? - while-loop

I have the following code in the update method of a base level class:
while(entities.iterator().hasNext()){
if(entities.iterator().next() != null){
entities.iterator().next().update();
Gdx.app.log(Game.LOG, "Updated Entity "+entities.iterator().next().getName()+".");
}
else{
Gdx.app.log(Game.LOG, "Could not update Entity.");
}
}
However, this statement will freeze the program when it is run, and will have to be force closed without providing any crash information. I can stop the freezing by using an if statement instead of a while, however, it will only update the first entity in the array.
What could be causing the freeze, and how can the iterator be looped without causing it?

Don't call the iterator() and next() methods more than required. The iterator() method will reset the iterator on every call. The next() method will fetch the next item on every call. Instead use something like this:
Iterator<T> iterator = entities.iterator();
while(iterator.hasNext()) {
T entity = iterator.next();
entity.update();
}
Where T should be replaced by the class of your entity.
Edit, easier would be using the syntactic sugar:
for (T entity : entities) {
entity.update();
}

Related

Test with Kotlin Coroutines is randomly failing

Let us suppose we have a class member whose purpose is
to bring 2 objects (let's say object1 and object2) from two different places and then create the final
result merging these two object in another one, which is finally returned.
Suppose then the operation of retrieving object1 and object2 can be done concurrently,
so this leads to a typical use case of kotlin coroutines.
What has been described so far is shown in the following example:
fun parallelCall(): MergedObject {
return runBlocking(context = Dispatchers.Default) {
try {
val object1 : Deferred<Object1> = async {
bringObject1FromSomewhere()
}
val object2 : Deferred<Object2> = async {
bringObject2FromSomewhere()
}
creteFinalObject(object1.await(), object2.await())
} catch (ex: Exception) {
throw ex
}
}
}
The surrounding try block should intercept any kind of exception thrown while
object1 and object2 are retrieved, as well as in the createFinalObject method.
This latter simply merges together the awaited results from previous calls,
waiting for both of them to be accomplished.
Note that the awaiting of the deferred object1 and object2 happens almost at the same time,
since they are both awaited when passed as arguments to the createFinalObject method.
In this scenario I can perform a test using mockk as mocking library such that whenever bringObject1FromSomewhere()
throws an exception, then the creteFinalObject method is NEVER called. Namely, something like:
#Test
fun `GIVEN bringObject1FromSomewhere throws exception WHEN parallelCall executes THEN creteFinalObject is never executed`() {
every { bringObject1FromSomewhere() } throws NullPointerException()
every { bringObject2FromSomewhere() } returns sampleObject2
assertThrows<NullPointerException> { parallelCall() }
verify(atMost = 1) { bringObject1FromSomewhere() }
verify(atMost = 1) { bringObject2FromSomewhere() }
//should never be called since bringObject1FromSomewhere() throws nullPointer exception
verify(exactly = 0) { creteFinalObject(any(), any()) }
}
The problem is that the test above works almost always, but, there are some cases in which it randomly fails,
calling the createFinalObject method regardless of the mocked values.
Is this issue related to the slight difference in time in which the deferred object1 and object2
are awaited when creteFinalObject(object1.await(), object2.await()) is called?
Another thing which comes to my mind could be the way in which I am expecting argument in the last line of the test:
verify(exactly = 0) { creteFinalObject(any(), any()) }
does mockk could have any problem when any() is used?.
Further, can potentially be an issue the fact that the try { } block is not able to detect the exception
before the createFinalObject method is called? I would never doubt about this in a non-parallel environment but probably
the usage of runBlocking as coroutineScope changes the rule of the game?
Any hints will be helpful, thanks!
Kotlin version:1.6.0 Corutines version: 1.5.2 mockk version: 1.12.2
Are you sure it fails because it attempts to call the creteFinalObject function? Because when reading your code, I think that should be impossible (of course, never say never :D). The creteFinalObject function can only be called if both object1.await() and object2.await() return successfully.
I think something else is going on. Because you're doing 2 separate async tasks (getting object 1 and getting object 2), I suspect that the ordering of these 2 tasks would result in either a success or a failure.
Running your code locally, I notice that it sometimes fails at this line:
verify(atMost = 1) { bringObject2FromSomewhere() }
And I think there is your error. If bringObject1FromSomewhere() is called before bringObject2FromSomewhere(), the exception is thrown and the second function invocation never happens, causing the test to fail. The other way around (2 before 1) would make the test succeed. The Dispatchers.Default uses an internal work queue, where jobs that are cancelled before they are even started will never start at all. And the first task can fail fast enough for the second task to not being able to start at all.
I thought the fix would be to use verify(atLeast = 0, atMost = 1) { bringObject2FromSomewhere() } instead, but as I see on the MockK GitHub issues page, this is not supported (yet): https://github.com/mockk/mockk/issues/806
So even though you specify that bringObject2FromSomewhere() should be called at most 1 time, it still tries to verify it is also called at least 1 time, which is not the case.
You can verify this by adding a delay to the async call to get the first object:
val object1 : Deferred<Object1> = async {
delay(100)
bringObject1FromSomewhere()
}
This way, the test always succeeds, because bringObject2FromSomewhere() always has enough time to be called.
So how to fix this? Either hope MockK fixes the functionality to specify verify(atLeast = 0, atMost = 1) { ... }, or disable the verification on this call for now.

How to return an int value stuck in a for loop but a callback in Kotlin?

I am trying to get the size of this firebase collection size of documents, and for some reason in Kotlin, I can't seem to get this to work. I have declared a variable to be zero in an int function and I put it inside a for loop where it increments to the size of the range. Then when I return the value, it is zero. Here is the code I have provided, please help me as to why it is returning zero.
This is just what is being passed to the function
var postSize = 0
That is the global variable, now for below
val db = FirebaseFirestore.getInstance()
val first = db.collection("Post").orderBy("timestamp")
getPostSize(first)
This is the function
private fun getPostSize(first: Query){
first.get().addOnSuccessListener { documents ->
for(document in documents) {
Log.d(TAG, "${document.id} => ${document.data}")
getActualPostSize(postSize++)
}
}
return postSize
}
private fun getActualPostSize(sizeOfPost: Int): Int {
// The number does push to what I am expecting right here if I called a print statement
return sizeOfPost // However here it just returns it to be zero again. Why #tenffour04? Why?
}
It is my understanding, according to the other question that this was linked to, that I was suppose to do something like this.
This question has answers that explain how to approach getting results from asynchronous APIs, like you're trying to do.
Here is a more detailed explanation using your specific example since you were having trouble adapting the answer from there.
Suppose this is your original code you were trying to make work:
// In your "calling code" (inside onCreate() or some click listener):
val db = FirebaseFirestore.getInstance()
val first = db.collection("Post").orderBy("timestamp")
val postSize = getPostSize(first)
// do something with postSize
// Elsewhere in your class:
private fun getPostSize(first: Query): Int {
var postSize = 0
first.get().addOnSuccessListener { documents ->
for(document in documents) {
Log.d(TAG, "${document.id} => ${document.data}")
postSize++
}
}
return postSize
}
The reason this doesn't work is that the code inside your addOnSuccessListener is called some time in the future, after getPostSize() has already returned.
The reason asynchronous code is called in the future is because it takes a long time to do its action, but it's bad to wait for it on the calling thread because it will freeze your UI and make the whole phone unresponsive. So the time-consuming action is done in the background on another thread, which allows the calling code to continue doing what it's doing and finish immediately so it doesn't freeze the UI. When the time-consuming action is finally finished, only then is its callback/lambda code executed.
A simple retrieval from Firebase like this likely takes less than half a second, but this is still too much time to freeze the UI, because it would make the phone seem janky. Half a second in the future is still in the future compared to the code that is called underneath and outside the lambda.
For the sake of simplifying the below examples, let's simplify your original function to avoid using the for loop, since it was unnecessary:
private fun getPostSize(first: Query): Int {
var postSize = 0
first.get().addOnSuccessListener { documents ->
postSize = documents.count()
}
return postSize
}
The following are multiple distinct approaches for working with asynchronous code. You only have to pick one. You don't have to do all of them.
1. Make your function take a callback instead of returning a value.
Change you function into a higher order function. Since the function doesn't directly return the post size, it is a good convention to put "Async" in the function name. What this function does now is call the callback to pass it the value you wanted to retrieve. It will be called in the future when the listener has been called.
private fun getPostSizeAsync(first: Query, callback: (Int) -> Unit) {
first.get().addOnSuccessListener { documents ->
val postSize = documents.count()
callback(postSize)
}
}
Then to use your function in your "calling code", you must use the retrieved value inside the callback, which can be defined using a lambda:
// In your "calling code" (inside onCreate() or some click listener):
val db = FirebaseFirestore.getInstance()
val first = db.collection("Post").orderBy("timestamp")
getPostSizeAsync(first) { postSize ->
// do something with postSize inside the lambda here
}
// Don't try to do something with postSize after the lambda here. Code under
// here is called before the code inside the lambda because the lambda is called
// some time in the future.
2. Handle the response directly in the calling code.
You might have noticed in the above solution 1, you are really just creating an intermediate callback step, because you already have to deal with the callback lambda passed to addOnSuccessListener. You could eliminate the getPostSize function completely and just deal with callbacks at once place in your code. I wouldn't normally recommend this because it violates the DRY principle and the principle of avoiding dealing with multiple levels of abstraction in a single function. However, it may be better to start this way until you better grasp the concept of asynchronous code.
It would look like this:
// In your "calling code" (inside onCreate() or some click listener):
val db = FirebaseFirestore.getInstance()
val first = db.collection("Post").orderBy("timestamp")
first.get().addOnSuccessListener { documents ->
val postSize = documents.count()
// do something with postSize inside the lambda here
}
// Don't try to do something with postSize after the lambda here. Code under
// here is called before the code inside the lambda because the lambda is called
// some time in the future.
3. Put the result in a LiveData. Observe the LiveData separately.
You can create a LiveData that will update its observers about results when it gets them. This may not be a good fit for certain situations, because it would get really complicated if you had to turn observers on and off for your particular logic flow. I think it is probably a bad solution for your code because you might have different queries you want to pass to this function, so it wouldn't really make sense to have it keep publishing its results to the same LiveData, because the observers wouldn't know which query the latest postSize is related to.
But here is how it could be done.
private val postSizeLiveData = MutableLiveData<Int>()
// Function name changed "get" to "fetch" to reflect it doesn't return
// anything but simply initiates a fetch operation:
private fun fetchPostSize(query: Query) {
first.get().addOnSuccessListener { documents ->
postSize.value = documents.count()
}
}
// In your "calling code" (inside onCreate() or some click listener):
val db = FirebaseFirestore.getInstance()
val first = db.collection("Post").orderBy("timestamp")
fetchPostSize(first)
postSizeLiveData.observer(this) { postSize ->
// Do something with postSize inside this observer that will
// be called some time in the future.
}
// Don't try to do something with postSize after the lambda here. Code under
// here is called before the code inside the lambda because the lambda is called
// some time in the future.
4. Use a suspend function and coroutine.
Coroutines allow you to write synchronous code without blocking the calling thread. After you learn to use coroutines, they lead to simpler code because there's less nesting of asynchronous callback lambdas. If you look at option 1, it will become very complicated if you need to call more than one asynchronous function in a row to get the results you want, for example if you needed to use postSize to decide what to retrieve from Firebase next. You would have to call another callback-based higher-order function inside the lambda of your first higher-order function call, nesting the future code inside other future code. (This is nicknamed "callback hell".) To write a synchronous coroutine, you launch a coroutine from lifecycleScope (or viewLifecycleOwner.lifecycleScope in a Fragment or viewModelScope in a ViewModel). You can convert your getter function into a suspend function to allow it to be used synchronously without a callback when called from a coroutine. Firebase provides an await() suspend function that can be used to wait for the result synchronously if you're in a coroutine. (Note that more properly, you should use try/catch when you call await() because it's possible Firebase fails to retrieve the documents. But I skipped that for simplicity since you weren't bothering to handle the possible failure with an error listener in your original code.)
private suspend fun getPostSize(first: Query): Int {
return first.get().await().count()
}
// In your "calling code" (inside onCreate() or some click listener):
lifecycleScope.launch {
val db = FirebaseFirestore.getInstance()
val first = db.collection("Post").orderBy("timestamp")
val postSize = getPostSize(first)
// do something with postSize
}
// Code under here will run before the coroutine finishes so
// typically, you launch coroutines and do all your work inside them.
Coroutines are the common way to do this in Kotlin, but they are a complex topic to learn for a newcomer. I recommend you start with one of the first two solutions until you are much more comfortable with Kotlin and higher order functions.

How to modify variables outside of their scope in kotlin?

I understand that in Kotlin there is no such thing as "Non-local variables" or "Global Variables" I am looking for a way to modify variables in another "Scope" in Kotlin by using the function below:
class Listres(){
var listsize = 0
fun gatherlistresult(){
var listallinfo = FirebaseStorage.getInstance()
.getReference()
.child("MainTimeline/")
.listAll()
listallinfo.addOnSuccessListener {
listResult -> listsize += listResult.items.size
}
}
}
the value of listsize is always 0 (logging the result from inside of the .addOnSuccessListener scope returns 8) so clearly the listsize variable isn't being modified. I have seen many different posts about this topic on other sites , but none fit my usecase.
I simply want to modify listsize inside of the .addOnSuccessListener callback
This method will always be returned 0 as the addOnSuccessListener() listener will be invoked after the method execution completed. The addOnSuccessListener() is a callback method for asynchronous operation and you will get the value if it gives success only.
You can get the value by changing the code as below:
class Demo {
fun registerListResult() {
var listallinfo = FirebaseStorage.getInstance()
.getReference()
.child("MainTimeline/")
.listAll()
listallinfo.addOnSuccessListener {
listResult -> listsize += listResult.items.size
processResult(listsize)
}
listallinfo.addOnFailureListener {
// Uh-oh, an error occurred!
}
}
fun processResult(listsize: Int) {
print(listResult+"") // you will get the 8 here as you said
}
}
What you're looking for is a way to bridge some asynchronous processing into a synchronous context. If possible it's usually better (in my opinion) to stick to one model (sync or async) throughout your code base.
That being said, sometimes these circumstances are out of our control. One approach I've used in similar situations involves introducing a BlockingQueue as a data pipe to transfer data from the async context to the sync context. In your case, that might look something like this:
class Demo {
var listSize = 0
fun registerListResult() {
val listAll = FirebaseStorage.getInstance()
.getReference()
.child("MainTimeline/")
.listAll()
val dataQueue = ArrayBlockingQueue<Int>(1)
listAll.addOnSuccessListener { dataQueue.put(it.items.size) }
listSize = dataQueue.take()
}
}
The key points are:
there is a blocking variant of the Queue interface that will be used to pipe data from the async context (listener) into the sync context (calling code)
data is put() on the queue within the OnSuccessListener
the calling code invokes the queue's take() method, which will cause that thread to block until a value is available
If that doesn't work for you, hopefully it will at least inspire some new thoughts!

Kotlin Kovenant returns the same object for all promises

I'm trying to use Kotlin Kovenant because I want a promise-based solution to track my retrofit calls.
What I did first was this:
all (
walkingRoutePromise,
drivingRoutePromise
) success { responses ->
//Do stuff with the list of responses
}
where the promises I pass are those that are resolved at the completion of my retrofit calls. However "responses" is a list of two identical objects. When debugging, I can confirm that two different objects with different values are being passed to the respective resolve methods. However kovenant returns two identical objects (same location in memory)
My next attempt was this:
task {
walkingRoutePromise
} then {
var returnval = it.get()
walkingDTO = returnval.deepCopy()
drivingRoutePromise
} success {
val returnval = it.get()
drivingDTO = returnval.deepCopy()
mapRoutes = MapRoutes(walkingDTO!!, drivingDTO!!)
currentRoute = mapRoutes!!.walking
callback()
}
Where I tried to do the calls one at a time and perform deep copies of the results. This worked for the first response, but then I found that it.get() in the success block - the success block of the second call - is the same unchanged object that I get from it.get() in the "then" block. It seems Kovenant is implemented to use one object for all of its resolutions, but after you resolve once, the single object it uses for the resolutions cannot be changed. What am I supposed to do if I want to access unique values from promise.resolve(object)? Seems like a very broken system.

Writing Custom Rule for Android-Lint

Q (tldr;): How do I use the JavaScanner in android-lint to check if a particular function call with a specific string as a parameter has been surrounded by a try/catch block.
Details: I have completed the android-lint tutorials on the official site and have gone through the source of the existing lint-checks. However, I can't seem to grasp the workflow for this AST-based parsing of JavaScanner. What I'm trying to achieve is to catch a function that sets a specific property and surround it with a try/catch block. For example:
MyPropertySettings.set("SOME_PROPERTY", "SOME_VAL");
should not trigger the lint rule but:
MyPropertySettings.set("SOME_SENSITIVE_PROPERTY", "SOME_VAL");
should because it's not surrounded by a try/catch block with SetPropertyException. I don't want to introduce the try/catch to the function itself because it only throws the exception in extremely rare cases (and the internals of the function are based on some reflection mojo).
For this question, even a workflow/hint would be fine. If I can get the first few steps, I might be able to grasp it better.
Update:
After some more study, I have found that I need to set the set function above in getApplicableMethodNames() and then, somehow read the property of that function to decide if the check applies. That part should be easy.
Surrounding try/catch would be more difficult and I gather I would need to do some "flow analysis". How is the question now.
Well, along with the getApplicableMethodNames() method, you need to override the visitMethod() function. You will get the MethodInvocationNode. Just fetch the arguments passed in the invocation using the node.astArguments() function. This returns a list of arguments that you can iterate through using a StrictListAccessor. Check the arguments passed and if it matches your criterion, run a loop and keep calculating the parent node of the invocation node till a try node is found. If it is a try node, then you can get a list of catches using node.astCatches(). Scan the list and find the appropriate exception. If not found, then report.
You can code like this:
check if it is surrounded by try/catch:
#Override
public void visitMethod(JavaContext context, AstVisitor visitor, MethodInvocation node) {
// check the specified class that invoke the method
JavaParser.ResolvedMethod method = (JavaParser.ResolvedMethod) context.resolve(node);
JavaParser.ResolvedClass clzz = method.getContainingClass();
boolean isSubClass = false;
// sSupportSuperType = {"class name"};
for (int i = 0; i < sSupportSuperType.length; i++) {
if (clzz.isSubclassOf(sSupportSuperType[i], false)) {
isSubClass = true;
break;
}
}
if (!isSubClass) return;
// check if surrounded by try/catch
Node parent = node;
while (true) {
Try tryCatch = context.getParentOfType(parent, Try.class);
if (tryCatch == null) {
break;
} else {
for (Catch aCatch : tryCatch.astCatches()) {
TypeReference catchType = aCatch.astExceptionDeclaration().astTypeReference();
}
parent = tryCatch;
}
}
// get the arguments string
String str = node.astArguments().first().toString();
if (!str.startsWith("\"SOME_PROPERTY\"")) {
context.report(ISSUE, node, context.getLocation(node), "message");
}
}
before this you have to define the specific method by override:
#Override
public List<String> getApplicableMethodNames() {
return Collections.singletonList("set");
}