I tried to make a floating window with androidx.co...
# compose
s
I tried to make a floating window with androidx.compose.ui.platform.ComposeView
Copy code
class FloatingService : Service() {
    
    private var windowManager: WindowManager? = null
    override fun onCreate() {
        super.onCreate()
        windowManager = ContextCompat.getSystemService(this, WindowManager::class.java)
        var view = LayoutInflater.from(this).inflate(R.layout.player_popup_close_overlay, null, false)
        val closeOverlayLayoutParams = buildCloseOverlayLayoutParams()
        var composeView = view.findViewById<ComposeView>(R.id.compose_view)
        composeView.setContent {
            Button(onClick = { }) {
                Text(text = "Click Me")
            }
        }
        Objects.requireNonNull(windowManager)?.addView(view, closeOverlayLayoutParams)
    }

}
after start service, the app will crash, and there is no error log in the LogCat. if update my view xml (player_popup_close_overlay.xml) by remove ComposeView, and add TextView for testing, it works fine. I am not sure what went wrong with ComposeView
a
There's definitely an error log in there 🙂 and chances are it's looking for a
ViewTreeLifecycleOwner
set on the root view of the new window you're creating
đŸ˜± 1
(please try to keep the code snippets >4-6 lines in the thread so that it doesn't flood the channel!)
👍 1
s
I can see the error log now. 2021-04-29 043846.735 10025-10025/com.example.screenoverlay E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.screenoverlay, PID: 10025 java.lang.IllegalStateException: ViewTreeLifecycleOwner not set for this ComposeView. If you are adding this ComposeView to an AppCompatActivity, make sure you are using AppCompat version 1.3+. If you are adding this ComposeView to a Fragment, make sure you are using Fragment version 1.3+. For other cases, manually set owners on this view by using
ViewTreeLifecycleOwner.set()
and
ViewTreeSavedStateRegistryOwner.set()
. at androidx.compose.ui.platform.AbstractComposeView.checkViewTreeOwners(ComposeView.android.kt:179) at androidx.compose.ui.platform.AbstractComposeView.ensureCompositionCreated(ComposeView.android.kt:195) at androidx.compose.ui.platform.AbstractComposeView.onAttachedToWindow(ComposeView.android.kt:235) at android.view.View.dispatchAttachedToWindow(View.java:20479) at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3489) at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3496) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2417) 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)
a
yep, use
ViewTreeLifecycleOwner.set
on the root view of that window (the one you add to the window manager) to set a LifecycleOwner for the ComposeView to locate and use
you'll likely want to use a
LifecycleRegistry
instance as your implementation of the
Lifecycle
object returned by it, and you should drive its lifecycle events as appropriate for your service to emulate an activity lifecycle
s
It works now and shows my composable able button now. but somehow, my composable button is not clickable.
Copy code
composeView.setContent {
    Button(onClick = { Log.d("test","from overlay window")}) {
        Text(text = "Click Me 1")
    }
}
@Adam Powell, all good now. actually I gave window param incorrectly, the overlay window does not response to any touch event. We need to use below line to root view.
Copy code
ViewTreeLifecycleOwner.set(view, owner)
ViewTreeSavedStateRegistryOwner.set(view, owner)
I also need to give a service binder and service connection, so that I could add an activity reference (life cycle owner) back to my service class. Thanks you for helping.
👍 1
I added a button into my composable overlay view. after click, it should open main activity immediately, but it wasn’t, there was a several second delay, look like click event got blocking some where. I am not sure what went wrong. do you have any idea ? I am also here by to share my project code. just incase if want to look.
a
without looking at the code, nothing springs to mind. If you can narrow down the issue enough to post as a snippet in a thread here it might be easier for folks here to take a look.
s
Inside - OverlayWindowScreen.kt
Copy code
var composeView = overlayView!!.findViewById<ComposeView>(R.id.compose_view)
composeView.setContent {
    SmallWindowScreen()
}
SmallWindowScreen it is a composeable function which use for display overlay window there is a button “Open”, click on that button will open MainActivity
Copy code
var intent = Intent(context, MainActivity::class.java)
context.startActivity(intent)
and the problem is that, if we click that button to many time, that button would freeze, and we click only one and wait, it will open activity some later (mabye 10seconds)
a
try using https://ui.perfetto.dev to see where the time is going after the button click
388 Views