Vert.x Test halts with TimeoutException: The test execution timed out - kotlin

I'm using Vert.x 3.5.3. I have this (simple) Verticle:
class DialPadVerticle : AbstractVerticle() {
private companion object : KLogging()
override fun start(future: Future<Void>) {
vertx.eventBus().consumer(Address.DIALPAD_COMBINATIONS) { message: Message<Int> ->
val input = message.body()
logger.info { "Received: $input" }
message.reply(JsonObject().put("result", DialPad().combinations(input)))
}
future.complete()
}
override fun stop(future: Future<Void>) {
logger.debug { "Stopping ${this.javaClass.simpleName} (${deploymentID()})...DONE" }
future.complete()
}
}
...and I'm trying to build a unit test skeleton for it using the experimental (yet) vertx-junit5. So far, I have this:
#ExtendWith(VertxExtension::class)
#DisplayName("Dial pad verticle should...")
internal class DialPadVerticleTest {
#BeforeEach
fun prepare(vertx: Vertx, testContext: VertxTestContext) {
vertx.deployVerticle(DialPadVerticle(), testContext.succeeding())
}
#Test
#Throws(Exception::class)
#DisplayName("Consume Message<Int> correctly")
fun `consume message correctly`(vertx: Vertx, testContext: VertxTestContext) {
vertx.eventBus().send<JsonObject>(Address.DIALPAD_COMBINATIONS, 5) {
// Assertions.assertThat(it.succeeded()).isTrue()
testContext.verify {
testContext.completeNow()
}
}
}
}
But every time I try to run that from within IntelliJ, I'm getting:
java.util.concurrent.TimeoutException: The test execution timed out
at io.vertx.junit5.VertxExtension.joinActiveTestContexts(VertxExtension.java:213)
at io.vertx.junit5.VertxExtension.beforeTestExecution(VertxExtension.java:171)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeBeforeTestExecutionCallbacks$4(TestMethodTestDescriptor.java:141)
at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeMethodsOrCallbacksUntilExceptionOccurs(TestMethodTestDescriptor.java:155)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeTestExecutionCallbacks(TestMethodTestDescriptor.java:140)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:111)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:58)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:113)
at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:121)
at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
at java.util.Iterator.forEachRemaining(Iterator.java:116)
at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:121)
at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:121)
at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
at java.util.Iterator.forEachRemaining(Iterator.java:116)
at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:121)
at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:55)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:43)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:170)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:154)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:74)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Is this somehow a bug on the vertx-junit5 library? I've noticed also that, if the Verticles relies on some external config, even though I pass the correct DeploymentOptions().setConfig(JsonObject().put(...)) as second parameter to deployVerticle, it doesn't read those.

I ran your code and noticed that the execution never reached the test method.
You need to also close your context in #BeforeEach methods:
#BeforeEach
fun prepare(vertx: Vertx, testContext: VertxTestContext) {
vertx.deployVerticle(DialPadVerticle(), testContext.succeeding {
testContext.completeNow()
})
}
testContext.succeeding only provides a AsyncResult handler that checks that the result succeeded, but it does not mark the whole test context as having completed. It simplifies checking intermediary steps.
Now the test passes just fine!

Would you have a minimal reproducer project somewhere?

Related

Cannot successfully init controller by ControllerFactory that returns a kotlin singleton object in javafx

I have a javafx project and I want to access the main controller by kotlin singleton reference.
But the injection cannot succeed.
A minimal example on the below:
App.kt
class App: Application() {
override fun start(primaryStage: Stage) {
val loader = FXMLLoader(javaClass.getResource("Window.fxml")).also { it.setControllerFactory { Controller } }
val root = loader.load<Parent>()
val scene = Scene(root, 400.0, 600.0)
primaryStage.scene = scene
primaryStage.show()
}
fun main(vararg args: String) {
launch(*args)
}
}
Controller.kt
object Controller : Initializable {
#FXML private lateinit var button: Button
#FXML fun buttonAction() { println("Clicked") }
override fun initialize(location: URL?, resources: ResourceBundle?) {
button.text = "Click Me"
}
}
Window.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="Controller"
prefHeight="400.0" prefWidth="600.0">
<Button fx:id="button" onAction="#buttonAction"/>
</AnchorPane>
Then I got the Exception:
Exception in Application start method
Exception in thread "main" java.lang.RuntimeException: Exception in Application start method
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: javafx.fxml.LoadException:
/D:/WorkPlace/Kotlin/LabelPlusFX/target/test-classes/window.fxml
at javafx.fxml/javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2625)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2603)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2466)
at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:2435)
at DemoApp.start(DemoApp.kt:16)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
... 1 more
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property button has not been initialized
at Controller.initialize(Controller.kt:20)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2573)
... 12 more
Why cannot fxml do injection successfully?
Thanks to James_D.
The key to this problem is how kotlin compiles object singleton.
Kotlin chooses to make the singleton fields static, but FXMLLoader only looks for instance fields (not static) since JavaFX8. That's why cannot FXMLLoader does injection successfully.
Related Question
javafx-8-compatibility-issues-fxml-static-fields
Controller.kt
class Controller: View() {
override val root: AnchorPane by fxml("/fxml/Window.fxml",hasControllerAttribute = true)
#FXML
lateinit var button: Button
init{
button.text = "Click me"
}
fun buttonAction(){
println("Clicked")
}
}
App.kt
class MyApp: App(Controller::class){
override fun start(stage: Stage) {
super.start(stage)
}
}

Loading an image into a RecyclerView cell

override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
val itunesStoreItemTitle = itunes.results.get(position)
val imageURL = itunesStoreItemTitle.artworkUrl100
//val inputStream = URL(imageURL).openStream()
//val posterImage = BitmapFactory.decodeStream(inputStream)
holder?.view?.textView_iTunes_title?.text = itunesStoreItemTitle.collectionName
//holder?.view?.imageView_itunes?.setImageBitmap(posterImage)
holder?.view?.textView_iTunes_Description?.text = itunesStoreItemTitle.longDescription
}
from my MainActivity class
fun fetchJSON() {
println("Attempting to fetch JSON")
val url = URL(BASE_URL).addParameters(iTunesMap)
val request = Request.Builder().url(url).build()
val client = OkHttpClient()
client.newCall(request).enqueue(object: Callback {
override fun onResponse(call: Call, response: Response) {
val body = response?.body?.string()
val gson = GsonBuilder().create()
val iTunesFeed = gson.fromJson(body, iTunesFeed::class.java)
runOnUiThread {
recyclerView_main.adapter = MoshiAdapter(iTunesFeed)
}
println(body)
}
override fun onFailure(call: Call, e: IOException) {
println("Failed to fetch data")
}
})
}
I am trying to load images into my RecyclerView cell but it crashes on the first commented line.
CRASH LOG
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.oneorangetree.itunessearch, PID: 17091
android.os.NetworkOnMainThreadException
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1605)
at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:115)
at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:103)
at java.net.InetAddress.getAllByName(InetAddress.java:1152)
at com.android.okhttp.Dns$1.lookup(Dns.java:41)
at com.android.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:178)
at com.android.okhttp.internal.http.RouteSelector.nextProxy(RouteSelector.java:144)
at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:86)
at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:176)
at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:128)
at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:97)
at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:289)
at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:232)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:465)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:411)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:248)
at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getInputStream(DelegatingHttpsURLConnection.java:211)
at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:30)
at java.net.URL.openStream(URL.java:1072)
at com.oneorangetree.itunessearch.adapters.MoshiAdapter.onBindViewHolder(MoshiAdapter.kt:30)
at com.oneorangetree.itunessearch.adapters.MoshiAdapter.onBindViewHolder(MoshiAdapter.kt:14)
at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:7065)
at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:7107)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:6012)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6279)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6118)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6114)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2303)
at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1627)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:665)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4134)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3851)
at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4404)
at android.view.View.layout(View.java:22844)
at android.view.ViewGroup.layout(ViewGroup.java:6389)
at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1843)
at android.view.View.layout(View.java:22844)
at android.view.ViewGroup.layout(ViewGroup.java:6389)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at android.view.View.layout(View.java:22844)
at android.view.ViewGroup.layout(ViewGroup.java:6389)
at androidx.appcompat.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:530)
at android.view.View.layout(View.java:22844)
at android.view.ViewGroup.layout(ViewGroup.java:6389)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
E/AndroidRuntime: at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at android.view.View.layout(View.java:22844)
at android.view.ViewGroup.layout(ViewGroup.java:6389)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
at android.view.View.layout(View.java:22844)
at android.view.ViewGroup.layout(ViewGroup.java:6389)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at com.android.internal.policy.DecorView.onLayout(DecorView.java:784)
at android.view.View.layout(View.java:22844)
at android.view.ViewGroup.layout(ViewGroup.java:6389)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:3470)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2938)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1952)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8171)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:972)
at android.view.Choreographer.doCallbacks(Choreographer.java:796)
at android.view.Choreographer.doFrame(Choreographer.java:731)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
your issue is very clear, android.os.NetworkOnMainThreadException occurs when you try to access network on your main thread, please use Rx or AsyncTask to handle network request, refer RxAndroid

Android SettingsActivity popuate ListPreference programatically

How can I populate the items of a ListPreference programatically rather than statically from arrays.xml?
SettingsActivity.kt
class SettingsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.settings_activity)
supportFragmentManager
.beginTransaction()
.replace(R.id.settings, SettingsFragment())
.commit()
supportActionBar?.setDisplayHomeAsUpEnabled(true)
// Do something here to populate the ListPreference bluetoothName...
}
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
// ... or here?
// (WTF is a Fragment anyway?)
}
}
}
root_preferences.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.preference.ListPreference
app:dialogTitle="Select bluetooth adapter"
app:key="bluetoothName"
app:summary="%s"
app:title="Bluetooth adapter" />
<androidx.preference.ListPreference
app:dialogTitle="Select units"
app:entries="#array/units_names"
app:entryValues="#array/units_values"
app:key="units"
app:summary="%s"
app:title="Units"
/>
</androidx.preference.PreferenceScreen>
This seems to work for populating the items, but the app crashes when the user selects one
Process: com.rwb.psamfd, PID: 23596
java.lang.ArrayIndexOutOfBoundsException: length=0; index=1
at androidx.preference.ListPreferenceDialogFragmentCompat.onDialogClosed(ListPreferenceDialogFragmentCompat.java:105)
at androidx.preference.PreferenceDialogFragmentCompat.onDismiss(PreferenceDialogFragmentCompat.java:265)
at androidx.fragment.app.DialogFragment$3.onDismiss(DialogFragment.java:120)
at android.app.Dialog$ListenersHandler.handleMessage(Dialog.java:1323)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
and fuck knows what that means.
You seem to have to give the ListPreference an #array/ otherwise you get IllegalStateException: ListPreference requires an entries array and an entryValues array.
<androidx.preference.ListPreference
app:dialogTitle="Select bluetooth adapter"
app:key="bluetoothName"
app:entries="#array/empty"
app:entryValues="#array/empty"
app:summary="%s"
app:title="Bluetooth adapter" />
<string-array name="empty"></string-array>
class SettingsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// get bluetooth devices
var cs: Array<CharSequence> = arrayOf("")
try {
val bt: BluetoothManager =
getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager;
val bta: BluetoothAdapter = bt.adapter;
val pairedDevices: Set<BluetoothDevice> = bta.bondedDevices
cs = pairedDevices.map { z -> z.name }.toTypedArray()
}
catch(e:Exception) {}
// Start the fragment
setContentView(R.layout.settings_activity)
supportFragmentManager
.beginTransaction()
.replace(R.id.settings, SettingsFragment(cs))
.commit()
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
class SettingsFragment(adapters: Array<CharSequence>) : PreferenceFragmentCompat() {
private var adapters: Array<CharSequence> = adapters
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
val p:ListPreference? = findPreference<ListPreference>("bluetoothName")
p?.setEntries(adapters)
}
}
}
Turns out you need
p?.setEntryValues(adapters)
as well.

vertx-lang-kotlin-coroutines test failed

I have been writing a test class:
class TestVerticle {
#BeforeEach
fun deploy_verticle(vertx: Vertx, testContext: VertxTestContext) {
vertx.deployVerticle(Verticle(), testContext.completing())
}
#Test
fun test(vertx: Vertx, testContext: VertxTestContext) {
testContext.verify {
GlobalScope.launch(vertx.dispatcher()) {
val reply = vertx.eventBus().requestAwait<Long>(AVIOEXTDMZAddr, "1")
assert(reply.body() == 1010L)
testContext.completeNow()
}
}
}
}
If the method start() of Verticle is written in the "common" way, the Test is passed positively:
override suspend fun start() {
vertx.eventBus().consumer<String>(AVIOEXTDMZAddr){
it.reply(1010L)
}
}
Differently, if I implement a different solution, with the use of vertx-lang-kotlin-coroutines API, the test throws a java.util.concurrent.TimeoutException
override suspend fun start() {
val consumerChannel = vertx.eventBus().consumer<String>(AVIOEXTDMZAddr).toChannel(vertx)
for (msg in consumerChannel) {
msg.reply(1010L)
}
}
what am I doing wrong?
Loop on channel blocks the coroutine. In this case, it blocks start of your verticle.
Wrap your for loop in launch block:
async {
for (msg in consumerChannel) {
msg.reply(1010L)
}
}
}

Kotlin null pointer exception when trying to get context from Registar in Flutter

I'm trying to create a Flutter Plugin that uses a native Android sdk
I'm able to compile the .aar libraries of the sdk and use them in the project but the sdk requires me to get the context of the main activity
here is the error im getting
E/MethodChannel#mychart_plugin(16277): Failed to handle method call
E/MethodChannel#mychart_plugin(16277): kotlin.KotlinNullPointerException
E/MethodChannel#mychart_plugin(16277): at org.ccf.flutter.plugin.mychart_plugin.MychartPlugin.getContext(MychartPlugin.kt:79)
E/MethodChannel#mychart_plugin(16277): at epic.mychart.android.library.api.authentication.WPAPIAuthentication$1.getContext(WPAPIAuthentication.java:564)
E/MethodChannel#mychart_plugin(16277): at epic.mychart.android.library.prelogin.AuthenticationService.libraryLogin(AuthenticationService.java:461)
E/MethodChannel#mychart_plugin(16277): at epic.mychart.android.library.api.authentication.WPAPIAuthentication.login(WPAPIAuthentication.java:411)
E/MethodChannel#mychart_plugin(16277): at org.ccf.flutter.plugin.mychart_plugin.MychartPlugin.onMethodCall(MychartPlugin.kt:42)
E/MethodChannel#mychart_plugin(16277): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:201)
E/MethodChannel#mychart_plugin(16277): at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:88)
E/MethodChannel#mychart_plugin(16277): at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:219)
E/MethodChannel#mychart_plugin(16277): at android.os.MessageQueue.nativePollOnce(Native Method)
E/MethodChannel#mychart_plugin(16277): at android.os.MessageQueue.next(MessageQueue.java:325)
E/MethodChannel#mychart_plugin(16277): at android.os.Looper.loop(Looper.java:142)
E/MethodChannel#mychart_plugin(16277): at android.app.ActivityThread.main(ActivityThread.java:6541)
E/MethodChannel#mychart_plugin(16277): at java.lang.reflect.Method.invoke(Native Method)
E/MethodChannel#mychart_plugin(16277): at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
E/MethodChannel#mychart_plugin(16277): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
here is my code for getting the context
class MychartPlugin: MethodCallHandler, WPAPIAuthentication.IWPOnLoginListener {
private var registrar: PluginRegistry.Registrar? = null
private val LOGIN_REQUEST_CODE = 9876
fun MychartPlugin(registrar: PluginRegistry.Registrar) {
this.registrar = registrar
}
companion object {
#JvmStatic
fun registerWith(registrar: Registrar) {
val channel = MethodChannel(registrar.messenger(), "mychart_plugin")
channel.setMethodCallHandler(MychartPlugin())
}
}
override fun onMethodCall(call: MethodCall, result: Result) {
if (call.method == "getPlatformVersion") {
result.success("Android ${android.os.Build.VERSION.RELEASE}")
} else if (call.method == "MyChartSdkLogin") {
WPAPIAuthentication.login(this, "TURKJ123", "TurkJ123", LOGIN_REQUEST_CODE)
result.success("called MyChartSdkLogin")
} else {
result.notImplemented()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
// super.onActivityResult(requestCode, resultCode, data)
if (requestCode == LOGIN_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
// login successful
Log.i("LoginFragment", "OK")
} else {
// login failed
val result = WPAPIAuthentication.getLoginResult(data)
Log.i("LoginFragment", result.toString())
val errorMessage = result.getErrorMessage(getContext())
if (!errorMessage.isEmpty()) {
Toast.makeText(getContext(), errorMessage, Toast.LENGTH_LONG).show()
}
}
}
}
override fun startActivityForResult(p0: Intent, p1: Int) {
// super.startActivityForResult(p0, p1)
}
override fun getSupportFragmentManager(): FragmentManager {
val act = registrar!!.activity() as FragmentActivity
return act.getSupportFragmentManager()
}
override fun getContext(): Context {
val cxt = registrar!!.context()
return cxt
}
}
notice the override getContext() method that im overriding from the sdk, I think this context call to the registar is where my KotlinNullPointerException is coming from
In getContext you have registrar!!. And registrar is a nullable field which you initialize to null and can only set in a method which you never call. Note that fun MychartPlugin isn't a constructor, you'd call it as e.g.
val plugin = MychartPlugin()
plugin.MychartPlugin(registrar)
But it doesn't seem like there is any reason to make registrar nullable or mutable in the first place. You can change to
class MychartPlugin(private val registrar: Registrar): ...
and
fun registerWith(registrar: Registrar) {
val channel = MethodChannel(registrar.messenger(), "mychart_plugin")
channel.setMethodCallHandler(MychartPlugin(registrar))
}