# Flutter as a module for Android Developers

Flutter has become quite popular among app developers because -

* Ease of development,
    
* Cross-platform,
    
* Declarative UI,
    
* Hot reload,
    
* and Native-like performance.
    

While we can build a fully functional application using Flutter, it's also possible to add Flutter to a fully functional native android application(and iOS application). In this article, we'll look into exactly that -

We can add Flutter into our existing apps as -

* Activity
    
* Fragment
    
* View
    

In this article, I'll be covering `FlutterActivity` and `FlutterFragment`. I'll make another article covering `FlutterView` using RecyclerView adapter.

In the example code snippets, I'll be using `Kotlin`.

---

### Setup Flutter module using Android Studio

We'll need to add a new module to our existing project by doing-

First, add the [Flutter plugin](https://plugins.jetbrains.com/plugin/9212-flutter) to Android Studio.

Then in your existing project - `File > New > New Module > Flutter Module` and then complete the module setup wizard.

![ide-wizard.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1636213188720/xOEfBh4FV.png align="left")

### Add a single Flutter screen as Activity

In flutter, we inflate a widget *(everything in Flutter is a widget)* using the `runApp` function by doing this -

```kotlin
void main() => runApp(const MyApp());
```

Let's say we want to do the same from our existing app as an `activity` we can do this -

```kotlin
fun navigateToFlutterActivity() {
        startActivity(
            FlutterActivity
                .createDefaultIntent(this)
        )
    }
```

Make sure `FlutterActivity` is imported.

```kotlin
import io.flutter.embedding.android.FlutterActivity
```

\*\*Result - \*\*

![no cache flutter.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1636348189034/mBk3qx-o3.gif align="left")

We'll notice some delay in inflating the widget 😕. This is because flutter runs on `Flutter Engine` which has a *non-trivial warm-up time*, what we can do is pre-cache the engine and use that to inflate the widget.

For this, we'll use a *cached* `FlutterEngine.`

### Adding a single Flutter Screen with Cached FlutterEngine as Activity

First, declare the FlutterEngine in the application class as follows -

```kotlin
class AndroidAndFlutterApplication : Application() {
    private lateinit var flutterEngine: FlutterEngine

    override fun onCreate() {
        super.onCreate()
        flutterEngine = FlutterEngine(this)

        flutterEngine.dartExecutor.executeDartEntrypoint(
            DartExecutor.DartEntrypoint.createDefault()
        )

        FlutterEngineCache
            .getInstance()
            .put("engineID", flutterEngine)
     }
}
```

`Engine id` parameter can we whatever we want, we'll need it later to uniquely identify the `FlutterEngine`.

Now we can use this `FlutterEngine` by simply using `.withCachedEngine()` builder as -

```kotlin
startActivity(
    FlutterActivity
      .withCachedEngine("engineID")
      .build(this)
  )
```

\*\*Result - \*\*

![cache flutter.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1636348168893/rOApUIytM.gif align="left")

Now there is no delay. 😊

### Adding a Flutter Screen as Fragment

Similarly, we can add a Flutter screen as a fragment in our existing application with/without a pre-cached engine. Here I'll be using the same `FlutterEngine` as in `FlutterActivity` example.

```kotlin
class FlutterFragmentContainerActivity : AppCompatActivity() {
    companion object {
        // Define a tag String to represent the FlutterFragment within
        // this Activity's FragmentManager.
        private const val TAG_FLUTTER_FRAGMENT = "flutter_fragment"
    }

    private var flutterFragment: FlutterFragment? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_flutter_fragment_container)

         // Attempt to find an existing FlutterFragment,
         // in case this is not the first time that onCreate() was run.
        flutterFragment = supportFragmentManager
            .findFragmentByTag(TAG_FLUTTER_FRAGMENT) as FlutterFragment?
        if (flutterFragment == null) {
        val newFlutterFragment =
            FlutterFragment.withCachedEngine("engineID")
            .build<FlutterFragment>()
        flutterFragment = newFlutterFragment

        supportFragmentManager
            .beginTransaction()
            .add(
                R.id.fragmentContainer,
                newFlutterFragment
            )
            .commit()
        }
    }
```

Make sure FlutterFragment is imported.

```kotlin
import io.flutter.embedding.android.FlutterFragment
```

### Navigating to a specific Flutter widget

Let's see we don't want to open the default Flutter`main() => runApp()`, instead we want to specify some entry point to inflate.

We can do that too. First, we need to define a `pragma` that indicates the Dart compiler that our function will be used in native code. In`main.dart` define -

```kotlin
@pragma('vm:forSpecificRoute')
void specificRoute() => runApp(const AppWithSpecificRoute());
```

Now we'll define a FlutterEngine and pass the

```kotlin
// Instantiate a FlutterEngine.
        flutterEngine = FlutterEngine(this)

        // Start executing Dart code to pre-warm the FlutterEngine.
        flutterEngine.dartExecutor.executeDartEntrypoint(
            DartExecutor.DartEntrypoint(
                FlutterMain.findAppBundlePath(), "specificRoute"
            )
        )

        // Cache the FlutterEngine to be used by FlutterActivity.
        FlutterEngineCache
            .getInstance()
            .put("engineID", flutterEngine)
```

Now we can use this `FlutterEngine` to inflate a specific widget.

---

I hope you found this article useful, you can find the source code [here](https://github.com/imabhishekkumar/AndroidAndFlutter).

Follow me for more articles like this. Have a great day! 😊
