facebook/litho

ContentAllocator API not working

shiv71 opened this issue · 14 comments

Version


 implementation 'com.facebook.litho:litho-core:0.45.0'
 implementation 'com.facebook.litho:litho-core-kotlin:0.45.0'
 implementation 'com.facebook.litho:litho-widget:0.45.0'
 implementation 'com.facebook.litho:litho-widget-kotlin:0.45.0'
 kapt 'com.facebook.litho:litho-processor:0.45.0'
 // SoLoader
 implementation 'com.facebook.soloader:soloader:0.10.4'
 // Testing Litho
 testImplementation 'com.facebook.litho:litho-testing:0.45.0'***

Issues and Steps to Reproduce

*** poolSize(), canPreallocate(), shouldUpdate() method not calling in SimpleMountable***

Expected Behavior

poolSize(), canPreallocate(), shouldUpdate() should work.

Sample Code


package com.buddynation.dronenation.bn.litho.timeline

import android.content.Context
import android.net.Uri
import android.util.Log
import androidx.media3.common.MediaItem
import androidx.media3.common.Player
import androidx.media3.datasource.DataSource
import androidx.media3.datasource.DefaultHttpDataSource
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.hls.HlsMediaSource
import androidx.media3.exoplayer.source.MediaSource
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
import androidx.media3.ui.PlayerView
import com.facebook.litho.*
import com.facebook.litho.visibility.onFocusedVisible
import com.facebook.litho.visibility.onInvisible
import com.facebook.litho.visibility.onVisibilityChanged
import com.facebook.rendercore.MeasureResult
import com.facebook.litho.visibility.onVisible

class MediaPlayer (
    private val videoUrl : String,
    private val style: Style? = null,
): MountableComponent() {




    override fun MountableComponentScope.render(): MountableRenderResult {
        Log.e("MediaPlayer","video MountableComponentScope")

        var mediaPlayerMountableComponent = MediaPlayerMountableComponent(videoUrl);


        return MountableRenderResult(mediaPlayerMountableComponent, style?.
        onVisible {
            Log.e("video-component","onVisible")
        }
            ?.onInvisible {
                Log.e("video-component","onInvisible")

            }?.
            onVisibilityChanged { event ->
                if (event.percentVisibleHeight > 50) {
                    mediaPlayerMountableComponent.play()
                    Log.e(
                        "video-component",
                        "View is mostly visible now. With: " +
                                "\ntop: ${event.visibleTop}" +
                                "\nleft: ${event.visibleLeft}" +
                                "\nvisible width: ${event.visibleWidth}" +
                                "\nvisible height: ${event.visibleHeight}" +
                                "\npercentage visible height: ${event.percentVisibleHeight}" +
                                "\npercentage visible width: ${event.percentVisibleWidth}")
                }else{
                    mediaPlayerMountableComponent.pause()
                }
            }
        )
    }

}
private const val defaultSize: Int = 400

internal class MediaPlayerMountableComponent(
    private val videoUrl: String,
    ) : SimpleMountable<PlayerView>(RenderType.VIEW){

   // private var videoView: PlayerView? = null
    private val playbackStateListener: Player.Listener = playbackStateListener()
    private var player: ExoPlayer? = null

    private var playWhenReady = true
    private var currentItem = 0
    private var playbackPosition = 0L

    override fun canPreallocate(): Boolean {
        Log.e("MediaPlayer","canPreallocate")

        return true
    }

    override fun poolSize(): Int {
        Log.e("MediaPlayer","poolSize")
        return 3
    }



    override fun shouldUpdate(
        newMountable: SimpleMountable<PlayerView>,
        currentLayoutData: Any?,
        nextLayoutData: Any?
    ): Boolean {
        Log.e("MediaPlayer","shouldUpdate")

        return super.shouldUpdate(newMountable, currentLayoutData, nextLayoutData)
    }

    fun play(){

        player?.let { exoPlayer ->
            exoPlayer.play()

        }
    }

    fun pause(){
        player?.let { exoPlayer ->
            exoPlayer.pause()
        }
    }

    override fun createContent(context: Context): PlayerView {
        Log.e("MediaPlayer","video createContent")

        var videoView  = PlayerView(context);
        return videoView
    }



    override fun mount(c: Context, content: PlayerView, layoutData: Any?) {
        Log.e("MediaPlayer","video mount")

        initializePlayer(c,content)
    }

    override fun unmount(c: Context, content: PlayerView, layoutData: Any?) {
        Log.e("MediaPlayer","video unmount")

        releasePlayer()
    }

    override fun MeasureScope.measure(widthSpec: Int, heightSpec: Int): MeasureResult {
        Log.e("MediaPlayer","video measure")

        return if (SizeSpec.getMode(widthSpec) == SizeSpec.UNSPECIFIED &&
            SizeSpec.getMode(heightSpec) == SizeSpec.UNSPECIFIED
        ) {
            MeasureResult(defaultSize, defaultSize)
        } else {
            // withEqualSize(widthSpec, heightSpec)
            MeasureResult(widthSpec, heightSpec)

        }



    }

    private fun initializePlayer(context: Context, videoView : PlayerView) {

       // val uri = Uri.parse(context.getString(R.string.media_url_mp4))
        val uri = Uri.parse(videoUrl)

        val trackSelector = DefaultTrackSelector(context).apply {
            setParameters(buildUponParameters().setMaxVideoSizeSd())
        }

        // Create a data source factory.
        val dataSourceFactory: DataSource.Factory = DefaultHttpDataSource.Factory()
        // Create a HLS media source pointing to a playlist uri.

        val hlsMediaSource: MediaSource = HlsMediaSource.Factory(dataSourceFactory)
            .createMediaSource(MediaItem.fromUri(uri))

        player = ExoPlayer.Builder(context)
            .setTrackSelector(trackSelector)
            .build()
            .also { exoPlayer ->
                videoView?.player = exoPlayer

                exoPlayer.setMediaSource(hlsMediaSource)
                //exoPlayer.playWhenReady = playWhenReady
                exoPlayer.seekTo(currentItem, playbackPosition)
                exoPlayer.addListener(playbackStateListener)
                exoPlayer.prepare()


                videoView.setShowNextButton(false)
                videoView.setShowPreviousButton(false)
                videoView.setFullscreenButtonClickListener {  }
                videoView.controllerAutoShow = false

            }
    }

    private fun releasePlayer() {
        player?.let { exoPlayer ->
            playbackPosition = exoPlayer.currentPosition
            currentItem = exoPlayer.currentMediaItemIndex
            playWhenReady = exoPlayer.playWhenReady
            exoPlayer.removeListener(playbackStateListener)
            exoPlayer.release()
        }
        player = null
    }

}

private fun playbackStateListener() = object : Player.Listener {
    override fun onPlaybackStateChanged(playbackState: Int) {
        val stateString: String = when (playbackState) {
            ExoPlayer.STATE_IDLE -> "ExoPlayer.STATE_IDLE      -"
            ExoPlayer.STATE_BUFFERING -> "ExoPlayer.STATE_BUFFERING -"
            ExoPlayer.STATE_READY -> "ExoPlayer.STATE_READY     -"
            ExoPlayer.STATE_ENDED -> "ExoPlayer.STATE_ENDED     -"
            else -> "UNKNOWN_STATE             -"
        }
        Log.d("MEDIA_STATE", "changed state to $stateString")
    }
}


Issues faced

I'm trying to create Facebook feed style UI with video autoplay feature.
I'm having below issues

  1. I'm using lazylist and if the first post having photo/video then it doesn't work. If I scroll down and up then it shows up.
  2. I tried to use preAllocate, poolsize and shouldUpdate methods but those are also not calling.

Can someone guide me on the above issues?
Also if someone can guide on improving performance of videos list and autoplay that would be great.

@astreet

@drd @astreet @javache @dreiss any one can reply the above question.

Thank you for reporting this bug. We'll land a fix this week. We'll get back to regarding loading photo/videos and performance.

@adityasharat Thanks for your reply.
We are waiting for fix.

@adityasharat I am facing one more issue.
I have created a custom component using android ImageView and glide to load url image. I am using this component with
lazy list component. Image is loading perfectly but when I scroll list up and down image is getting blurred.

Thank you for reporting this bug. We'll land a fix this week. We'll get back to regarding loading photo/videos and performance.

@adityasharat any updates on fix?

The fix has landed (commit). It should be available in the next release which we'll publish this week.

The fix has landed (commit). It should be available in the next release which we'll publish this week.

Thanks for the update. I was wondering did anyone ever created a working sample of a Facebook/instagram style news feed with photos and videos? do you have any idea about this?

The closest we have is a surface with photos in the Litho sample app.

EDITED:
We don't really have OSS examples of how to use Litho for a moderately complex app, and no open source video component.

In general, it is recommended to do as much work as possible ahead of time; this means doing most of the heavy lifting of prepare the media during the @OnPrepare and/or @OnMeasure callbacks. These should be done in a way to make @OnMount a cheap operation (i.e. when on mount is invoked the media should be ready for render).

I hope these general recommendation can help you design a solution that fits your needs.

Screen.Recording.2023-02-13.at.17.57.26.mov

The fix has landed (commit). It should be available in the next release which we'll publish this week.

Is this fix released?

The fix has landed (commit). It should be available in the next release which we'll publish this week.

Below issue are not resolved
I'm using lazylist and if the first post having photo/video then it doesn't work. If I scroll down and up then it shows up.
I tried to use preAllocate, and shouldUpdate methods but those are also not calling.
Image getting blur when scorlling list up and down.

@adityasharat awaiting for your reply.

Can you please provide a repro (say as a patch) for this issue otherwise it very hard to provide support.

Ok we will try to provide demo

Closing. Please reopen if required