is it possible to set a variable from an activity that an Espresso Test is running on? Because when I try to set a variable like:
activityRule.getActivity().mViewPager.setCurrentItem(1);
I get the error:
lStateException: Must be called from main thread of fragment host
You can do it like this:
#get:Rule
val intentsTestRule = ActivityTestRule(MainActivity::class.java, false, true)
#Before
fun start {
val intent = Intent().apply {
putExtra("value", 1)
}
intentsTestRule.launchActivity(intent)
}
and then in MainActivity:
if (intent.getIntExtra("value", 0)) {
//Do you stuff
}
Related
I was writing a kotin application that needs to retrive data online.
Using the async(Dispatcher.IO) to get the result from the server and
val variable1 = async(Dispatchers.IO) {
delay(10000)
"I am the guy who comes 10 secs later\nDid you miss me?"
}
using variable1.join() to wait for the result like shown below:
#ExperimentalCoroutinesApi
fun btn(view: android.view.View) {
binding.firstText.text = ""
runBlocking {
launch(Dispatchers.IO) {
//runOnUiThread { pop = popUp() }
val variable1 = async(Dispatchers.IO) {
delay(10000)
"I am the guy who comes 10 secs later\nDid you miss me?"
}
variable1.join()
val a = variable1.await()
Log.d(TAG, "btn: ******************************************************* $a")
runOnUiThread {
//binding.firstText.text = a
}
}
}
}
I have an issue getting the result asynchronously, variable1 keeps blocking the UI thread.
To my understanding, .join() waits for the result before executing. But the problem is that it blocks the UI thread even when its not run on the main thread.
How better should I have done this task? Thanks.
Since I see no evidence of any blocking operations, this is all you need:
fun btn(view: android.view.View) {
binding.firstText.text = ""
viewModelScope.launch {
delay(10_000)
val a = "I am the guy who comes 10 secs later\nDid you miss me?"
Log.d(TAG, "btn: $a")
binding.firstText.text = a
}
}
If you do intend to make blocking operations instead of that delay(10_000), then you can add this:
fun btn(view: android.view.View) {
binding.firstText.text = ""
viewModelScope.launch {
val a = withContext(Dispatchers.IO) {
blockingOperation()
"I am the guy who comes 10 secs later\nDid you miss me?"
}
Log.d(TAG, "btn: $a")
binding.firstText.text = a
}
}
Note there's the viewModelScope, this won't work unless you're inside a ViewModel class. You can use GlobalScope instead to try things out, but this is not a production-worthy solution as it leads to memory leaks at runtime whenever you trigger many such actions while the previous ones are in progress (and they will be because there's nothing cancelling them).
Is it possible to create a Dispatcher for the current thread? Check this sample code as an example of what I want to accomplish:
val dispatcher = if (parallel) {
Dispatcher.Default
} else {
// What should I write here so I just use the current thread to run doStuff?
}
val deferredList = list.map {
async(dispatcher) { doStuff(it) }
}
When you build a coroutine, you're passing a CoroutineContext as argument. If you don't pass anything, the new coroutine is built with the current CoroutineContext (its parent's context).
Instead of a Dispatcher you should aim to a CoroutineContext:
val context = if (parallel) {
Dispatchers.Default
} else {
coroutineContext
}
val deferredList = list.map {
async(context) { doStuff(it) }
}
You can also "extract" every Element of the context individually using the Element type as key:
Job: coroutineContext[Job]
Dispatcher: coroutineContext[ContinuationInterceptor]
ExceptionHandler: coroutineContext[CoroutineExceptionHandler]
Name: coroutineContext[CoroutineName]
Use Dispatchers.Unconfined, it's used exactly to run on a current thread.
The whole code will look as follows:
val dispatcher = if (parallel) Dispatcher.Default else Dispatchers.Unconfined
val deferredList = list.map {
async(dispatcher) { doStuff(it) }
}
I'm learning myself some android programming (beginning level) and following a tutorial. I'm getting an error when I run/build the project. Expecting member declaration. I've checked the code for typos and syntax errors. I've googled this, but I'm just not sure what it means or what to look for to fix it.
Are other classes used in the project automatically seen by the MainActivity class?
Code in part:
MainActivity.kt:
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
val friendlyDestroyer = Destroyer("Invincible")
val friendlyCarrier = Carrier("Indomitable")
val enemyDestroyer = Destroyer("Grey Death")
val enemyCarrier = Carrier("Big Grey Death")
val friendlyShipyard = ShipYard()
friendlyDestroyer.takeDamage(enemyDestroyer.shootShell())
friendlyDestroyer.takeDamage(enemyCarrier.launchAerialAttack())
// Fight back
enemyCarrier.takeDamage(friendlyCarrier.launchAerialAttack())
enemyCarrier.takeDamage(friendlyDestroyer.shootShell())
...
Any line that has an instance to a class with a function call shows the red squiggly line and the error.
In the line: friendlyDestroyer.takeDamage(enemyDestroyer.shootShell()), it shows the expecting member declaration error at just about every part of the line.
This happens on every instance of a class making a call to a class.
I'm not seeing any errors for the other classes/files.
Destroyer.kt:
package com.johndcowan.basicclasses
class Destroyer(name: String) {
// what is the name of the ship
var name: String = ""
private set
// what type of ship is it
// alwys a destroyer
val type = "Destroyer"
// how much the ship can take before sinking
private var hullIntegrity = 200
// how many shots left in the arsenal
var ammo = 1
// cannot be directly set externally
private set
// no external access whatsoever
private var shotPower = 60
// has the ship been sunk
private var sunk = false
// this code runs as the instance is being initialized
init {
// so we can use the name parameter
this.name = "$type $name"
}
fun takeDamage(damageTaken: Int) {
if (!sunk) {
hullIntegrity -= damageTaken
println("$name hull integrity = $hullIntegrity")
if (hullIntegrity <= 0){
println("Destroyer $name has been sunk")
sunk = true
}
} else {
// Already sunk
println("Error Ship does not exist")
}
}
fun shootShell():Int {
// let the calling code know how much damage to do
return if (ammo > 0) {
ammo--
shotPower
}else{
0
}
}
...
What am I missing or not seeing?
Thanks for any tips.
First of all, I'm new in Kotlin, so please be nice :).
It's also my first time posting on StackOverflow
I want to literally STOP the current thread that I created but nothing works.
I tried quit(), quitSafely(), interrupt() but nothing works.
I created a class (Data.kt), in which I create and initialize a Handler and HandlerThread as follows :
class Dispatch(private val label: String = "main") {
var handler: Handler? = null
var handlerThread: HandlerThread? = null
init {
if (label == "main") {
handlerThread = null
handler = Handler(Looper.getMainLooper())
} else {
handlerThread = HandlerThread(label)
handlerThread!!.start()
handler = Handler(handlerThread!!.looper)
}
}
fun async(runnable: Runnable) = handler!!.post(runnable)
fun async(block: () -> (Unit)) = handler!!.post(block)
fun asyncAfter(milliseconds: Long, function: () -> (Unit)) {
handler!!.postDelayed(function, milliseconds)
}
fun asyncAfter(milliseconds: Long, runnable: Runnable) {
handler!!.postDelayed(runnable, milliseconds)
}
companion object {
val main = Dispatch()
private val global = Dispatch("global")
//fun global() = global
}
}
And now, in my DataManager, I use these to do asynchronous things :
fun getSomething(forceNetwork: Boolean ) {
val queue1 = Dispatch("thread1") // Create a thread called "thread1"
queue1.async {
for (i in 0..2_000_000) {
print("Hello World")
// Do everything i want in the current thread
}
// And on the main thread I call my callback
Dispatch.main.async {
//callback?.invoke(.........)
}
}
}
Now, in my MainActivity, I made 2 buttons :
One for running the function getSomething()
The other one is used for switching to another Controller View :
val button = findViewById<Button>(R.id.button)
button.setOnClickListener {
DataManager.getSomething(true)
}
val button2 = findViewById<Button>(R.id.button2)
button2.setOnClickListener {
val intent = Intent(this, Test::class.java) // Switch to my Test Controller
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
startActivity(intent)
finish()
}
Is there a way to stop the thread, because when I switch to my second View, print("Hello World") is still triggered, unfortunately.
Thanks for helping me guys I hope that you understand !
A thread needs to periodically check a (global) flag and when it becomes true then the thread will break out from the loop. Java threads cannot be safely stopped without its consent.
Refer to page 252 here http://www.rjspm.com/PDF/JavaTheCompleteReference.pdf that describes the true story behind the legend.
I think that a truly interruptible thread is only possible through the support of the operating system kernel. The actual true lock is held deep down by the CPU hardware microprocessor.
I'm trying to do something rather simple. I would like to wrap the whole method code into an additional closure block that would measure the execution time. Right now I'm getting a really not helpful error message:
Error:Groovyc: NPE while processing Test.groovy
Annotation:
#Retention(RetentionPolicy.SOURCE)
#Target([ElementType.METHOD])
#GroovyASTTransformationClass(["WithTimingASTTransformation"])
public #interface WithTiming {
}
My wrapping closure:
class Benchmark {
static def measureTime(Closure cl) {
def start = System.currentTimeMillis()
def result = cl()
def time = System.currentTimeMillis() - start
println "it took $time"
result
}
}
My Transformation:
#GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
class WithTimingASTTransformation implements ASTTransformation {
#Override
void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
MethodNode method = astNodes[1]
method.code = wrap(method)
}
private Statement wrap(MethodNode method) {
def newBlock = new BlockStatement()
newBlock.addStatement(
new ExpressionStatement(
new StaticMethodCallExpression(
new ClassNode(Benchmark),
'measureTime',
new ArgumentListExpression(
new ClosureExpression(new Parameter[0], method.code)
))))
newBlock
}
}
I'm really stuck here and don't know how can I debug the problem.
There is an answer on a similar topic (wrapping whole method body into a try/catch block here). This works fine but my case is slightly different.
In my case similar NPE was coming from:
java.lang.NullPointerException
at org.codehaus.groovy.classgen.asm.ClosureWriter.createClosureClass(ClosureWriter.java:194)
at org.codehaus.groovy.classgen.asm.ClosureWriter.getOrAddClosureClass(ClosureWriter.java:159)
at org.codehaus.groovy.classgen.asm.ClosureWriter.writeClosure(ClosureWriter.java:90)
at org.codehaus.groovy.classgen.AsmClassGenerator.visitClosureExpression(AsmClassGenerator.java:673)
Whereas:
if (parameters == null || expression.getVariableScope() == null) {
parameters = Parameter.EMPTY_ARRAY;
} else if (parameters.length == 0) {
// let's create a default 'it' parameter
Parameter it = new Parameter(ClassHelper.OBJECT_TYPE, "it", ConstantExpression.NULL);
parameters = new Parameter[]{it};
Variable ref = expression.getVariableScope().getDeclaredVariable("it");
if (ref != null) it.setClosureSharedVariable(ref.isClosureSharedVariable());
}
and line 194 (as of https://github.com/groovy/groovy-core/commit/a52d0d3c5dd1cbb342992d36235171718a563c8b) is:
Variable ref = expression.getVariableScope().getDeclaredVariable("it");
Thus you need to define a VariableScope for your ClosureExpression. I had to add tracing into org.codehaus.groovy.ast.ClosureWriter to find this, because there is an issue with exception display on stage of Class Generation - both in IntelliJ Idea and in Groovy Console - it does not show proper lines of code.
Furthermore, I think that either ClosureWriter or ClosureExpression constructor can be fixed to work aligned by default - without this NPE. I will possibly submit an issue to Groovy Jira for this.
Now I am able to inject closure expression in my code. But struggling to call this closure.
Getting:
groovy.lang.MissingMethodException: No signature of method: com.a9ae0b01f0ffc.VSMSGEN.implementation.T_visa_recon_generator$_convert_vts_log_to_ctf_closure2.call() is applicable for argument types: () values: []
Long story short, after some iterations my method-wrapping AST looks like this:
BlockStatement bs = new BlockStatement()
ClosureExpression closureExp = new ClosureExpression( methodNode.parameters, methodNode.code )
closureExp.variableScope = new VariableScope() // <- this does the trick!
bs.addStatement new ExpressionStatement( new StaticMethodCallExpression( new ClassNode( TransactionUtil ), 'wrap', new ArgumentListExpression( closureExp ) ) )
methodNode.code = bs
The line closureExp.variableScope = new VariableScope() avoids the NPE in ClosureWriter.java:194 and the whole thing runs like a charm!
Hope it helps someone...