<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Victor Loveday</title>
    <description>The latest articles on DEV Community by Victor Loveday (@droidchief).</description>
    <link>https://dev.to/droidchief</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F732900%2Fd5095efc-a7ec-440d-86ee-aa2631022595.PNG</url>
      <title>DEV Community: Victor Loveday</title>
      <link>https://dev.to/droidchief</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/droidchief"/>
    <language>en</language>
    <item>
      <title>Choosing Between MethodChannel and PlatformView: A Real Decision, Not a Rule of Thumb</title>
      <dc:creator>Victor Loveday</dc:creator>
      <pubDate>Thu, 24 Sep 2026 19:31:31 +0000</pubDate>
      <link>https://dev.to/droidchief/choosing-between-methodchannel-and-platformview-a-real-decision-not-a-rule-of-thumb-32fl</link>
      <guid>https://dev.to/droidchief/choosing-between-methodchannel-and-platformview-a-real-decision-not-a-rule-of-thumb-32fl</guid>
      <description>&lt;h2&gt;
  
  
  I Embedded a Native Camera Preview in Flutter (And Learned Exactly Where MethodChannel Stops Being Enough)
&lt;/h2&gt;

&lt;p&gt;Seven years into mobile engineering, I wanted to answer a question I've seen a few times: when do you actually need PlatformView instead of MethodChannel? Most answers I've seen are either "PlatformView is for native UI" (true, but not useful) or skip straight to copy-pasteable boilerplate with none of the failure modes that actually teach you anything.&lt;/p&gt;

&lt;p&gt;Over the weekend, I built a small Flutter app that embeds a native Android camera preview with a live ML Kit face-detection overlay, drawn natively, not through a Flutter widget stacked on top. This article is the build and, more usefully, the three things that broke along the way and what each one taught me about how Flutter's native bridging actually works under the hood.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl95dk5e39qzt05zc3pys.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl95dk5e39qzt05zc3pys.png" alt="LensBridge app UI mockup showing a live camera preview with a green face-detection box drawn around a face, a Flutter debug ribbon in the top-right corner, and bottom controls for switching lens and stopping the camera" width="488" height="972"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why MethodChannel wasn't the question
&lt;/h2&gt;

&lt;p&gt;Before touching code, it's worth being precise about something I initially framed loosely myself: &lt;code&gt;MethodChannel&lt;/code&gt; isn't "too weak" for native work; it's just the wrong tool for a specific job. It's a request/response bridge. Dart calls a method, native code handles it, returns a result. For one-off calls, biometric auth, reading an NFC tag, taking a photo, it's genuinely the right tool, no asterisk needed.&lt;/p&gt;

&lt;p&gt;What it categorically cannot do is put a native &lt;code&gt;View&lt;/code&gt; inside your Flutter widget tree. It moves data, not UI. The moment you need an actual native surface rendering live inside your layout- a camera preview, a map SDK's own view- you need &lt;code&gt;PlatformView&lt;/code&gt;. That's not a performance tradeoff or a style preference. It's the only mechanism Flutter gives you for that job.&lt;/p&gt;

&lt;p&gt;So the real architecture question for LensBridge wasn't "MethodChannel or PlatformView". It was "PlatformView for the pixels, MethodChannel for the commands," running side by side, each doing what it's actually built for.&lt;/p&gt;

&lt;h2&gt;
  
  
  The architecture
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;PlatformView&lt;/code&gt;&lt;/strong&gt; hosts a &lt;code&gt;PreviewView&lt;/code&gt; (CameraX) wrapped in a &lt;code&gt;FrameLayout&lt;/code&gt;, with a second custom &lt;code&gt;View&lt;/code&gt; stacked on top for drawing detection boxes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ImageAnalysis&lt;/code&gt;&lt;/strong&gt; (a separate CameraX use case from &lt;code&gt;Preview&lt;/code&gt;) feeds frames to ML Kit's on-device face detector&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;MethodChannel&lt;/code&gt;&lt;/strong&gt; handles the three things Dart needs to &lt;em&gt;tell&lt;/em&gt; native code to do: switch lens, stop, start
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CameraPlatformView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;viewId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;lifecycleOwner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LifecycleOwner&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;PlatformView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;previewView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;PreviewView&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PreviewView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;implementationMode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PreviewView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ImplementationMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;COMPATIBLE&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;overlayView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;OverlayView&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OverlayView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FrameLayout&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FrameLayout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;addView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;previewView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;FrameLayout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LayoutParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MATCH_PARENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MATCH_PARENT&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nf"&gt;addView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;overlayView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;FrameLayout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LayoutParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MATCH_PARENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MATCH_PARENT&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getView&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;View&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;container&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two lines in there, &lt;code&gt;implementationMode&lt;/code&gt; and the explicit &lt;code&gt;LayoutParams&lt;/code&gt;, look unremarkable. They cost me two separate debugging sessions. More on both below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fab8mb26bjeph3tyn41go.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fab8mb26bjeph3tyn41go.png" alt="A simple architecture diagram" width="799" height="571"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  What actually broke
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;code&gt;unbindAll()&lt;/code&gt; doesn't clear the surface
&lt;/h3&gt;

&lt;p&gt;After wiring MethodChannel controls for Stop, hitting it left the last camera frame frozen on screen instead of going blank. Not a bug. &lt;code&gt;PreviewView&lt;/code&gt; is backed by a &lt;code&gt;SurfaceView&lt;/code&gt;/&lt;code&gt;TextureView&lt;/code&gt;, and &lt;code&gt;unbindAll()&lt;/code&gt; stops new frames from being pushed but never explicitly clears the existing buffer. Nothing tells the GPU to draw anything else over it, so the last frame just sits there.&lt;/p&gt;

&lt;p&gt;Confirmed it was genuinely stopped (not stalled) by waving a hand in front of the camera. No update. Fixed it by explicitly toggling &lt;code&gt;previewView.visibility&lt;/code&gt; on stop/start rather than relying on frame delivery to communicate state.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. A completely silent 0×0 view
&lt;/h3&gt;

&lt;p&gt;Once ML Kit was wired up and logcat confirmed detection was running (&lt;code&gt;face_count=1&lt;/code&gt; in the stats), nothing appeared on screen. No crash, no warning. The overlay simply didn't render.&lt;/p&gt;

&lt;p&gt;The cause: I added the overlay view to its container with &lt;code&gt;addView(view)&lt;/code&gt; and no explicit &lt;code&gt;LayoutParams&lt;/code&gt;. Default behavior is &lt;code&gt;WRAP_CONTENT&lt;/code&gt;, and since &lt;code&gt;OverlayView&lt;/code&gt; has no intrinsic content,  it's just a custom &lt;code&gt;View&lt;/code&gt; doing manual canvas drawing, it measured out to 0×0. &lt;code&gt;onDraw()&lt;/code&gt; was being called the whole time, just onto a canvas with no area to draw into.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;addView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;overlayView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;FrameLayout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LayoutParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;FrameLayout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LayoutParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MATCH_PARENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nc"&gt;FrameLayout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LayoutParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MATCH_PARENT&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the one I'd flag hardest to anyone stacking a custom-drawn view over a CameraX preview: the pipeline can be entirely correct and you'll still see nothing, because the bug isn't in your detection logic at all.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. SurfaceView doesn't respect view z-order
&lt;/h3&gt;

&lt;p&gt;Even after fixing #2, the overlay &lt;em&gt;still&lt;/em&gt; didn't show, except for a single frame that flashed the instant I hit Stop. That flash was the clue.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;PreviewView&lt;/code&gt; defaults to &lt;code&gt;ImplementationMode.PERFORMANCE&lt;/code&gt;, which renders through a &lt;code&gt;SurfaceView&lt;/code&gt;. &lt;code&gt;SurfaceView&lt;/code&gt; content composites through a separate hardware layer, outside Android's normal view-drawing pass, meaning it can visually sit above other views in the same layout regardless of their z-order in code. My overlay was drawing correctly the entire time. It was just being painted over, every frame, by the camera feed's hardware-composited layer underneath it. &lt;/p&gt;

&lt;p&gt;The fix is a documented tradeoff, not a hack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;previewView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;implementationMode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PreviewView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ImplementationMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;COMPATIBLE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;COMPATIBLE&lt;/code&gt; forces a &lt;code&gt;TextureView&lt;/code&gt; instead, which renders as a normal part of the view hierarchy, with predictable layering, at the cost of losing &lt;code&gt;PERFORMANCE&lt;/code&gt; mode's hardware-layer fast path. For a demo like this, that's the right trade every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I'd actually reconsider
&lt;/h2&gt;

&lt;p&gt;If I rebuilt this today, I'd add the &lt;code&gt;COMPATIBLE&lt;/code&gt; implementation mode from the start rather than discovering it two bugs deep. It's a known CameraX behavior. I just hadn't hit it firsthand before. &lt;/p&gt;

&lt;p&gt;Code's on GitHub: &lt;a href="https://github.com/droidchief/lense_bridge" rel="noopener noreferrer"&gt;https://github.com/droidchief/lense_bridge&lt;/a&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>kotlin</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Kotlin for Server-Side</title>
      <dc:creator>Victor Loveday</dc:creator>
      <pubDate>Tue, 02 Nov 2021 16:19:27 +0000</pubDate>
      <link>https://dev.to/droidchief/kotlin-for-server-side-2hmg</link>
      <guid>https://dev.to/droidchief/kotlin-for-server-side-2hmg</guid>
      <description>&lt;p&gt;With &lt;strong&gt;Kotlin&lt;/strong&gt;, we can create different applications for different platforms. Server-side applications are no exception. Similarly to Java, Kotlin can be used to set up and run server side applications. Several frameworks like &lt;strong&gt;Spark&lt;/strong&gt; and &lt;strong&gt;Spring&lt;/strong&gt; which is used with Java also have support for Kotlin. I will show you four of them as we proceed. But first;&lt;/p&gt;

&lt;h3&gt;
  
  
  Ktor
&lt;/h3&gt;

&lt;p&gt;Ktor (pronounced Kay-tor) is an asynchronous open source framework for creating micro services and web applications. It was developed with Kotlin by Jetbrains. The framework is lightweight and has a great support for coroutines and KMM (Kotlin Multi Platform).&lt;/p&gt;

&lt;h4&gt;
  
  
  Four frameworks for server-side development with Kotlin
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Spring Boot:&lt;/strong&gt; This framework is widely used for creating stand-alone Spring Based Applications. Applications created with Spring Boot are of large-scale, production-grade, while you just need to trigger the run button.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Javalin:&lt;/strong&gt; This framework is referred to as the most lightweight for Kotlin and Java server-side development. Javalin supports network configuration components such as Web Sockets, HTTP2 and async requests and so on. Javalin was initiated as a clone of Java. Although it was not anticipated by its developers, still Javalin emerged into a wider framework. It was moulded into a ground-up rewrite, with reference to the JavaScript framework koa.js.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Spark:&lt;/strong&gt; Spark is one of the earliest expressive Kotlin or Java web framework built for rapid development. It can also be used in higher-level Kotlin development. It is not so popular. Spark is not so trusted with respect to micro-services.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vert.X:&lt;/strong&gt; Just like Java and Kotlin, Vert.X is an ecosystem used for building reactive applications in different programming languages. Vert.X comes with a powerful set of tools. However, it is not advisable for everyone. It comes with detailed documentation and is thoroughly compatible with Kotlin libraries. It creates reactive Web applications for the Java Virtual Machine.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Why Ktor ?
&lt;/h3&gt;

&lt;p&gt;It is a very lightweight framework that reduces the effort required to create web applications in Kotlin. It doesn’t manipulate the underlying technologies of a project and is compatible with most of them, with very rare exceptions.&lt;/p&gt;

&lt;p&gt;It is highly reliable, as it is a product of the Kotlin team, itself. It allows developers to rapidly create both, client and server-side applications that target multiple platforms. Ktor exploits Kotlin Coroutines for providing high scalability and offers an efficient and idiomatic API for developers.&lt;/p&gt;

&lt;p&gt;It works on a minimum memory footprint and comes in as a lightweight thread. It is analogous to Javalin, it is also a real micro-framework plus it's simplicity. Left to me, I'd say it's the most suitable for prototyping. &lt;/p&gt;

</description>
      <category>todayilearned</category>
      <category>kotlin</category>
      <category>webservice</category>
      <category>backend</category>
    </item>
  </channel>
</rss>
