Null pointer exception: Result must not be null in Fragment class - android-studio

I'm trying to implement a calculator in my multi-purpose app, but I've run into a small problem. I've implemented the calculator function in a Fragment class. Every time I click the Calculator fragment the whole app crashes.
Here's the code and got help with from a tutorial.
Calculator Fragment
package com.khumomashapa.notes.fragments
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.khumomashapa.notes.R
import com.khumomashapa.notes.helper.OperationsHelper
import kotlinx.android.synthetic.main.fragment_calculator.*
class CalculatorFragment : Fragment() {
var digit_on_screen = StringBuilder(12)
var operation: Char = ' '
var leftHandSide: Double = 0.0
var rightHandSide: Double = 0.0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
result_id.text = "0"
initializeButtons()
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_calculator, container, false)
}
private fun initializeButtons() {
functionalButtons()
operationalButtons()
numericalButtons()
}
/**
* This function initializes all of our numerical buttons from
* [0 - 9]
*/
private fun numericalButtons() {
one_btn.setOnClickListener {
appendToDigitOnScreen("1")
}
two_btn.setOnClickListener {
appendToDigitOnScreen("2")
}
three_btn.setOnClickListener {
appendToDigitOnScreen("3")
}
four_btn.setOnClickListener {
appendToDigitOnScreen("4")
}
five_btn.setOnClickListener {
appendToDigitOnScreen("5")
}
six_btn.setOnClickListener {
appendToDigitOnScreen("6")
}
seven_btn.setOnClickListener {
appendToDigitOnScreen("7")
}
eight_btn.setOnClickListener {
appendToDigitOnScreen("8")
}
nine_btn.setOnClickListener {
appendToDigitOnScreen("9")
}
zero_btn.setOnClickListener {
appendToDigitOnScreen("0")
}
dot_btn.setOnClickListener {
appendToDigitOnScreen(".")
}
}
/**
* Insert the button been clicked onto the screen so user can see
* inputs for the button clicked
*/
private fun appendToDigitOnScreen(digit: String) {
// Add each digit to our string builder
digit_on_screen.append(digit)
// display it on the screen of our mobile app
result_id.text = digit_on_screen.toString()
}
/**
* Initialize the operation keys in our calculator like the
* addition key, subtraction key and the likes
*/
private fun operationalButtons() {
addition_btn.setOnClickListener {
selectOperation('A')
}
subtract_btn.setOnClickListener {
selectOperation('S')
}
divide_btn.setOnClickListener {
selectOperation('D')
}
multipy_btn.setOnClickListener {
selectOperation('M')
}
}
/**
* Function to assign operational sign to our math calculations
*/
private fun selectOperation(c: Char) {
operation = c
leftHandSide = digit_on_screen.toString().toDouble()
digit_on_screen.clear()
result_id.text = "0"
}
/**
* Handles functional operations in out application like
* clear button, backspace button and the clear everything button
*/
private fun functionalButtons() {
clear_everything_btn.setOnClickListener {
digit_on_screen.clear()
result_id.text = "0"
}
clear_btn.setOnClickListener {
if (digit_on_screen.length <= 0) {
return#setOnClickListener
} else {
clearDigit()
}
}
backspace_btn.setOnClickListener {
if (digit_on_screen.length <= 0) {
return#setOnClickListener
} else {
clearDigit()
}
}
equal_btn.setOnClickListener {
performMathOperation()
}
}
/**
* This function performs our Math Operation which is then showed on the screen.
*/
private fun performMathOperation() {
rightHandSide = digit_on_screen.toString().toDouble()
when (operation) {
'A' -> {
val sum = OperationsHelper.add(leftHandSide, rightHandSide)
result_id.text = sum.toString()
digit_on_screen.clear()
digit_on_screen.append(sum)
}
'S' -> {
val subtract = OperationsHelper.subtract(leftHandSide, rightHandSide)
result_id.text = subtract.toString()
digit_on_screen.clear()
digit_on_screen.append(subtract)
}
'M' -> {
val multiply = OperationsHelper.multiply(leftHandSide, rightHandSide)
result_id.text = multiply.toString()
digit_on_screen.clear()
digit_on_screen.append(multiply)
}
'D' -> {
val divide = OperationsHelper.divide(leftHandSide, rightHandSide)
result_id.text = divide.toString()
digit_on_screen.clear()
digit_on_screen.append(divide)
}
}
}
/**
* This function remove the last digit on the screen.
*/
private fun clearDigit() {
val length = digit_on_screen.length
digit_on_screen.deleteCharAt(length - 1)
if (length <= 0) {
result_id.text = "0"
}else{
result_id.text = digit_on_screen.toString()
}
}
}
The Logcat
2021-03-28 11:25:35.688 25778-25778/? E/Zygote: isWhitelistProcess - Process is Whitelisted
2021-03-28 11:25:35.689 25778-25778/? E/Zygote: accessInfo : 1
2021-03-28 11:25:35.697 25778-25778/? I/momashapa.note: Late-enabling -Xcheck:jni
2021-03-28 11:25:35.716 25778-25778/? E/momashapa.note: Unknown bits set in runtime_flags: 0x8000
2021-03-28 11:25:35.724 25778-25778/? D/ActivityThread: setConscryptValidator
2021-03-28 11:25:35.724 25778-25778/? D/ActivityThread: setConscryptValidator - put
2021-03-28 11:25:36.122 25778-25778/com.khumomashapa.notes D/PhoneWindow: forceLight changed to true [] from com.android.internal.policy.PhoneWindow.updateForceLightNavigationBar:4274 com.android.internal.policy.DecorView.updateColorViews:1547 com.android.internal.policy.PhoneWindow.dispatchWindowAttributesChanged:3252 android.view.Window.setFlags:1153 com.android.internal.policy.PhoneWindow.generateLayout:2474
2021-03-28 11:25:36.123 25778-25778/com.khumomashapa.notes I/MultiWindowDecorSupport: [INFO] isPopOver = false
2021-03-28 11:25:36.123 25778-25778/com.khumomashapa.notes I/MultiWindowDecorSupport: updateCaptionType >> DecorView#ab7bf2e[], isFloating: false, isApplication: true, hasWindowDecorCaption: false, hasWindowControllerCallback: true
2021-03-28 11:25:36.123 25778-25778/com.khumomashapa.notes D/MultiWindowDecorSupport: setCaptionType = 0, DecorView = DecorView#ab7bf2e[]
2021-03-28 11:25:36.181 25778-25778/com.khumomashapa.notes W/momashapa.note: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (greylist, reflection, allowed)
2021-03-28 11:25:36.182 25778-25778/com.khumomashapa.notes W/momashapa.note: Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (greylist, reflection, allowed)
2021-03-28 11:25:36.403 25778-25778/com.khumomashapa.notes I/ViewRootImpl#32ff46b[MainActivity]: setView = com.android.internal.policy.DecorView#ab7bf2e TM=true MM=false
2021-03-28 11:25:36.445 25778-25778/com.khumomashapa.notes I/ViewRootImpl#32ff46b[MainActivity]: Relayout returned: old=(0,0,1080,2400) new=(0,0,1080,2400) req=(1080,2400)0 dur=15 res=0x7 s={true 507110252544} ch=true
2021-03-28 11:25:36.445 25778-27904/com.khumomashapa.notes D/OpenGLRenderer: createReliableSurface : 0x758376d580(0x7612206000)
2021-03-28 11:25:36.446 25778-27904/com.khumomashapa.notes I/AdrenoGLES: QUALCOMM build : eb230ec, I000594fe7d
Build Date : 04/01/20
OpenGL ES Shader Compiler Version: EV031.27.05.03
Local Branch :
Remote Branch : refs/tags/AU_LINUX_ANDROID_LA.UM.8.9.R1.10.00.00.558.065
Remote Branch : NONE
Reconstruct Branch : NOTHING
2021-03-28 11:25:36.446 25778-27904/com.khumomashapa.notes I/AdrenoGLES: Build Config : S P 8.0.12 AArch64
2021-03-28 11:25:36.451 25778-27904/com.khumomashapa.notes I/AdrenoGLES: PFP: 0x016ee187, ME: 0x00000000
2021-03-28 11:25:36.481 25778-27904/com.khumomashapa.notes D/OpenGLRenderer: makeCurrent EglSurface : 0x0 -> 0x0
2021-03-28 11:25:36.485 25778-27904/com.khumomashapa.notes D/OpenGLRenderer: eglCreateWindowSurface : 0x757f3dce80
2021-03-28 11:25:36.522 25778-27904/com.khumomashapa.notes D/OpenGLRenderer: makeCurrent EglSurface : 0x0 -> 0x757f3dce80
2021-03-28 11:25:36.527 25778-27904/com.khumomashapa.notes W/Gralloc3: mapper 3.x is not supported
2021-03-28 11:25:36.625 25778-25778/com.khumomashapa.notes I/ViewRootImpl#32ff46b[MainActivity]: MSG_WINDOW_FOCUS_CHANGED 1 1
2021-03-28 11:25:36.626 25778-25778/com.khumomashapa.notes D/InputMethodManager: prepareNavigationBarInfo() DecorView#ab7bf2e[MainActivity]
2021-03-28 11:25:36.626 25778-25778/com.khumomashapa.notes D/InputMethodManager: getNavigationBarColor() -855310
2021-03-28 11:25:36.633 25778-25778/com.khumomashapa.notes D/InputMethodManager: prepareNavigationBarInfo() DecorView#ab7bf2e[MainActivity]
2021-03-28 11:25:36.633 25778-25778/com.khumomashapa.notes D/InputMethodManager: getNavigationBarColor() -855310
2021-03-28 11:25:36.633 25778-25778/com.khumomashapa.notes V/InputMethodManager: Starting input: tba=com.khumomashapa.notes ic=null mNaviBarColor -855310 mIsGetNaviBarColorSuccess true , NavVisible : true , NavTrans : false
2021-03-28 11:25:36.633 25778-25778/com.khumomashapa.notes D/InputMethodManager: startInputInner - Id : 0
2021-03-28 11:25:36.633 25778-25778/com.khumomashapa.notes I/InputMethodManager: startInputInner - mService.startInputOrWindowGainedFocus
2021-03-28 11:25:36.647 25778-25778/com.khumomashapa.notes I/ViewRootImpl#32ff46b[MainActivity]: MSG_RESIZED: frame=(0,0,1080,2400) ci=(0,91,0,126) vi=(0,91,0,126) or=1
2021-03-28 11:25:36.655 25778-25778/com.khumomashapa.notes D/InputMethodManager: prepareNavigationBarInfo() DecorView#ab7bf2e[MainActivity]
2021-03-28 11:25:36.655 25778-25778/com.khumomashapa.notes D/InputMethodManager: getNavigationBarColor() -855310
2021-03-28 11:25:36.655 25778-25778/com.khumomashapa.notes V/InputMethodManager: Starting input: tba=com.khumomashapa.notes ic=null mNaviBarColor -855310 mIsGetNaviBarColorSuccess true , NavVisible : true , NavTrans : false
2021-03-28 11:25:36.656 25778-25778/com.khumomashapa.notes D/InputMethodManager: startInputInner - Id : 0
2021-03-28 11:25:37.295 25778-25778/com.khumomashapa.notes I/ViewRootImpl#32ff46b[MainActivity]: ViewPostIme pointer 0
2021-03-28 11:25:37.334 25778-25778/com.khumomashapa.notes I/ViewRootImpl#32ff46b[MainActivity]: ViewPostIme pointer 1
2021-03-28 11:25:37.363 25778-25778/com.khumomashapa.notes D/AndroidRuntime: Shutting down VM
2021-03-28 11:25:37.364 25778-25778/com.khumomashapa.notes E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.khumomashapa.notes, PID: 25778
java.lang.NullPointerException: result_id must not be null
at com.khumomashapa.notes.fragments.CalculatorFragment.onCreate(CalculatorFragment.kt:22)
at androidx.fragment.app.Fragment.performCreate(Fragment.java:2586)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:838)
at androidx.fragment.app.FragmentTransition.addToFirstInLastOut(FragmentTransition.java:1197)
at androidx.fragment.app.FragmentTransition.calculateFragments(FragmentTransition.java:1080)
at androidx.fragment.app.FragmentTransition.startTransitions(FragmentTransition.java:119)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1866)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
at androidx.fragment.app.FragmentManagerImpl$2.run(FragmentManagerImpl.java:150)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:237)
at android.app.ActivityThread.main(ActivityThread.java:8167)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)
2021-03-28 11:25:37.385 25778-25778/com.khumomashapa.notes I/Process: Sending signal. PID: 25778 SIG: 9

For a fragment, onCreate gets called before your view is created. The lifecycle method you should be considering is onViewCreated which namely guarantees the view hierarchy has been created by this point.
You can take a look in more detail about the fragment lifecycle in the documentation.

Related

JHipster Integration Tests with LocalStack testcontainers

I have a JHipster (7.9.3) application with Kafka and Postgres TestContainers used in the integration tests. I want to integrate my application with S3 storage. For this purpose, I want to write some Integration tests using LocalStack testcontainer.
I have created a new annotation:
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface EmbeddedS3 {
}
and added localstack dependency to the project:
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>localstack</artifactId>
<scope>test</scope>
</dependency>
created a LocalStackTestContainer as:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.testcontainers.containers.localstack.LocalStackContainer;
import org.testcontainers.containers.output.Slf4jLogConsumer;
import org.testcontainers.utility.DockerImageName;
public class LocalStackTestContainer implements InitializingBean, DisposableBean {
private LocalStackContainer localStackContainer;
private static final Logger log = LoggerFactory.getLogger(LocalStackTestContainer.class);
#Override
public void destroy() {
if (null != localStackContainer) {
localStackContainer.close();
}
}
#Override
public void afterPropertiesSet() {
if (null == localStackContainer) {
localStackContainer =
new LocalStackContainer(DockerImageName.parse("localstack/localstack:1.2.0"))
.withServices(LocalStackContainer.Service.S3)
.withLogConsumer(new Slf4jLogConsumer(log))
.withReuse(true)
;
}
if (!localStackContainer.isRunning()) {
localStackContainer.start();
}
}
public LocalStackContainer getLocalStackContainer() {
return localStackContainer;
}
}
and adjusted TestContainersSpringContextCustomizerFactory.createContextCustomizer method with:
EmbeddedS3 s3LocalStackAnnotation = AnnotatedElementUtils.findMergedAnnotation(testClass, EmbeddedS3.class);
if (null != s3LocalStackAnnotation) {
log.debug("detected the EmbeddedS3 annotation on class {}", testClass.getName());
log.info("Warming up the localstack S3");
if (null == localStackTestContainer) {
localStackTestContainer = beanFactory.createBean(LocalStackTestContainer.class);
beanFactory.registerSingleton(LocalStackTestContainer.class.getName(), localStackTestContainer);
// ((DefaultListableBeanFactory) beanFactory).registerDisposableBean(LocalStackTestContainer.class.getName(), localStackTestContainer);
}
}
Added #EmbeddedS3 annotation to the #IntegrationTest annotation as:
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#SpringBootTest(classes = {AgentMarlinApp.class, AsyncSyncConfiguration.class, TestSecurityConfiguration.class, TestLocalStackConfiguration.class})
#EmbeddedKafka
#EmbeddedSQL
#EmbeddedS3
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
#ActiveProfiles({"testdev", "it-test"})
public #interface IntegrationTest {
// 5s is the spring default https://github.com/spring-projects/spring-framework/blob/29185a3d28fa5e9c1b4821ffe519ef6f56b51962/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClient.java#L106
String DEFAULT_TIMEOUT = "PT5S";
String DEFAULT_ENTITY_TIMEOUT = "PT5S";
}
To initialize AmazonS3 client I have #TestConfiguration:
#Bean
public AmazonS3 amazonS3(LocalStackTestContainer localStackTestContainer) {
LocalStackContainer localStack = localStackTestContainer.getLocalStackContainer();
return AmazonS3ClientBuilder
.standard()
.withEndpointConfiguration(
new AwsClientBuilder.EndpointConfiguration(
localStack.getEndpointOverride(LocalStackContainer.Service.S3).toString(),
localStack.getRegion()
)
)
.withCredentials(
new AWSStaticCredentialsProvider(
new BasicAWSCredentials(localStack.getAccessKey(), localStack.getSecretKey())
)
)
.build();
}
I have 2 integration classes (ending with *IT), when first class tests are executed I see that testcontainers are started
2022-10-30 14:34:42.031 DEBUG 27208 --- [ main] 🐳 [testcontainers/ryuk:0.3.3] : Starting container: testcontainers/ryuk:0.3.3
2022-10-30 14:34:42.032 DEBUG 27208 --- [ main] 🐳 [testcontainers/ryuk:0.3.3] : Trying to start container: testcontainers/ryuk:0.3.3 (attempt 1/1)
2022-10-30 14:34:42.033 DEBUG 27208 --- [ main] 🐳 [testcontainers/ryuk:0.3.3] : Starting container: testcontainers/ryuk:0.3.3
2022-10-30 14:34:42.033 INFO 27208 --- [ main] 🐳 [testcontainers/ryuk:0.3.3] : Creating container for image: testcontainers/ryuk:0.3.3
2022-10-30 14:34:42.371 INFO 27208 --- [ main] 🐳 [testcontainers/ryuk:0.3.3] : Container testcontainers/ryuk:0.3.3 is starting: 5505472cec1608db3383ebeeee99a8d02b48331a53f5d53613a0a53c1cd51986
2022-10-30 14:34:43.271 INFO 27208 --- [ main] 🐳 [testcontainers/ryuk:0.3.3] : Container testcontainers/ryuk:0.3.3 started in PT1.2706326S
2022-10-30 14:34:43.282 INFO 27208 --- [ main] o.t.utility.RyukResourceReaper : Ryuk started - will monitor and terminate Testcontainers containers on JVM exit
2022-10-30 14:34:43.283 INFO 27208 --- [ main] org.testcontainers.DockerClientFactory : Checking the system...
2022-10-30 14:34:43.283 INFO 27208 --- [ main] org.testcontainers.DockerClientFactory : βœ”οΈŽ Docker server version should be at least 1.6.0
2022-10-30 14:34:43.284 INFO 27208 --- [ main] 🐳 [localstack/localstack:1.2.0] : HOSTNAME_EXTERNAL environment variable set to localhost (to match host-routable address for container)
2022-10-30 14:34:43.284 DEBUG 27208 --- [ main] 🐳 [localstack/localstack:1.2.0] : Starting container: localstack/localstack:1.2.0
2022-10-30 14:34:43.285 DEBUG 27208 --- [ main] 🐳 [localstack/localstack:1.2.0] : Trying to start container: localstack/localstack:1.2.0 (attempt 1/1)
2022-10-30 14:34:43.285 DEBUG 27208 --- [ main] 🐳 [localstack/localstack:1.2.0] : Starting container: localstack/localstack:1.2.0
2022-10-30 14:34:43.285 INFO 27208 --- [ main] 🐳 [localstack/localstack:1.2.0] : Creating container for image: localstack/localstack:1.2.0
2022-10-30 14:34:44.356 WARN 27208 --- [ main] 🐳 [localstack/localstack:1.2.0] : Reuse was requested but the environment does not support the reuse of containers
To enable reuse of containers, you must set 'testcontainers.reuse.enable=true' in a file located at C:\Users\artjo\.testcontainers.properties
2022-10-30 14:34:44.581 INFO 27208 --- [ main] 🐳 [localstack/localstack:1.2.0] : Container localstack/localstack:1.2.0 is starting: d09c4e105058444699a29338b85d7294efec29941857e581daf634d391395869
2022-10-30 14:34:48.321 INFO 27208 --- [ main] 🐳 [localstack/localstack:1.2.0] : Container localstack/localstack:1.2.0 started in PT5.0370436S
2022-10-30 14:34:48.321 INFO 27208 --- [ main] ContainersSpringContextCustomizerFactory : Warming up the sql database
2022-10-30 14:34:48.327 DEBUG 27208 --- [ main] 🐳 [postgres:14.5] : Starting container: postgres:14.5
2022-10-30 14:34:48.327 DEBUG 27208 --- [ main] 🐳 [postgres:14.5] : Trying to start container: postgres:14.5 (attempt 1/1)
2022-10-30 14:34:48.327 DEBUG 27208 --- [ main] 🐳 [postgres:14.5] : Starting container: postgres:14.5
2022-10-30 14:34:48.327 INFO 27208 --- [ main] 🐳 [postgres:14.5] : Creating container for image: postgres:14.5
2022-10-30 14:34:48.328 WARN 27208 --- [ main] 🐳 [postgres:14.5] : Reuse was requested but the environment does not support the reuse of containers
To enable reuse of containers, you must set 'testcontainers.reuse.enable=true' in a file located at C:\Users\artjo\.testcontainers.properties
2022-10-30 14:34:48.415 INFO 27208 --- [ main] 🐳 [postgres:14.5] : Container postgres:14.5 is starting: 5e4fcf583b44345651aad9d5f939bc913d62eafe16a73017379c9e43f2028ff4
But when the second IT test is started the LocalStackTestContainer bean is not available anymore.
How do I need to configure this so localstack container bean remain available during all the tests execution?
######################## UPDATE 01.11.2022 ########################
Other testcontainers are configured the same way (no changes from the auto generated code)
public class TestContainersSpringContextCustomizerFactory implements ContextCustomizerFactory {
private Logger log = LoggerFactory.getLogger(TestContainersSpringContextCustomizerFactory.class);
private static LocalStackTestContainer localStackTestContainer;
private static KafkaTestContainer kafkaBean;
private static SqlTestContainer devTestContainer;
private static SqlTestContainer prodTestContainer;
#Override
public ContextCustomizer createContextCustomizer(Class<?> testClass, List<ContextConfigurationAttributes> configAttributes) {
return (context, mergedConfig) -> {
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
TestPropertyValues testValues = TestPropertyValues.empty();
// EmbeddedS3 s3LocalStackAnnotation = AnnotatedElementUtils.findMergedAnnotation(testClass, EmbeddedS3.class);
// if (null != s3LocalStackAnnotation) {
// log.debug("detected the EmbeddedS3 annotation on class {}", testClass.getName());
// log.info("Warming up the localstack S3");
//
// if (null == localStackTestContainer) {
// localStackTestContainer = beanFactory.createBean(LocalStackTestContainer.class);
// beanFactory.registerSingleton(LocalStackTestContainer.class.getName(), localStackTestContainer);
//// ((DefaultListableBeanFactory) beanFactory).registerDisposableBean(LocalStackTestContainer.class.getName(), localStackTestContainer);
// }
// }
EmbeddedSQL sqlAnnotation = AnnotatedElementUtils.findMergedAnnotation(testClass, EmbeddedSQL.class);
if (null != sqlAnnotation) {
log.debug("detected the EmbeddedSQL annotation on class {}", testClass.getName());
log.info("Warming up the sql database");
if (
Arrays
.asList(context.getEnvironment().getActiveProfiles())
.contains("test" + JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)
) {
if (null == devTestContainer) {
try {
Class<? extends SqlTestContainer> containerClass = (Class<? extends SqlTestContainer>) Class.forName(
this.getClass().getPackageName() + ".PostgreSqlTestContainer"
);
devTestContainer = beanFactory.createBean(containerClass);
beanFactory.registerSingleton(containerClass.getName(), devTestContainer);
// ((DefaultListableBeanFactory)beanFactory).registerDisposableBean(containerClass.getName(), devTestContainer);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
testValues =
testValues.and(
"spring.r2dbc.url=" + devTestContainer.getTestContainer().getJdbcUrl().replace("jdbc", "r2dbc") + ""
);
testValues = testValues.and("spring.r2dbc.username=" + devTestContainer.getTestContainer().getUsername());
testValues = testValues.and("spring.r2dbc.password=" + devTestContainer.getTestContainer().getPassword());
testValues = testValues.and("spring.liquibase.url=" + devTestContainer.getTestContainer().getJdbcUrl() + "");
}
if (
Arrays
.asList(context.getEnvironment().getActiveProfiles())
.contains("test" + JHipsterConstants.SPRING_PROFILE_PRODUCTION)
) {
if (null == prodTestContainer) {
try {
Class<? extends SqlTestContainer> containerClass = (Class<? extends SqlTestContainer>) Class.forName(
this.getClass().getPackageName() + ".PostgreSqlTestContainer"
);
prodTestContainer = beanFactory.createBean(containerClass);
beanFactory.registerSingleton(containerClass.getName(), prodTestContainer);
// ((DefaultListableBeanFactory)beanFactory).registerDisposableBean(containerClass.getName(), prodTestContainer);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
testValues =
testValues.and(
"spring.r2dbc.url=" + prodTestContainer.getTestContainer().getJdbcUrl().replace("jdbc", "r2dbc") + ""
);
testValues = testValues.and("spring.r2dbc.username=" + prodTestContainer.getTestContainer().getUsername());
testValues = testValues.and("spring.r2dbc.password=" + prodTestContainer.getTestContainer().getPassword());
testValues = testValues.and("spring.liquibase.url=" + prodTestContainer.getTestContainer().getJdbcUrl() + "");
}
}
EmbeddedKafka kafkaAnnotation = AnnotatedElementUtils.findMergedAnnotation(testClass, EmbeddedKafka.class);
if (null != kafkaAnnotation) {
log.debug("detected the EmbeddedKafka annotation on class {}", testClass.getName());
log.info("Warming up the kafka broker");
if (null == kafkaBean) {
kafkaBean = beanFactory.createBean(KafkaTestContainer.class);
beanFactory.registerSingleton(KafkaTestContainer.class.getName(), kafkaBean);
// ((DefaultListableBeanFactory)beanFactory).registerDisposableBean(KafkaTestContainer.class.getName(), kafkaBean);
}
testValues =
testValues.and(
"spring.cloud.stream.kafka.binder.brokers=" +
kafkaBean.getKafkaContainer().getHost() +
':' +
kafkaBean.getKafkaContainer().getMappedPort(KafkaContainer.KAFKA_PORT)
);
}
testValues.applyTo(context);
};
}
}
######################## UPDATE 02.11.2022 ########################
Reproducible example project can be found here GITHUB

Why do I need to wrap navActions.navigateToPurchase() with LaunchedEffect in fun NavGraph when use Jetpack Compose?

In my plan, I hope to display Home UI when I run an app first, a user can open Purchase UI by clicking a button on Home UI. And more, Purchase UI will be displayed automatically if the app is expired when I run the app first.
In Code A, navActions.navigateToPurchase() is invoked in both fun NavGraph(...) and fun ScreenHome(...).
The app will crash if I don't wrap navActions.navigateToPurchase() with LaunchedEffect in fun NavGraph(), why? You can see Error Logs below.
Code A
#Composable
fun NavGraph(
modifier: Modifier = Modifier,
navController: NavHostController = rememberNavController(),
navActions: NavigationActions = remember(navController) { NavigationActions(navController) },
startDestination: String = RouteDestinations.HOME
) {
val currentNavBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = currentNavBackStackEntry?.destination?.route ?: startDestination
NavHost(
navController = navController,
startDestination = startDestination,
modifier = modifier
) {
composable(
RouteDestinations.HOME
) {
if (isAppExpired(LocalContext.current)) {
LaunchedEffect(Unit) {
navActions.navigateToPurchase()
}
} else {
ScreenHome(
navActions = navActions
)
}
}
composable(
RouteDestinations.PURCHASE
) { entry ->
ScreenPurchase(
onBack = { navController.popBackStack() }
)
}
}
}
#Composable
fun ScreenHome(
navActions: NavigationActions
) {
Button(
onClick = { navActions.navigateToPurchase() }
) {
Text("Nav to Purchase")
}
}
class NavigationActions(private val navController: NavHostController) {
fun navigateToHome(){
navController.navigate(RouteDestinations.HOME)
}
fun navigateToPurchase(){
navController.navigate(RouteDestinations.PURCHASE)
}
}
class ActivityMain : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
SoundMeterTheme {
Surface(color = MaterialTheme.colors.background) {
NavGraph()
}
}
}
}
}
Error Logs
2022-08-01 19:26:54.271 5611-5655/info.dodata.soundmeter E/cr_VariationsUtils: Failed reading seed file "/data/user/0/info.dodata.soundmeter/app_webview/variations_seed": /data/user/0/info.dodata.soundmeter/app_webview/variations_seed (No such file or directory)
2022-08-01 19:26:54.500 5611-5698/info.dodata.soundmeter E/chromium: [ERROR:gl_surface_egl.cc(335)] eglChooseConfig failed with error EGL_SUCCESS
2022-08-01 19:26:55.288 5611-5704/info.dodata.soundmeter E/eglCodecCommon: GoldfishAddressSpaceHostMemoryAllocator: ioctl_ping failed for device_type=5, ret=-1
2022-08-01 19:26:55.510 5611-5698/info.dodata.soundmeter E/chromium: [ERROR:gl_surface_egl.cc(335)] eglChooseConfig failed with error EGL_SUCCESS
2022-08-01 19:26:55.624 5611-5611/info.dodata.soundmeter E/AndroidRuntime: FATAL EXCEPTION: main
Process: info.dodata.soundmeter, PID: 5611
java.util.NoSuchElementException: List contains no element matching the predicate.
at androidx.navigation.compose.NavHostKt$NavHost$4.invoke(NavHost.kt:180)
at androidx.navigation.compose.NavHostKt$NavHost$4.invoke(NavHost.kt:141)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.animation.CrossfadeKt$Crossfade$4$1.invoke(Crossfade.kt:115)
at androidx.compose.animation.CrossfadeKt$Crossfade$4$1.invoke(Crossfade.kt:110)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.animation.CrossfadeKt.Crossfade(Crossfade.kt:124)
at androidx.compose.animation.CrossfadeKt.Crossfade(Crossfade.kt:55)
at androidx.navigation.compose.NavHostKt.NavHost(NavHost.kt:141)
at androidx.navigation.compose.NavHostKt.NavHost(NavHost.kt:67)
at info.dodata.soundmeter.presentation.ui.NavGraphKt.NavGraph(NavGraph.kt:38)
at info.dodata.soundmeter.presentation.ui.NavGraphKt$NavGraph$3.invoke(Unknown Source:21)
at info.dodata.soundmeter.presentation.ui.NavGraphKt$NavGraph$3.invoke(Unknown Source:10)
at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:157)
at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2270)
at androidx.compose.runtime.ComposerImpl.skipCurrentGroup(Composer.kt:2530)
at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3038)
at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3024)
at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:252)
at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown Source:1)
at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3024)
at androidx.compose.runtime.ComposerImpl.recompose$runtime_release(Composer.kt:2999)
at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:709)
at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:876)
at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:107)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:485)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:454)
at androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame(AndroidUiFrameClock.android.kt:34)
at androidx.compose.ui.platform.AndroidUiDispatcher.performFrameDispatch(AndroidUiDispatcher.android.kt:109)
at androidx.compose.ui.platform.AndroidUiDispatcher.access$performFrameDispatch(AndroidUiDispatcher.android.kt:41)
at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame(AndroidUiDispatcher.android.kt:69)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:947)
at android.view.Choreographer.doCallbacks(Choreographer.java:761)
at android.view.Choreographer.doFrame(Choreographer.java:693)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:935)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [androidx.compose.runtime.PausableMonotonicFrameClock#186f44, StandaloneCoroutine{Cancelling}#ee6482d, AndroidUiDispatcher#1d8a162]
for my simple knowledge, the navigate function need to be called in the function or click event, navActions.navigateToPurchase() was not called in any of the above, because function marked Composable is not like normal function or click event, that is why LauchEffect is used as side effect for such scenarios as explained by jetpack compose tutorials on google developer guide

Insert in middle of a Object in nodeJS

I have a object and I need insert a object in the middle.
I tried a push and sort, but dosenΒ΄t work...
this is my code:
let myObject = [
{
'item1' : 'string1',
'item2' : 'string2',
'item3' : 'string3',
'item4' : 'string4',
'item5' : 'string5',
'item6' : 'string6',
'item7' : 'string7',
'item8' : 'string8',
'item10' : 'string10',
'item11' : 'string11',
'item12' : 'string12',
'item14' : 'string14',
'item15' : 'string15'
},
{
'item16' : 'string16',
'item17' : 'string17',
'item18' : 'string18',
'item19' : 'string19',
'item20' : 'string20',
'item21' : 'string21',
'item22' : 'string22',
'item23' : 'string23',
'item25' : 'string25',
'item26' : 'string26',
'item27' : 'string27',
'item29' : 'string29',
'item30' : 'string30'
}
]
myObject[0].item9 = 'string9'
myObject[0].item13 = 'string13'
console.log(myObject[0])
//OUTPUT
// {
// item1: 'string1',
// item2: 'string2',
// item3: 'string3',
// item4: 'string4',
// item5: 'string5',
// item6: 'string6',
// item7: 'string7',
// item8: 'string8',
// item10: 'string10',
// item11: 'string11',
// item12: 'string12',
// item14: 'string14',
// item15: 'string15',
// item9: 'string9',
// item13: 'string13'
// }
myObject = Object.fromEntries(Object.entries(myObject[0]).sort())
console.log(myObject)
//OUTPUT
// {
// item1: 'string1',
// item10: 'string10',
// item11: 'string11',
// item12: 'string12',
// item13: 'string13',
// item14: 'string14',
// item15: 'string15',
// item2: 'string2',
// item3: 'string3',
// item4: 'string4',
// item5: 'string5',
// item6: 'string6',
// item7: 'string7',
// item8: 'string8',
// item9: 'string9'
// }
How can I do that OUTPUT:
{
item1: 'string1',
item2: 'string2',
item3: 'string3',
item4: 'string4',
item5: 'string5',
item6: 'string6',
item7: 'string7',
item8: 'string8',
item9: 'string9',
item10: 'string10',
item11: 'string11',
item12: 'string12',
item13: 'string13',
item14: 'string14',
item15: 'string15'
}
That would be a solution that came to my head but i'm sure that there is a more efficient and sexy solution to this problem. The problem is that you would need to convert it back to an object from the array. Should work, I didn't came to test it just wrote it quick in my notepad :).
let myObject = [
{
'item1' : 'string1',
'item2' : 'string2',
'item3' : 'string3',
'item4' : 'string4',
'item5' : 'string5',
'item6' : 'string6',
'item7' : 'string7',
'item8' : 'string8',
'item10' : 'string10',
'item11' : 'string11',
'item12' : 'string12',
'item14' : 'string14',
'item15' : 'string15'
},
{
'item16' : 'string16',
'item17' : 'string17',
'item18' : 'string18',
'item19' : 'string19',
'item20' : 'string20',
'item21' : 'string21',
'item22' : 'string22',
'item23' : 'string23',
'item25' : 'string25',
'item26' : 'string26',
'item27' : 'string27',
'item29' : 'string29',
'item30' : 'string30'
}
]
var result = Object.keys(myObject[0]).map(e => ({item: e, string: myObject[0][e]}))
result.splice(8, 0, {item: 'item9', word: 'string9'});
result.splice(12, 0, {item: 'item13', word: 'string13'});
//result would be an array of objects with params 'item' and 'array'
console.log(result)

Dart Map and Parsing JSON

As a new Dart Fan, I would like to understand the concept of Map/List.
I tried to do HTTP requests, getting JSON data. And it's ok till I have to assign to the Map.
Let me show you the example of JSON data:
{
"error":"",
"error_number":"",
"response_code":200,
"result":[
{
"id":1,
"name":"Great Deal",
"day_aired":"2015-07-05 11:06:09",
"trend":"Noone",
"trend_details": [{
"name":"Great Deal",
}
]
},
{
"id":2,
....
}
]
}
The code:
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<ApiResponse> fetchData(String command, Map params) async {
final String url =
'https://example.com/api/v2/....';
final response = await http.get(url);
if (response.statusCode == 200) {
return ApiResponse.fromJson(json.decode(response.body));
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load post');
}
}
}
final response = await http.get(url);
dynamic data = json.decode(response.body);
List<String> parsed = data['result'] as List<String>;
// List<String> parsedList = new List<String>.from(parsed);
if (response.statusCode == 200) {
//return json.decode(response.body);
List<ApiResponse> list = List<ApiResponse>.from(
parsed.map((i) => ApiResponse.fromJson(i as Map<String, dynamic>)));
}
I do the same as this article. But I read this article too. I'm trying to create Future<ApiResponse> with data from json.decode(response.body) (result entry inside of it).
factory ApiResponse.fromJson(Map<String, dynamic> json) {...}
But as I understand, result is not Map<String, dynamic> but when I try to invoke the code below it says:
Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'List<String>' in type cast and it referred to List<String> parsed = data['result'] as List<String>;.
I'm confused and I know the code is a mess. I read in the second article that I should do an additional cast to trend_details but it did not work as I expected. Obviously data['result'] is an array but how to cast it properly? What are the good practices?
result stores a list of Map<String, dynamic>
final parsed = data['result'] as List<Map<String, dynamic>>;
You can parse json string with the following structure and code
You can see picture display correct result name
code snippet
var payload = payloadFromJson(jsonStr);
print('${payload.result[0].name}');
related class
// To parse this JSON data, do
//
// final payload = payloadFromJson(jsonString);
import 'dart:convert';
Payload payloadFromJson(String str) => Payload.fromJson(json.decode(str));
String payloadToJson(Payload data) => json.encode(data.toJson());
class Payload {
String error;
String errorNumber;
int responseCode;
List<Result> result;
Payload({
this.error,
this.errorNumber,
this.responseCode,
this.result,
});
factory Payload.fromJson(Map<String, dynamic> json) => Payload(
error: json["error"] == null ? null : json["error"],
errorNumber: json["error_number"] == null ? null : json["error_number"],
responseCode: json["response_code"] == null ? null : json["response_code"],
result: json["result"] == null ? null : List<Result>.from(json["result"].map((x) => Result.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"error": error == null ? null : error,
"error_number": errorNumber == null ? null : errorNumber,
"response_code": responseCode == null ? null : responseCode,
"result": result == null ? null : List<dynamic>.from(result.map((x) => x.toJson())),
};
}
class Result {
int id;
String name;
DateTime dayAired;
String trend;
List<TrendDetail> trendDetails;
Result({
this.id,
this.name,
this.dayAired,
this.trend,
this.trendDetails,
});
factory Result.fromJson(Map<String, dynamic> json) => Result(
id: json["id"] == null ? null : json["id"],
name: json["name"] == null ? null : json["name"],
dayAired: json["day_aired"] == null ? null : DateTime.parse(json["day_aired"]),
trend: json["trend"] == null ? null : json["trend"],
trendDetails: json["trend_details"] == null ? null : List<TrendDetail>.from(json["trend_details"].map((x) => TrendDetail.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"id": id == null ? null : id,
"name": name == null ? null : name,
"day_aired": dayAired == null ? null : dayAired.toIso8601String(),
"trend": trend == null ? null : trend,
"trend_details": trendDetails == null ? null : List<dynamic>.from(trendDetails.map((x) => x.toJson())),
};
}
class TrendDetail {
String name;
TrendDetail({
this.name,
});
factory TrendDetail.fromJson(Map<String, dynamic> json) => TrendDetail(
name: json["name"] == null ? null : json["name"],
);
Map<String, dynamic> toJson() => {
"name": name == null ? null : name,
};
}
full code
import 'package:flutter/material.dart';
// To parse this JSON data, do
//
// final payload = payloadFromJson(jsonString);
import 'dart:convert';
Payload payloadFromJson(String str) => Payload.fromJson(json.decode(str));
String payloadToJson(Payload data) => json.encode(data.toJson());
class Payload {
String error;
String errorNumber;
int responseCode;
List<Result> result;
Payload({
this.error,
this.errorNumber,
this.responseCode,
this.result,
});
factory Payload.fromJson(Map<String, dynamic> json) => Payload(
error: json["error"] == null ? null : json["error"],
errorNumber: json["error_number"] == null ? null : json["error_number"],
responseCode: json["response_code"] == null ? null : json["response_code"],
result: json["result"] == null ? null : List<Result>.from(json["result"].map((x) => Result.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"error": error == null ? null : error,
"error_number": errorNumber == null ? null : errorNumber,
"response_code": responseCode == null ? null : responseCode,
"result": result == null ? null : List<dynamic>.from(result.map((x) => x.toJson())),
};
}
class Result {
int id;
String name;
DateTime dayAired;
String trend;
List<TrendDetail> trendDetails;
Result({
this.id,
this.name,
this.dayAired,
this.trend,
this.trendDetails,
});
factory Result.fromJson(Map<String, dynamic> json) => Result(
id: json["id"] == null ? null : json["id"],
name: json["name"] == null ? null : json["name"],
dayAired: json["day_aired"] == null ? null : DateTime.parse(json["day_aired"]),
trend: json["trend"] == null ? null : json["trend"],
trendDetails: json["trend_details"] == null ? null : List<TrendDetail>.from(json["trend_details"].map((x) => TrendDetail.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"id": id == null ? null : id,
"name": name == null ? null : name,
"day_aired": dayAired == null ? null : dayAired.toIso8601String(),
"trend": trend == null ? null : trend,
"trend_details": trendDetails == null ? null : List<dynamic>.from(trendDetails.map((x) => x.toJson())),
};
}
class TrendDetail {
String name;
TrendDetail({
this.name,
});
factory TrendDetail.fromJson(Map<String, dynamic> json) => TrendDetail(
name: json["name"] == null ? null : json["name"],
);
Map<String, dynamic> toJson() => {
"name": name == null ? null : name,
};
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
String jsonStr = '''
{
"error":"",
"error_number":"",
"response_code":200,
"result":[
{
"id":1,
"name":"Great Deal",
"day_aired":"2015-07-05 11:06:09",
"trend":"Noone",
"trend_details": [{
"name":"Great Deal"
}
]
}
]
}
''';
void _incrementCounter() {
var payload = payloadFromJson(jsonStr);
print('${payload.result[0].name}');
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}

Groovy SwingBuilder ToggleButton StateChange

Is there anyway to avoid the stateChange event being fired more than one time when the toggleButton is clicked? Or am I using the wrong event handler? It gets called 5 times for every toggle.
#!/usr/bin/env groovy
import groovy.swing.SwingBuilder
import static javax.swing.JFrame.EXIT_ON_CLOSE
def swing = new SwingBuilder()
swing.edt {
lookAndFeel 'nimbus'
frame(title : "Throttle",
pack : true,
show : true,
defaultCloseOperation: EXIT_ON_CLOSE,
id : "frame" ) {
boxLayout()
toggleButton(text: 'fl',
selected : false,
rolloverEnabled: false,
toolTipText : 'f1',
stateChanged : { e ->
println e.source
})
}
}
swing.doLater { frame.size = [128, 320] }
I switched to from stateChanged to actionPerformed then it worked as what I expected. Not sure why I used stateChanged in the first place!

Resources