Git Product home page Git Product logo

Comments (25)

chrisbanes avatar chrisbanes commented on April 19, 2024 2

Thanks for the project. I finally managed to reproduce this (note to self: change the emulator to use 1 CPU core). Now to work out what's happening....

from accompanist.

chrisbanes avatar chrisbanes commented on April 19, 2024 2

I just come up with a bit of a hack which fixes this. It's safe to use, but I don't want to ship it in the library until I speak to some of the team: https://gist.github.com/chrisbanes/bd9aa241dbab971c23433aaff8104d38, but it should unblock you all.

from accompanist.

chrisbanes avatar chrisbanes commented on April 19, 2024 1

Worked this out. So using ProvideWindowInsets in fragments can result in the following:

  1. Fragment is added.
  2. onCreateView is called.
  3. Fragment's ComposeView is added to the hierarchy.
  4. Some time later (after initial view layout pass AFAICT), the first composition happens.
    • ProvideWindowInsets is called which sets listeners and requests an insets pass.
  5. Compose content is laid out using 0 sized insets.
  6. In the next view layout pass, insets are dispatched and the Compose WindowInsets are updated.
  7. Compose content is laid out using correct insets.

The visual flicker is caused by steps 5 & 7 happening quickly after each other.

Using observeFromView() from #158 instead results in the following:

  1. Fragment is added
  2. onCreateView is called
    • observeFromView() is called from onCreateView() which sets listeners and requests an insets pass.
  3. Fragment's ComposeView is added to the hierarchy.
  4. In the first layout of ComposeView insets are dispatched, and this library's WindowInsets are updated.
  5. Compose content is composed using correct insets from first layout.

No flicker! 😅

from accompanist.

chrisbanes avatar chrisbanes commented on April 19, 2024 1

BTW do you think that the Jetpack Compose team can do something about this? Maybe something needs to be changed in ComposeView?

Yeah I've reached out and hoping we can come up with something.

I'm still investigating why the WindowInsets aren't dispatched in the first measure pass. If we could fix that, we wouldn't have any isseues.

from accompanist.

radzio avatar radzio commented on April 19, 2024 1

Thanks! Works like a charm :)

from accompanist.

ReginFell avatar ReginFell commented on April 19, 2024 1

Is there any better solution for this issue?

We are migrating to Compose and as a first step we want to migrate from xmls to Composable, so we can't easily get rid of fragments therefore we have to deal with the issue.

The workaround #155 (comment) works, but is it reliable? If so, can we have it in the library?

from accompanist.

alexvanyo avatar alexvanyo commented on April 19, 2024 1

Some experimental insets APIs have been merged into androidx, available in the latest snapshots (if you're feeling adventurous, feel free to try it out and report issues or feedback!)

The mechanism behind the implementation is a little bit different than accompanist, and in my initial testing the approach seems to be more reliable around flickering and in fragments.

from accompanist.

apkelly avatar apkelly commented on April 19, 2024

Just to confirm, the app I'm working on does use Fragments, each one provides its UI using Compose, we still use the existing Jetpack Navigation via Fragments for navigating between Fragments in a single Activity app.

from accompanist.

apkelly avatar apkelly commented on April 19, 2024

#shipit!

from accompanist.

Nghicv avatar Nghicv commented on April 19, 2024

@apkelly @chrisbanes I still got flicker when applying observeFromView. I am using fragments with navigation.

from accompanist.

chrisbanes avatar chrisbanes commented on April 19, 2024

@Nghicv do you have an example of this? Does it happen on specific devices? I'm not sure there's much else we can do.

from accompanist.

Nghicv avatar Nghicv commented on April 19, 2024

@chrisbanes I have just tested TV app from the google play store, it got flicker too
this is my device
Screen Shot 2021-02-08 at 09 23 19

from accompanist.

radzio avatar radzio commented on April 19, 2024

@apkelly @chrisbanes

have you managed to make it work with FragmentContainerView and the Navigation Library (multiple fragments with composable UI) ?

I have one Activity

class HomeActivity : FragmentActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        WindowCompat.setDecorFitsSystemWindows(window, false)

        binding = ActivityMainBinding.inflate(layoutInflater)

        setContentView(binding.root)
    }
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/nav_graph" />

</androidx.constraintlayout.widget.ConstraintLayout>

and fragments like:

class MyFragment: BaseFragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View = ComposeView(requireContext()).apply {
        layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)

        val windowInsets = ViewWindowInsetObserver(this).start(consumeWindowInsets = false)

        setContent {
            Providers(
                LocalWindowInsets provides windowInsets
            ) {
                // composable UI 
            }
        }
    }

my UI is flickering on Pixel 2 Emulator API 30 and OnePlus 8T API 30

from accompanist.

chrisbanes avatar chrisbanes commented on April 19, 2024

@radzio if you have a simple project, would you mind uploading it? (zip is fine). I've got a few apps which use fragments and I haven't seen any flickers.

from accompanist.

radzio avatar radzio commented on April 19, 2024

@chrisbanes

Maybe we are talking about different bug/feature but check this video:

WCel6GbbrZ.mp4

"Hi there text" evidently starts without inset padding (just play it in slow-mo). Maybe I'm doing something wrong but I have no idea what :(.

When I'm not using insets and statusBarsPadding modifier there is no jumping at all. TextField is, as expected, in wrong place ,under status bar):

Example app:
Flickering.zip

from accompanist.

chrisbanes avatar chrisbanes commented on April 19, 2024

OK, got a little further with this. This is what happens internally:

D/ComposeView Parent: Attached to window
D/ViewWindowInsetObserver: requestApplyInsets() called
D/ComposeView: Attached to window

D/ComposeView Parent: onMeasure

# First measure/layout of Composables. WindowInsets are empty
D/InsetsPaddingModifier: measure(): Insets(left=0, top=0, right=0, bottom=0)

D/ComposeView Parent: onMeasure
D/ViewWindowInsetObserver: WindowInsets dispatched and received

D/ComposeView Parent: onMeasure
D/ComposeView Parent: onMeasure

D/ComposeView Parent: onLayout
D/ComposeView: First layout

# Second measure/layout of Composables. WindowInsets are now filled
D/InsetsPaddingModifier: measure(): Insets(left=0, top=48, right=0, bottom=0)

As a summary: the composables are laid out once before the WindowInsets are dispatched. I'm not sure there's much we can do here.

from accompanist.

radzio avatar radzio commented on April 19, 2024

@chrisbanes thanks for the investigation. It's sad that we can't do more here.

However, at least in my case, I think that I can use activity.window.decorView.rootWindowInsets

On the first fragment, it will not work because it's null, but it's ok for me because the first fragment is not inset-dependent. But on the subsequent fragments, I get this value immediately. However, I don't know how to use this rootWindowInsets because I can't set anything (setters are internal :) )

BTW do you think that the Jetpack Compose team can do something about this? Maybe something needs to be changed in ComposeView?

from accompanist.

Nghicv avatar Nghicv commented on April 19, 2024

@chrisbanes @radzio the hack worked but I got a white screen before the destination screen is shown. seem to Time to showing white screen equal to the time to wait MAXIMUM_ONMEASURE_IGNORED

from accompanist.

chrisbanes avatar chrisbanes commented on April 19, 2024

@Nghicv that would make sense, as that is what the hack is doing.

from accompanist.

Nghicv avatar Nghicv commented on April 19, 2024

@chrisbanes should we come up with a better solution?

from accompanist.

github-actions avatar github-actions commented on April 19, 2024

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

from accompanist.

github-actions avatar github-actions commented on April 19, 2024

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

from accompanist.

natario1 avatar natario1 commented on April 19, 2024

Is this related to fragments only? We're seeing the same jump in an app without fragments, not sure if I should open a separate issue or investigate more.

from accompanist.

svenjacobs avatar svenjacobs commented on April 19, 2024

I just come up with a bit of a hack which fixes this. It's safe to use, but I don't want to ship it in the library until I speak to some of the team: https://gist.github.com/chrisbanes/bd9aa241dbab971c23433aaff8104d38, but it should unblock you all.

Thanks! This hack works for me (with a slight modification: Providers -> CompositionLocalProvider), however is there now a more reliable and stable solution?

from accompanist.

mxkmn avatar mxkmn commented on April 19, 2024

So, seems like I found how to fix this: https://stackoverflow.com/q/77807932/12544067

from accompanist.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.