Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fresco already initialized #92

Closed
MobilefactoryAT opened this issue Oct 8, 2020 · 10 comments
Closed

Fresco already initialized #92

MobilefactoryAT opened this issue Oct 8, 2020 · 10 comments

Comments

@MobilefactoryAT
Copy link

we are using Fresco in our app as image cache library anyway and Giphy trys to initialize it twice...
Log appears when Giphy SDK is configured:

Giphy.configure(
                    context,
                    "KEY",
                    verificationMode = false
                )

Fresco: Fresco has already been initialized! Fresco.initialize(...) should only be called 1 single time to avoid memory leaks!
W/unknown:ImagePipelineFactory: ImagePipelineFactory has already been initialized! ImagePipelineFactory.initialize(...) should only be called once to avoid unexpected behavior.

Is it possible to disable the secondary initialisation?

@ALexanderLonsky
Copy link
Collaborator

@MobilefactoryAT We have special fresco setup to support our use case, though this should not pose any conflicts with your use of fresco outside of the GIPHY SDK. We can make this setup method public so that you may call it in advance of presentation of the GIPHY fragment.

@MobilefactoryAT
Copy link
Author

I'm just wondering, when I initialised my Fresco at app startup and later on somewhere in the app your fresco is initialised (eg.: before Giphy bottom sheet is shown) . Does fresco block/use 2x memory and bitmap cache and stuff or just once and your newly set fresco initialisation overrules mine previous initialised cache and ram settings?
Could this more easily lead to a OutOfMemoryException when we use 2x fresco instead of onetime? Whats the best practice in such a case?

@ALexanderLonsky
Copy link
Collaborator

Does fresco block/use 2x memory and bitmap cache and stuff or just once and your newly set fresco initialisation overrules mine previous initialised cache and ram settings? Could this more easily lead to a OutOfMemoryException when we use 2x fresco instead of onetime? Whats the best practice in such a case?
I don't have an answer right now, it depends on Fresco implementation. For sure Fresco.initialize(...) should only be called once as per their message.
But as I wrote above, we need Fresco to be initialised on the GIPHY SDK side. So what we suggest is to make the Fresco setup method public on the GIPHY SDK level so that you may use it at your app startup instead of initialising Fresco yourself.

@MobilefactoryAT
Copy link
Author

Well, I have my own "CacheKeyFactory" and "OkHttpClient" that needs to be set during initialisation. Just to make the init call public wouldn't work for me I think...

@ALexanderLonsky
Copy link
Collaborator

I see, I'll coordinate this with my team and get back to you.

@ALexanderLonsky
Copy link
Collaborator

@MobilefactoryAT
What if we extend the init call with more params?
okhttpclient builder as an optional parameter and cache configs you prefer.
So initialising is still on our side but you provide your own config/builders.

@MobilefactoryAT
Copy link
Author

MobilefactoryAT commented Oct 14, 2020

@ALexanderLonsky
This is my current setup. I don't mind about the disc cache config, but the rest would be nice.
Let me know what you can do :-)

thanks

`
//Make sure Fresco is initialized before creating the first ImageViews depending on it.
if (!Fresco.hasBeenInitialized()) {
//defining request timeouts and logging
val okHttpClient = OkHttpClient.Builder()
.readTimeout(35, TimeUnit.SECONDS)
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.cache(null)
.addInterceptor(StaleIfErrorInterceptor())
.apply {
//print all logs in debug mode
if (BuildConfig.DEBUG) {
addInterceptor(HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BASIC
})
}
}.build()

            val ipc =
                OkHttpImagePipelineConfigFactory.newBuilder(context, okHttpClient)
                    .setMainDiskCacheConfig(
                        DiskCacheConfig.newBuilder(context)
                            .setMaxCacheSize(150)
                            .setMaxCacheSizeOnLowDiskSpace(50)
                            .setMaxCacheSizeOnVeryLowDiskSpace(10)
                            .build()
                    )
                    .setCacheKeyFactory(ContentCacheKeyFactory)
                    .apply {
                        if (BuildConfig.DEBUG) setImageCacheStatsTracker(
                            FrescoCacheLogging()
                        )
                    }
                    .build()

            Fresco.initialize(context, ipc)
        }

`

@ALexanderLonsky
Copy link
Collaborator

@MobilefactoryAT please try this version:
com.giphy.sdk:ui:2.0.3-fresco-handler

Giphy has one new property: frescoHandler

You can set it here:
Giphy.configure(context, YOUR_API_KEY, verificationMode, YOUR_FRESCO_HANDLER)

Then:

override fun handle(imagePipelineConfigBuilder: ImagePipelineConfig.Builder) {
        imagePipelineConfigBuilder
            .setMainDiskCacheConfig(
                DiskCacheConfig.newBuilder(context)
                    .setMaxCacheSize(150)
                    .setMaxCacheSizeOnLowDiskSpace(50)
                    .setMaxCacheSizeOnVeryLowDiskSpace(10)
                    .build()
            )
            .setCacheKeyFactory(ContentCacheKeyFactory)
            .apply {
                if (BuildConfig.DEBUG) setImageCacheStatsTracker(
                    FrescoCacheLogging()
                )
            }
    }

    override fun handle(okHttpClientBuilder: OkHttpClient.Builder) {
        okHttpClientBuilder
            .readTimeout(35, TimeUnit.SECONDS)
            .connectTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(60, TimeUnit.SECONDS)
            .cache(null)
            .addInterceptor(StaleIfErrorInterceptor())
            .apply {
//print all logs in debug mode
                if (BuildConfig.DEBUG) {
                    addInterceptor(HttpLoggingInterceptor().apply {
                        level = HttpLoggingInterceptor.Level.BASIC
                    })
                }
            }
    }

@MobilefactoryAT
Copy link
Author

MobilefactoryAT commented Oct 15, 2020

@ALexanderLonsky thanks for the fast implementation changes from your side, I'm impressed ;-)
Here is my solution, it seems to work fine 👍

`
/**
* Initialize Fresco image cache.
* Uses Giphy Fresco library for default initialization, to avoid double init of Fresco.
* As fallback we use our own fresco [initFrescoWithoutGiphy]
*/
fun initImageCache(context: Context) {
try {
Giphy.configure(
context,

            //Giphy key from remote config
            Settings.giphy_api(),
            
            //only set this to true if you apply for an API key
            verificationMode = false,

            //because we need to set our custom CacheKey handler and other settings
            frescoHandler = object : GiphyFrescoHandler {
                override fun handle(imagePipelineConfigBuilder: ImagePipelineConfig.Builder) {
                    initFrescoImagePipeline(imagePipelineConfigBuilder, context)
                }

                override fun handle(okHttpClientBuilder: OkHttpClient.Builder) {
                    initFrescoHttpClient(okHttpClientBuilder)
                }
            }
        )
    } catch (e: Exception) {
        Timber.e(e)

        //Make sure Fresco is initialized before creating the first ImageViews depending on it.
        //In case Fresco init fails with Giphy library
        initFrescoWithoutGiphy(context)
    }
}

/**
 * Runs init of Fresco library with our config.
 * Used as fallback if Fresco fails.
 */
private fun initFrescoWithoutGiphy(context: Context) {
    catch {
        //do not go further if Fresco is already ready
        if (!Fresco.hasBeenInitialized()) {

            //custom http handler
            val okHttpClient = OkHttpClient.Builder().run {
                initFrescoHttpClient(this)
                build()
            }

            //apply our pipeline config
            val ipc = OkHttpImagePipelineConfigFactory.newBuilder(
                context,
                okHttpClient
            ).run {
                initFrescoImagePipeline(this, context)
                build()
            }

            //run init
            Fresco.initialize(context, ipc)
        }
    }
}

/**
 * Setup config for Http handler for Fresco library
 */
private fun initFrescoHttpClient(okHttpClientBuilder: OkHttpClient.Builder) {
    okHttpClientBuilder.readTimeout(35, TimeUnit.SECONDS)
        .connectTimeout(30, TimeUnit.SECONDS)
        .writeTimeout(60, TimeUnit.SECONDS)
        //do not use http cache, because Fresco takes care of that
        //Drawback, changed user profile pictures won't be updated as long as they are cached
        .cache(null)
        .addInterceptor(StaleIfErrorInterceptor())
        .apply {
            //print all logs in debug mode
            if (BuildConfig.DEBUG) {
                addInterceptor(HttpLoggingInterceptor().apply {
                    level = HttpLoggingInterceptor.Level.BASIC
                })
            }
        }
}

/**
 * Setup pipline config for Fresco library
 */
private fun initFrescoImagePipeline(
    imagePipelineConfigBuilder: ImagePipelineConfig.Builder,
    context: Context
) {
    imagePipelineConfigBuilder
        .setMainDiskCacheConfig(
            DiskCacheConfig.newBuilder(context)
                .setMaxCacheSize(150)
                .setMaxCacheSizeOnLowDiskSpace(50)
                .setMaxCacheSizeOnVeryLowDiskSpace(10)
                .build()
        )
        //we use our own Cache key strategy to avoid double caching from different file servers
        .setCacheKeyFactory(ContentCacheKeyFactory)
        //in DEBUG mode we log all cache hits
        .apply {
            if (BuildConfig.DEBUG) setImageCacheStatsTracker(
                FrescoCacheLogging()
            )
        }
}`

@ALexanderLonsky
Copy link
Collaborator

Awesome, looks good!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants