Why does my callstack say that I have 2 mains running?

Viewed 389

I started on implementing background messages for FCM, and they required me to make my own Kotlin Application. But ever since I did that I seem 2 have 2 main functions in my callstack.

enter image description here

How is this possible? If I run a empty project it has 0 mains in the callstack?

I added Application.kt

package HERE_I_HAVE_MY_PACKAGE_NAME

import io.flutter.app.FlutterApplication
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback
import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService

public class Application: FlutterApplication(), PluginRegistrantCallback {
  override fun onCreate() {
    super.onCreate()
    FlutterFirebaseMessagingService.setPluginRegistrant(this)
  }

  override fun registerWith(registry: PluginRegistry) {
    FirebaseCloudMessagingPluginRegistrant.registerWith(registry)
  }
}

And FirebaseCloudMessagingPluginRegistrant.kt

package HERE_I_HAVE_MY_PACKAGE_NAME

import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin

class FirebaseCloudMessagingPluginRegistrant {
  companion object {
    fun registerWith(registry: PluginRegistry) {
      if (alreadyRegisteredWith(registry)) {
        return;
      }
      FirebaseMessagingPlugin.registerWith(registry.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin"))
    }

    fun alreadyRegisteredWith(registry: PluginRegistry): Boolean {
      val key = FirebaseCloudMessagingPluginRegistrant::class.java.name
      if (registry.hasPlugin(key)) {
        return true
      }
      registry.registrarFor(key)
      return false
    }
  }
}

And this is my AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.company_name.app_name">
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <!-- io.flutter.app.FlutterApplication is an android.app.Application that
         calls FlutterMain.startInitialization(this); in its onCreate method.
         In most cases you can leave this as-is, but you if you want to provide
         additional functionality it is fine to subclass or reimplement
         FlutterApplication and put your custom class here. -->
    <application
        android:name=".Application"
        android:label="App Name"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
            <intent-filter>
                <action android:name="FLUTTER_NOTIFICATION_CLICK" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
        <activity
        android:name="com.yalantis.ucrop.UCropActivity"
        android:screenOrientation="portrait"
        android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
        <!-- Don't delete the meta-data below.
             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_channel_id"
            android:value="@string/default_notification_channel_id"/>  
    </application>
</manifest>
2 Answers

If you mark your main function as async, or your main function calls another function marked with async, it will fork to handle the event queue or microtask queue, that is actually what enables it to await a future without blocking the thread and return back to where it left after the await keyword .

I am not sure what causes main() to run more than once, (3 in my case), but I have found a way around it

void main() {
  runApp(new MaterialApp(
    home: new BeforeRunning(),
  ));
}

class BeforeRunning extends StatefulWidget {
  BeforeRunning({Key key}) : super(key: key);

  @override
  _BeforeRunningState createState() => _BeforeRunningState();
}

class _BeforeRunningState extends State<BeforeRunning> {
  @override
  void initState() {
    super.initState();
    Timer(Duration(milliseconds: 10), () {
      Navigator.of(context).pushReplacement(new MaterialPageRoute(builder: (BuildContext context) => MyApp()));
    });
  }

  @override
  Widget build(BuildContext context) {    //You can add a splash screen here
    SystemChrome.setEnabledSystemUIOverlays([]);
    return Container(
      height: MediaQuery.of(context).size.height,
      width: MediaQuery.of(context).size.width,
      color: Colors.black,
    );
  }
}

class MyApp extends StatefulWidget {
  MyApp({Key key}) : super(key: key);

  @override
  _MyAppState createState() => new _MyAppState();
}

class _MyAppState extends State<MyApp> {
  //initState() here
  //build() here
}

Basically, add a quick Timer() (10 milliseconds) in the BeforeRunning()'s initState() with Navigator.of(context).pushReplacement( /*next screen*/) inside, and any screen from then on will only build once. (Works for me)

main() and BeforeRunning() run more than once, but the Timer() somehow stops all threads but one

Related