Giter Club home page Giter Club logo

Comments (9)

thomaszurkan-optimizely avatar thomaszurkan-optimizely commented on May 22, 2024

Hi @Sinapse87,
I'm not sure what you are asking. If you look at 1.5.1 in test_app there is an example of using synchronous as opposed to asynchronous.

The call to datafileHandler.downloadDatafile(context, projectId, null);
actually updates the cache with the latest datafile from CDN. So, if you wanted to use the latest, you could do is something like the following:

 if (optimizelyManager.isDatafileCached(myApplication)) {
                optimizelyManager.initialize(myApplication);
  } else {
                optimizelyManager.initialize(myApplication, R.raw.datafile);
 }

You could have the data file in your bundle, like above or in code as a string datafile. The app would initialize with the datafile passed in. You also have access to the cached datafile directly to pass in or augment before passing it in. Does that answer your question?

from android-sdk.

Sinapse87 avatar Sinapse87 commented on May 22, 2024

Hi Thomas, thanks for your answer but it does not answer the question. We to initialize everything in out Dependency Injection framework, Dagger.

This is the code in the OptimizelyManager.java:

`
/**
* Initialize Optimizely Synchronously
*


* Instantiates and returns an {@link OptimizelyClient} instance. Will also cache the instance
* for future lookups via getClient
*
* @param context any {@link Context} instance
* @param datafile the datafile
* @return an {@link OptimizelyClient} instance
*/
public OptimizelyClient initialize(@nonnull Context context, @nonnull String datafile) {
if (!isAndroidVersionSupported()) {
return optimizelyClient;
}

    try {
        optimizelyClient = buildOptimizely(context, datafile);
    } catch (ConfigParseException e) {
        logger.error("Unable to parse compiled data file", e);
    } catch (Exception e) {
        logger.error("Unable to build OptimizelyClient instance", e);
    } catch (Error e) {
        logger.error("Unable to build OptimizelyClient instance", e);
    }

    datafileHandler.downloadDatafile(context, projectId, null);

    return optimizelyClient;
}

`

Unfortunately:

datafileHandler.downloadDatafile(context, projectId, null);

We do not see the above updating the file from the cdn. It is downloading the file from the cdn, but not storing it, because you are passing null in the listener. in fact this is your code:

`
/**
* Asynchronous download data file.
*


* We create a DatafileService intent, create a DataService connection, and bind it to the application context.
* After we receive the datafile, we unbind the service and cleanup the service connection.
* This gets the project file from the Optimizely CDN.
*
* @param context application context
* @param projectId project id of the datafile to get
* @param listener listener to call when datafile download complete
*/
public void downloadDatafile(final Context context, String projectId, final DatafileLoadedListener listener) {
final Intent intent = new Intent(context.getApplicationContext(), DatafileService.class);
if (datafileServiceConnection == null) {
this.datafileServiceConnection = new DatafileServiceConnection(projectId, context.getApplicationContext(),
new DatafileLoadedListener() {
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
@OverRide
public void onDatafileLoaded(@nullable String dataFile) {
if (listener != null) {
listener.onDatafileLoaded(dataFile);
}

                        if (datafileServiceConnection != null && datafileServiceConnection.isBound()) {
                            context.getApplicationContext().unbindService(datafileServiceConnection);
                            datafileServiceConnection = null;
                        }

                    }

                    @Override
                    public void onStop(Context context) {
                        if (listener != null) {
                            listener.onStop(context);
                        }
                    }
                });
        context.getApplicationContext().bindService(intent, datafileServiceConnection, Context.BIND_AUTO_CREATE);
    }
}

`

but the listener is null.

Am I misunderstanding something?
Thanks

from android-sdk.

thomaszurkan-optimizely avatar thomaszurkan-optimizely commented on May 22, 2024

Yes, you are missing what is happening in the DataServiceConnection. First, it uses its own internal DatafileDownloadListener that calls into the passed in listener if it exists. The DataServiceConnection creates a DatafileLoader that in turn creates a request. When this request is fulfilled, it saves it to the DatafileCache. So, the file is in data file cache. However, the cached file will never be used unless you explicitly check for it and use it as in the coding example I provided. Does that make sense?

from android-sdk.

Sinapse87 avatar Sinapse87 commented on May 22, 2024

Thomas, thanks for your answer.

So, are you suggesting to reinitialize the manager everytime we need to use it to see if there is a new version of the datafile being cached?

if (optimizelyManager.isDatafileCached(myApplication)) { optimizelyManager.initialize(myApplication); } else { optimizelyManager.initialize(myApplication, R.raw.datafile); }

from android-sdk.

thomaszurkan-optimizely avatar thomaszurkan-optimizely commented on May 22, 2024

No, that would not work. If you want to always use the CDN datafile, then I would use the async passing in the onStartListener. That always goes to cache if there and downloads the latest if not. Generally, we suggest not initializing mid experience because the customer could get re-bucketed and get a inconsistent experience.

Can you tell me exactly what you are want to achieve? Do you always want to use the latest?

from android-sdk.

Sinapse87 avatar Sinapse87 commented on May 22, 2024

We are trying to achieve a simple happy path:

  1. App starts up and downloads the new datafile overriding the file in the raw folder.
  2. If optimizely server not responding the file in raw folder would have been used.

Generally, we suggest not initializing mid experience because the customer could get re-bucketed and get a inconsistent experience.

in that case, why do we have to provide a "datafileDownloadInterval"?

Sorry, I feel this is not being documented very well.

from android-sdk.

thomaszurkan-optimizely avatar thomaszurkan-optimizely commented on May 22, 2024

No need to apologize, we are revamping our initialize because others are also finding it confusing. I would suggest using the synchronous version I mentioned above. You don't have to provide a datafileDownloadInterval. If you provide one, the datafile will be periodically polled at that interval and if a new file is found it is downloaded. If you don't provide a datafile download interval, then there will not be periodic downloads. But, you would still get a download from the initialize. The idea being that the next time you start up, you can use that downloaded datafile from cache. It is always downloaded to cache. We are thinking about adding a listener that is called when the cached file has changed.

from android-sdk.

Sinapse87 avatar Sinapse87 commented on May 22, 2024

Hi Thomas, thanks for your answer!
So, first of all, we still have three issue:

  1. Even specifying an interval, the datafile is not being pulled down. We specify 30 seconds for example, but we do not see any network call at all, excluding the first one. Not sure why the interval is multiplied per 1000 here:

` /**
* Start background checks if the the project datafile jas been updated. This starts an alarm service that checks to see if there is a
* new datafile to download at interval provided. If there is a update, the new datafile is cached.
*
* @param context application context
* @param updateInterval frequency of updates in seconds
*/
public void startBackgroundUpdates(Context context, String projectId, Long updateInterval) {
enableBackgroundCache(context, projectId);

    AlarmManager alarmManager = (AlarmManager) context
            .getSystemService(Context.ALARM_SERVICE);
    ServiceScheduler.PendingIntentFactory pendingIntentFactory = new ServiceScheduler
            .PendingIntentFactory(context.getApplicationContext());
    ServiceScheduler serviceScheduler = new ServiceScheduler(alarmManager, pendingIntentFactory,
            LoggerFactory.getLogger(ServiceScheduler.class));

    Intent intent = new Intent(context.getApplicationContext(), DatafileService.class);
    intent.putExtra(DatafileService.EXTRA_PROJECT_ID, projectId);
    serviceScheduler.schedule(intent, updateInterval * 1000);
}

`

  1. Using the approach you are suggesting, the user will not get the new datafile when the the app starts up. He will only get the previous datafile (from the cache) and the new datafile will override the new one but it will not be used.

  2. Changing experiments on the server, does change the datafile on the server, but it does not push it down to the CDN, in fact we keep getting the old datafile and an http 304.

I opened a support ticket too, but no answer.

We are thinking about adding a listener that is called when the cached file has changed.

Yes, this is exactly what I suggest in the first message. Currently, null is being passed rather than a listener. Even if you just pass the listener present in the manager, that could be enough for us to have a callback and upload the datafile manually. A much better solution would have that listener to update the datafile.

Let me know if I got something wrong, please
Thanks

from android-sdk.

thomaszurkan-optimizely avatar thomaszurkan-optimizely commented on May 22, 2024

developer docs are updated along with simpler initialize options

from android-sdk.

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.