robospice icon indicating copy to clipboard operation
robospice copied to clipboard

Loading from cache does not work after fragment is resumed

Open stoefln opened this issue 11 years ago • 10 comments

As long as I am staying in the same fragment the cache works perfectly fine. BUT as soon as I am switching the app to the background and then reloading the data onResume(), the cache is not valid anymore and a network connection is made.

Here is my code (in fragment.onResume()):

protected void loadData(final OnDataLoadListener onDataLoadListener) {
       final ReverseStringRequestListener listener = new ReverseStringRequestListener(onDataLoadListener);
       final String cacheKey = "cacheKey234234";
       final ConfigFeedRequest request = new ConfigFeedRequest("http://app.tty-eli.com/index.php?id=3");
       getSpiceManager().getFromCacheAndLoadFromNetworkIfExpired(request, cacheKey, DurationInMillis.ONE_SECOND * 50, listener);
}

Any ideas why this might happen? I am creating the SpiceManager in the class header of the fragment like that:

private SpiceManager spiceManager = new SpiceManager(InMemorySpiceService.class);

Here is the log:

10-07 16:07:06.595    5618-5618/at.tty_eli.app D//SpiceManager.java:212﹕ 16:07:06.606 main SpiceManager started.
10-07 16:07:06.605    5618-5618/at.tty_eli.app V/AppointmentFragment_﹕ onResume
10-07 16:07:06.605    5618-5618/at.tty_eli.app D//SpiceManager.java:489﹕ 16:07:06.619 main adding request to request queue
10-07 16:07:06.605    5618-5618/at.tty_eli.app D/AbsListView﹕ onVisibilityChanged() is called, visibility : 0
10-07 16:07:06.605    5618-5618/at.tty_eli.app D/AbsListView﹕ unregisterIRListener() is called
10-07 16:07:06.615    5618-6034/at.tty_eli.app V//SpiceManager.java:1191﹕ 16:07:06.623 SpiceManagerThread 2 Binding to service.
10-07 16:07:06.625    5618-5618/at.tty_eli.app D//SpiceService.java:134﹕ 16:07:06.631 main SpiceService instance created.
10-07 16:07:06.625    5618-5618/at.tty_eli.app D/AbsListView﹕ unregisterIRListener() is called
10-07 16:07:06.625    5618-6034/at.tty_eli.app V//SpiceManager.java:1197﹕ 16:07:06.633 SpiceManagerThread 2 Binding to service succeeded.
10-07 16:07:06.625    5618-6034/at.tty_eli.app D//SpiceManager.java:1245﹕ 16:07:06.637 SpiceManagerThread 2 Waiting for service to be bound.
10-07 16:07:06.645    5618-5618/at.tty_eli.app V//SpiceService.java:506﹕ 16:07:06.656 main Pending requests : 0
10-07 16:07:06.645    5618-5618/at.tty_eli.app V//SpiceService.java:508﹕ 16:07:06.658 main Stop foreground
10-07 16:07:06.655    5618-5618/at.tty_eli.app D//SpiceServiceListenerNotifier.java:33﹕ 16:07:06.662 main Message Queue starting
10-07 16:07:06.655    5618-5618/at.tty_eli.app D//SpiceManager.java:1088﹕ 16:07:06.664 main Bound to service : InMemorySpiceService
10-07 16:07:06.665    5618-6034/at.tty_eli.app D//SpiceManager.java:1252﹕ 16:07:06.673 SpiceManagerThread 2 Bound ok.
10-07 16:07:06.665    5618-6034/at.tty_eli.app D//SpiceManager.java:286﹕ 16:07:06.678 SpiceManagerThread 2 Sending request to service : CachedSpiceRequest
10-07 16:07:06.675    5618-6034/at.tty_eli.app D//RequestProcessor.java:63﹕ 16:07:06.683 SpiceManagerThread 2 Adding request to queue 1121951496: CachedSpiceRequest [requestCacheKey=cacheKey234234, cacheDuration=50000, spiceRequest=at.tty_eli.app.network.ConfigFeedRequest@42c24c50] size is 0
10-07 16:07:06.675    5618-6034/at.tty_eli.app D//RequestProcessor.java:85﹕ 16:07:06.689 SpiceManagerThread 2 Adding entry for type class at.tty_eli.app.network.ConfigFeedResponse and cacheKey cacheKey234234.
10-07 16:07:06.685    5618-6034/at.tty_eli.app D//RequestProgressManager.java:61﹕ 16:07:06.692 SpiceManagerThread 2 Request was added to queue.
10-07 16:07:06.685    5618-6034/at.tty_eli.app D//SpiceServiceListenerNotifier.java:146﹕ 16:07:06.695 SpiceManagerThread 2 Message queue is Handler (android.os.Handler) {42dfa580}
10-07 16:07:06.685    5618-5618/at.tty_eli.app D//SpiceServiceListenerNotifier.java:175﹕ 16:07:06.698 main Processing request added: CachedSpiceRequest [requestCacheKey=cacheKey234234, cacheDuration=50000, spiceRequest=at.tty_eli.app.network.ConfigFeedRequest@42c24c50]
10-07 16:07:06.695    5618-6034/at.tty_eli.app D//RequestProgressManager.java:82﹕ 16:07:06.703 SpiceManagerThread 2 Sending progress PENDING
10-07 16:07:06.695    5618-6034/at.tty_eli.app D//SpiceServiceListenerNotifier.java:146﹕ 16:07:06.708 SpiceManagerThread 2 Message queue is Handler (android.os.Handler) {42dfa580}
10-07 16:07:06.705    5618-5618/at.tty_eli.app V//DefaultRequestListenerNotifier.java:131﹕ 16:07:06.710 main Notifying 1 listeners of progress com.octo.android.robospice.request.listener.RequestProgress@42c24c88
10-07 16:07:06.705    5618-6038/at.tty_eli.app D//DefaultRequestRunner.java:83﹕ 16:07:06.714 Thread-6031 Processing request : CachedSpiceRequest [requestCacheKey=cacheKey234234, cacheDuration=50000, spiceRequest=at.tty_eli.app.network.ConfigFeedRequest@42c24c50]
10-07 16:07:06.705    5618-6034/at.tty_eli.app V//SpiceService.java:506﹕ 16:07:06.713 SpiceManagerThread 2 Pending requests : 1
10-07 16:07:06.705    5618-6038/at.tty_eli.app D//DefaultRequestRunner.java:97﹕ 16:07:06.718 Thread-6031 Loading request from cache : CachedSpiceRequest [requestCacheKey=cacheKey234234, cacheDuration=50000, spiceRequest=at.tty_eli.app.network.ConfigFeedRequest@42c24c50]
10-07 16:07:06.715    5618-6038/at.tty_eli.app D//RequestProgressManager.java:82﹕ 16:07:06.720 Thread-6031 Sending progress READING_FROM_CACHE
10-07 16:07:06.715    5618-6038/at.tty_eli.app D//SpiceServiceListenerNotifier.java:146﹕ 16:07:06.727 Thread-6031 Message queue is Handler (android.os.Handler) {42dfa580}
10-07 16:07:06.715    5618-5618/at.tty_eli.app V//DefaultRequestListenerNotifier.java:131﹕ 16:07:06.729 main Notifying 1 listeners of progress com.octo.android.robospice.request.listener.RequestProgress@42b0d130
10-07 16:07:06.725    5618-6034/at.tty_eli.app V//SpiceService.java:508﹕ 16:07:06.716 SpiceManagerThread 2 Stop foreground
10-07 16:07:06.725    5618-6038/at.tty_eli.app D//LruCacheObjectPersister.java:47﹕ 16:07:06.732 Thread-6031 Miss from lru cache for cacheKey234234
10-07 16:07:06.725    5618-6038/at.tty_eli.app D//LruCacheObjectPersister.java:47﹕ 16:07:06.737 Thread-6031 Miss from lru cache for cacheKey234234
10-07 16:07:06.735    5618-6038/at.tty_eli.app D//DefaultRequestRunner.java:129﹕ 16:07:06.741 Thread-6031 Cache content not available or expired or disabled
10-07 16:07:06.745    5618-6038/at.tty_eli.app D//DefaultRequestRunner.java:148﹕ 16:07:06.751 Thread-6031 Calling netwok request.
10-07 16:07:06.745    5618-6038/at.tty_eli.app D//RequestProgressManager.java:82﹕ 16:07:06.755 Thread-6031 Sending progress LOADING_FROM_NETWORK
10-07 16:07:06.755    5618-6038/at.tty_eli.app D//SpiceServiceListenerNotifier.java:146﹕ 16:07:06.760 Thread-6031 Message queue is Handler (android.os.Handler) {42dfa580}
10-07 16:07:06.755    5618-5618/at.tty_eli.app V//DefaultRequestListenerNotifier.java:131﹕ 16:07:06.763 main Notifying 1 listeners of progress com.octo.android.robospice.request.listener.RequestProgress@42c11c38
10-07 16:07:10.435    5618-6038/at.tty_eli.app D//DefaultRequestRunner.java:151﹕ 16:07:10.442 Thread-6031 Network request call ended.
10-07 16:07:10.435    5618-6038/at.tty_eli.app D//DefaultRequestRunner.java:171﹕ 16:07:10.447 Thread-6031 Start caching content...
10-07 16:07:10.445    5618-6038/at.tty_eli.app D//RequestProgressManager.java:82﹕ 16:07:10.453 Thread-6031 Sending progress WRITING_TO_CACHE
10-07 16:07:10.455    5618-6038/at.tty_eli.app D//SpiceServiceListenerNotifier.java:146﹕ 16:07:10.459 Thread-6031 Message queue is Handler (android.os.Handler) {42dfa580}
10-07 16:07:10.455    5618-5618/at.tty_eli.app V//DefaultRequestListenerNotifier.java:131﹕ 16:07:10.462 main Notifying 1 listeners of progress com.octo.android.robospice.request.listener.RequestProgress@42a3aa28
10-07 16:07:10.455    5618-6038/at.tty_eli.app D//LruCacheObjectPersister.java:74﹕ 16:07:10.467 Thread-6031 Put in lru cache for cacheKey234234
10-07 16:07:10.465    5618-6038/at.tty_eli.app D//RequestProgressManager.java:82﹕ 16:07:10.473 Thread-6031 Sending progress COMPLETE
10-07 16:07:10.475    5618-6038/at.tty_eli.app D//SpiceServiceListenerNotifier.java:146﹕ 16:07:10.480 Thread-6031 Message queue is Handler (android.os.Handler) {42dfa580}
10-07 16:07:10.475    5618-5618/at.tty_eli.app V//DefaultRequestListenerNotifier.java:131﹕ 16:07:10.483 main Notifying 1 listeners of progress com.octo.android.robospice.request.listener.RequestProgress@42a977a0
10-07 16:07:10.475    5618-6038/at.tty_eli.app D//SpiceServiceListenerNotifier.java:146﹕ 16:07:10.488 Thread-6031 Message queue is Handler (android.os.Handler) {42dfa580}
10-07 16:07:10.485    5618-5618/at.tty_eli.app V//DefaultRequestListenerNotifier.java:166﹕ 16:07:10.491 main Notifying 1 listeners of request success
10-07 16:07:10.485    5618-5618/at.tty_eli.app V//DefaultRequestListenerNotifier.java:172﹕ 16:07:10.494 main Notifying ReverseStringRequestListener
10-07 16:07:10.485    5618-5618/at.tty_eli.app V/AppointmentFragment_﹕ onDataReady
10-07 16:07:10.495    5618-6038/at.tty_eli.app V//RequestProgressManager.java:161﹕ 16:07:10.503 Thread-6031 Removing CachedSpiceRequest [requestCacheKey=cacheKey234234, cacheDuration=50000, spiceRequest=at.tty_eli.app.network.ConfigFeedRequest@42c24c50]  size is 1
10-07 16:07:10.505    5618-6038/at.tty_eli.app D//RequestProgressManager.java:91﹕ 16:07:10.508 Thread-6031 Sending all request complete.
10-07 16:07:10.515    5618-6038/at.tty_eli.app V//SpiceService.java:495﹕ 16:07:10.520 Thread-6031 Pending requests : 0
10-07 16:07:10.515    5618-6038/at.tty_eli.app D//SpiceServiceListenerNotifier.java:146﹕ 16:07:10.524 Thread-6031 Message queue is Handler (android.os.Handler) {42dfa580}
10-07 16:07:10.545    5618-5618/at.tty_eli.app D/AbsListView﹕ unregisterIRListener() is called
10-07 16:07:10.565    5618-6038/at.tty_eli.app D//DefaultRequestRunner.java:295﹕ 16:07:10.569 Thread-6031 It tooks 3828 ms to process request CachedSpiceRequest [requestCacheKey=cacheKey234234, cacheDuration=50000, spiceRequest=at.tty_eli.app.network.ConfigFeedRequest@42c24c50].

stoefln avatar Oct 08 '14 18:10 stoefln

I guess the problem comes from the fact that each fragment manages its own SpiceManager.

If so, the SpiceManager is stopped and a new one is restarted when you press home and resume the app. Then they start a different spice service. As you service seems to have a memory cache only, it is not filled anymore with you value.

But it doesn't explain why the same manager can be static and that works.

Can you try with a real disk cache ?

If you want the SpiceManager to be shared by fragments, manage it at the activity level and pass it to the fragments.

S. Le 2014-10-08 14:49, "Stephan Petzl" [email protected] a écrit :

As long as I am staying in the same fragment the cache works perfectly fine. BUT as soon as I am switching the app to the background and then reloading the data onResume(), the cache is not valid anymore and a network connection is made.

Here is my code (in fragment.onResume()):

protected void loadData(final OnDataLoadListener onDataLoadListener) { final ReverseStringRequestListener listener = new ReverseStringRequestListener(onDataLoadListener); final String cacheKey = "cacheKey234234"; final ConfigFeedRequest request = new ConfigFeedRequest("http://app.tty-eli.com/index.php?id=3"); getSpiceManager().getFromCacheAndLoadFromNetworkIfExpired(request, cacheKey, DurationInMillis.ONE_SECOND * 50, listener); }

Any ideas why this might happen? I am creating the SpiceManager in the class header of the fragment like that:

private SpiceManager spiceManager = new SpiceManager(InMemorySpiceService.class);

Here is the log:

10-07 16:07:06.595 5618-5618/at.tty_eli.app D//SpiceManager.java:212﹕ 16:07:06.606 main SpiceManager started. 10-07 16:07:06.605 5618-5618/at.tty_eli.app V/AppointmentFragment_﹕ onResume 10-07 16:07:06.605 5618-5618/at.tty_eli.app D//SpiceManager.java:489﹕ 16:07:06.619 main adding request to request queue 10-07 16:07:06.605 5618-5618/at.tty_eli.app D/AbsListView﹕ onVisibilityChanged() is called, visibility : 0 10-07 16:07:06.605 5618-5618/at.tty_eli.app D/AbsListView﹕ unregisterIRListener() is called 10-07 16:07:06.615 5618-6034/at.tty_eli.app V//SpiceManager.java:1191﹕ 16:07:06.623 SpiceManagerThread 2 Binding to service. 10-07 16:07:06.625 5618-5618/at.tty_eli.app D//SpiceService.java:134﹕ 16:07:06.631 main SpiceService instance created. 10-07 16:07:06.625 5618-5618/at.tty_eli.app D/AbsListView﹕ unregisterIRListener() is called 10-07 16:07:06.625 5618-6034/at.tty_eli.app V//SpiceManager.java:1197﹕ 16:07:06.633 SpiceManagerThread 2 Binding to service succeeded. 10-07 16:07:06.625 5618-6034/at.tty_eli.app D//SpiceManager.java:1245﹕ 16:07:06.637 SpiceManagerThread 2 Waiting for service to be bound. 10-07 16:07:06.645 5618-5618/at.tty_eli.app V//SpiceService.java:506﹕ 16:07:06.656 main Pending requests : 0 10-07 16:07:06.645 5618-5618/at.tty_eli.app V//SpiceService.java:508﹕ 16:07:06.658 main Stop foreground 10-07 16:07:06.655 5618-5618/at.tty_eli.app D//SpiceServiceListenerNotifier.java:33﹕ 16:07:06.662 main Message Queue starting 10-07 16:07:06.655 5618-5618/at.tty_eli.app D//SpiceManager.java:1088﹕ 16:07:06.664 main Bound to service : InMemorySpiceService 10-07 16:07:06.665 5618-6034/at.tty_eli.app D//SpiceManager.java:1252﹕ 16:07:06.673 SpiceManagerThread 2 Bound ok. 10-07 16:07:06.665 5618-6034/at.tty_eli.app D//SpiceManager.java:286﹕ 16:07:06.678 SpiceManagerThread 2 Sending request to service : CachedSpiceRequest 10-07 16:07:06.675 5618-6034/at.tty_eli.app D//RequestProcessor.java:63﹕ 16:07:06.683 SpiceManagerThread 2 Adding request to queue 1121951496: CachedSpiceRequest [requestCacheKey=cacheKey234234, cacheDuration=50000, spiceRequest=at.tty_eli.app.network.ConfigFeedRequest@42c24c50] size is 0 10-07 16:07:06.675 5618-6034/at.tty_eli.app D//RequestProcessor.java:85﹕ 16:07:06.689 SpiceManagerThread 2 Adding entry for type class at.tty_eli.app.network.ConfigFeedResponse and cacheKey cacheKey234234. 10-07 16:07:06.685 5618-6034/at.tty_eli.app D//RequestProgressManager.java:61﹕ 16:07:06.692 SpiceManagerThread 2 Request was added to queue. 10-07 16:07:06.685 5618-6034/at.tty_eli.app D//SpiceServiceListenerNotifier.java:146﹕ 16:07:06.695 SpiceManagerThread 2 Message queue is Handler (android.os.Handler) {42dfa580} 10-07 16:07:06.685 5618-5618/at.tty_eli.app D//SpiceServiceListenerNotifier.java:175﹕ 16:07:06.698 main Processing request added: CachedSpiceRequest [requestCacheKey=cacheKey234234, cacheDuration=50000, spiceRequest=at.tty_eli.app.network.ConfigFeedRequest@42c24c50] 10-07 16:07:06.695 5618-6034/at.tty_eli.app D//RequestProgressManager.java:82﹕ 16:07:06.703 SpiceManagerThread 2 Sending progress PENDING 10-07 16:07:06.695 5618-6034/at.tty_eli.app D//SpiceServiceListenerNotifier.java:146﹕ 16:07:06.708 SpiceManagerThread 2 Message queue is Handler (android.os.Handler) {42dfa580} 10-07 16:07:06.705 5618-5618/at.tty_eli.app V//DefaultRequestListenerNotifier.java:131﹕ 16:07:06.710 main Notifying 1 listeners of progress com.octo.android.robospice.request.listener.RequestProgress@42c24c88 10-07 16:07:06.705 5618-6038/at.tty_eli.app D//DefaultRequestRunner.java:83﹕ 16:07:06.714 Thread-6031 Processing request : CachedSpiceRequest [requestCacheKey=cacheKey234234, cacheDuration=50000, spiceRequest=at.tty_eli.app.network.ConfigFeedRequest@42c24c50] 10-07 16:07:06.705 5618-6034/at.tty_eli.app V//SpiceService.java:506﹕ 16:07:06.713 SpiceManagerThread 2 Pending requests : 1 10-07 16:07:06.705 5618-6038/at.tty_eli.app D//DefaultRequestRunner.java:97﹕ 16:07:06.718 Thread-6031 Loading request from cache : CachedSpiceRequest [requestCacheKey=cacheKey234234, cacheDuration=50000, spiceRequest=at.tty_eli.app.network.ConfigFeedRequest@42c24c50] 10-07 16:07:06.715 5618-6038/at.tty_eli.app D//RequestProgressManager.java:82﹕ 16:07:06.720 Thread-6031 Sending progress READING_FROM_CACHE 10-07 16:07:06.715 5618-6038/at.tty_eli.app D//SpiceServiceListenerNotifier.java:146﹕ 16:07:06.727 Thread-6031 Message queue is Handler (android.os.Handler) {42dfa580} 10-07 16:07:06.715 5618-5618/at.tty_eli.app V//DefaultRequestListenerNotifier.java:131﹕ 16:07:06.729 main Notifying 1 listeners of progress com.octo.android.robospice.request.listener.RequestProgress@42b0d130 10-07 16:07:06.725 5618-6034/at.tty_eli.app V//SpiceService.java:508﹕ 16:07:06.716 SpiceManagerThread 2 Stop foreground 10-07 16:07:06.725 5618-6038/at.tty_eli.app D//LruCacheObjectPersister.java:47﹕ 16:07:06.732 Thread-6031 Miss from lru cache for cacheKey234234 10-07 16:07:06.725 5618-6038/at.tty_eli.app D//LruCacheObjectPersister.java:47﹕ 16:07:06.737 Thread-6031 Miss from lru cache for cacheKey234234 10-07 16:07:06.735 5618-6038/at.tty_eli.app D//DefaultRequestRunner.java:129﹕ 16:07:06.741 Thread-6031 Cache content not available or expired or disabled 10-07 16:07:06.745 5618-6038/at.tty_eli.app D//DefaultRequestRunner.java:148﹕ 16:07:06.751 Thread-6031 Calling netwok request. 10-07 16:07:06.745 5618-6038/at.tty_eli.app D//RequestProgressManager.java:82﹕ 16:07:06.755 Thread-6031 Sending progress LOADING_FROM_NETWORK 10-07 16:07:06.755 5618-6038/at.tty_eli.app D//SpiceServiceListenerNotifier.java:146﹕ 16:07:06.760 Thread-6031 Message queue is Handler (android.os.Handler) {42dfa580} 10-07 16:07:06.755 5618-5618/at.tty_eli.app V//DefaultRequestListenerNotifier.java:131﹕ 16:07:06.763 main Notifying 1 listeners of progress com.octo.android.robospice.request.listener.RequestProgress@42c11c38 10-07 16:07:10.435 5618-6038/at.tty_eli.app D//DefaultRequestRunner.java:151﹕ 16:07:10.442 Thread-6031 Network request call ended. 10-07 16:07:10.435 5618-6038/at.tty_eli.app D//DefaultRequestRunner.java:171﹕ 16:07:10.447 Thread-6031 Start caching content... 10-07 16:07:10.445 5618-6038/at.tty_eli.app D//RequestProgressManager.java:82﹕ 16:07:10.453 Thread-6031 Sending progress WRITING_TO_CACHE 10-07 16:07:10.455 5618-6038/at.tty_eli.app D//SpiceServiceListenerNotifier.java:146﹕ 16:07:10.459 Thread-6031 Message queue is Handler (android.os.Handler) {42dfa580} 10-07 16:07:10.455 5618-5618/at.tty_eli.app V//DefaultRequestListenerNotifier.java:131﹕ 16:07:10.462 main Notifying 1 listeners of progress com.octo.android.robospice.request.listener.RequestProgress@42a3aa28 10-07 16:07:10.455 5618-6038/at.tty_eli.app D//LruCacheObjectPersister.java:74﹕ 16:07:10.467 Thread-6031 Put in lru cache for cacheKey234234 10-07 16:07:10.465 5618-6038/at.tty_eli.app D//RequestProgressManager.java:82﹕ 16:07:10.473 Thread-6031 Sending progress COMPLETE 10-07 16:07:10.475 5618-6038/at.tty_eli.app D//SpiceServiceListenerNotifier.java:146﹕ 16:07:10.480 Thread-6031 Message queue is Handler (android.os.Handler) {42dfa580} 10-07 16:07:10.475 5618-5618/at.tty_eli.app V//DefaultRequestListenerNotifier.java:131﹕ 16:07:10.483 main Notifying 1 listeners of progress com.octo.android.robospice.request.listener.RequestProgress@42a977a0 10-07 16:07:10.475 5618-6038/at.tty_eli.app D//SpiceServiceListenerNotifier.java:146﹕ 16:07:10.488 Thread-6031 Message queue is Handler (android.os.Handler) {42dfa580} 10-07 16:07:10.485 5618-5618/at.tty_eli.app V//DefaultRequestListenerNotifier.java:166﹕ 16:07:10.491 main Notifying 1 listeners of request success 10-07 16:07:10.485 5618-5618/at.tty_eli.app V//DefaultRequestListenerNotifier.java:172﹕ 16:07:10.494 main Notifying ReverseStringRequestListener 10-07 16:07:10.485 5618-5618/at.tty_eli.app V/AppointmentFragment_﹕ onDataReady 10-07 16:07:10.495 5618-6038/at.tty_eli.app V//RequestProgressManager.java:161﹕ 16:07:10.503 Thread-6031 Removing CachedSpiceRequest [requestCacheKey=cacheKey234234, cacheDuration=50000, spiceRequest=at.tty_eli.app.network.ConfigFeedRequest@42c24c50] size is 1 10-07 16:07:10.505 5618-6038/at.tty_eli.app D//RequestProgressManager.java:91﹕ 16:07:10.508 Thread-6031 Sending all request complete. 10-07 16:07:10.515 5618-6038/at.tty_eli.app V//SpiceService.java:495﹕ 16:07:10.520 Thread-6031 Pending requests : 0 10-07 16:07:10.515 5618-6038/at.tty_eli.app D//SpiceServiceListenerNotifier.java:146﹕ 16:07:10.524 Thread-6031 Message queue is Handler (android.os.Handler) {42dfa580} 10-07 16:07:10.545 5618-5618/at.tty_eli.app D/AbsListView﹕ unregisterIRListener() is called 10-07 16:07:10.565 5618-6038/at.tty_eli.app D//DefaultRequestRunner.java:295﹕ 16:07:10.569 Thread-6031 It tooks 3828 ms to process request CachedSpiceRequest [requestCacheKey=cacheKey234234, cacheDuration=50000, spiceRequest=at.tty_eli.app.network.ConfigFeedRequest@42c24c50].

— Reply to this email directly or view it on GitHub https://github.com/stephanenicolas/robospice/issues/370.

stephanenicolas avatar Oct 09 '14 23:10 stephanenicolas

I removed my comment with the static instance of spice manager again. It does not work as expected.

Then they start a different spice service.

I don't get this part. Isn't the whole point of using a service, exactly to have a decoupled instance which is not depending on the live cycle of activities and fragments? Why is instancing a new SpiceManager influencing the cache?

stoefln avatar Oct 10 '14 12:10 stoefln

My Service looks like this:

package at.anne_eli.app.service;
import android.Manifest;
import android.app.Application;
import android.content.Context;
import android.content.pm.PackageManager;
import com.octo.android.robospice.SpiceService;
import com.octo.android.robospice.networkstate.NetworkStateChecker;
import com.octo.android.robospice.persistence.CacheManager;
import com.octo.android.robospice.persistence.ObjectPersister;
import com.octo.android.robospice.persistence.memory.CacheItem;
import com.octo.android.robospice.persistence.memory.LruCache;
import com.octo.android.robospice.persistence.memory.LruCacheObjectPersister;
import at.anne_eli.app.network.ConfigFeedResponse;
/**
 * Created by stephan on 07.10.14.
 */
public class InMemorySpiceService extends SpiceService {
    public InMemorySpiceService() {
        super();
    }
    @Override
    protected NetworkStateChecker getNetworkStateChecker() {
        return new MyNetworkStateChecker();
    }
    @Override
    public CacheManager createCacheManager(Application application) {
        CacheManager manager = new CacheManager();
        manager.addPersister(new MyPersister(ConfigFeedResponse.class, new LruCache(1024 * 1024)));
        return manager;
    }
    class MyPersister extends LruCacheObjectPersister {
        public MyPersister(Class clazz, LruCache> lruCache) {
            super(clazz, lruCache);
        }
        public MyPersister(ObjectPersister decoratedPersister, LruCache> lruCache) {
            super(decoratedPersister, lruCache);
        }
        @Override
        public boolean canHandleClass(Class> clazz) {
            if (clazz.equals(ConfigFeedResponse.class)) {
                return true;
            }
            return super.canHandleClass(clazz);
        }
    }
    private class MyNetworkStateChecker implements NetworkStateChecker {
        @Override
        public boolean isNetworkAvailable(final Context context) {
            return true;
        }
        @Override
        public void checkPermissions(final Context context) {
            checkHasPermission(context, Manifest.permission.ACCESS_NETWORK_STATE);
            checkHasPermission(context, Manifest.permission.INTERNET);
        }
        private boolean checkHasPermission(final Context context, final String permissionName) {
            final boolean hasPermission = context.getPackageManager().checkPermission(permissionName, context.getPackageName()) == PackageManager.PERMISSION_GRANTED;
            if (!hasPermission) {
                throw new SecurityException("Application doesn\'t declare ");
            }
            return true;
        }
    }
}

stoefln avatar Oct 10 '14 13:10 stoefln

Just debugged a little further: Indeed, each time I switch from one fragment to another a new SpiceService and thus a new CacheManager is created. Can you tell me why this is happening?

stoefln avatar Oct 10 '14 14:10 stoefln

I don't understand @Stephan Petzl, as service is like an activity. These things live and die and have a life cycle. There are no chances you can get a service to survive for ever. So, yes, every time you start a new spice manager it will start a new service. The only exception is that if a spice service is already started, your new spicemanager will use it, but this rarely happen and no one has a real control over it.

There is a true limitation in your approach when using a RAM only cache manager. This can be super fast and convenient but you don't persist the state of the cache if you don't write it somewhere.

So there are 2 solutions here :

  • either you use a disk cache as intended in RS
  • or you can use a small hack and use a cache manager in RAM only that is a singleton and reused by all your instances of your spice service. But even, then you will never be able to guarantee that this cache manager will always be there as android apps can be wiped out by the system at any time. This is a the core of android programming model : make apps transients so that they don't fill up the system memory for ever..

S.

2014-10-10 10:20 GMT-04:00 Stephan Petzl [email protected]:

Just debugged a little further: Indeed, each time I switch from one fragment to another a new SpiceService and thus a new CacheManager is created. Can you tell me why this is happening?

— Reply to this email directly or view it on GitHub https://github.com/stephanenicolas/robospice/issues/370#issuecomment-58662031 .

stephanenicolas avatar Oct 13 '14 12:10 stephanenicolas

@stephanenicolas Thanks for your explanations! And I get it now: Since this is a bound service, it will be cleaned up by android as soon as there are no references to it anymore. That makes totally sense from a technical side of things. However, wouldn't you agree, that it's kind of counter-intuitive, that the whole caching is not working anymore as soon as you use the LruCacheObjectPersister and you pause and resume the app? (That's also how you have implemented it in your samples.) For me from a User perspective, it's not intuitive that the cache is not returning a cached object after I rotate the device- especially when I know that the big advantage of RoboSpice is that it runs in a service (which is decoupled from the activity live cycle).

I can totally see your point with saving the data to disc- but for my application I would really like to have a fast implementation, which delivers data from RAM instantly and only retrieves from disc when RAM is not available anymore. I don't want to criticize roboSpice- it's a wonderful piece of library- that's just my 2 cents of feedback.

stoefln avatar Oct 15 '14 22:10 stoefln

@stoefln, In our application, we have extended the SpiceManager by adding our own execute method and implemented a singleton LruCache. This way, we are synchronously checking the LruCache before anything has been submitted to the SpiceService, giving us a considerable performance gain when there is a cache hit. This is a simple paradigm which improved responsiveness for us dramatically, but it adds "synchronicity" and is not part of the RoboSpice's underlying idea. However, if I understood your challenge correctly, it may help in your case.

nkeskinov avatar Oct 16 '14 09:10 nkeskinov

Hi @Nikola Keskinov and @Stephan Petzl,

Stephan, from a user perspective I know it can be surprising but that is what Android programming is about : preserving resources through life cycles. Things live and die and free resources on Android.

So, I think it's really a better idea to stick to using a disk cache and use RAM caching with great care in RS and in Android in general. That's why RS provides so many options for disk caching data.

Adding a RAM cache is still possible. Personally I would prefer a singleton RAM cache to decorate/backed by a disk cache at the service level. But maybe @Nikola Keskinov's solution is a simpler .. I would need to see it in a PR to judge ;)

S.

2014-10-16 5:25 GMT-04:00 Nikola Keskinov [email protected]:

@stoefln https://github.com/stoefln, In our application, we have extended the SpiceManager by adding our own execute method and implemented a singleton LruCache. This way, we are synchronously checking the LruCache before anything has been submitted to the SpiceService, giving us a considerable performance gain when there is a cache hit. This is a simple paradigm which improved responsiveness for us dramatically, but it adds "synchronicity" and is not part of the RoboSpice's underlying idea. However, if I understood your challenge correctly, it may help in your case.

— Reply to this email directly or view it on GitHub https://github.com/stephanenicolas/robospice/issues/370#issuecomment-59335808 .

stephanenicolas avatar Oct 16 '14 09:10 stephanenicolas

Hi @stephanenicolas,

The solution we have is still too messy and coupled with our app, but I do plan to generalize and integrate it into RoboSpice as a nice PR one day. However, the idea of it, in simplest terms is:

// may not be syntactically correct as it is an excerpt of a bigger class with out-of-this-context code
public class APICacheSpiceManager extends SpiceManager {

    // singleton memory cache, extension/wrapper of Android's LruCache
    private final APICache cache = APICache.getInstance();

    public <T, R> void fetch(Context context, AbstractSpiceRequest<T, R> req, Object cacheKey, long cacheDuration, RequestListener<T> listener) {
        T result;
        if (cacheKey != null) {
            result = (T) cache.get(cacheKey, cacheDuration);

            if (result != null) {
                Log.d("FETCH", ms(time) + "Instantly loading request from L1 cache: " + req);
                listener.onRequestSuccess(result);
                return;
            } else {
                // CacheFillerListener is going to save the result in our memory cache, storing the timestamp of the creation as well (for cache duration)
                listener = new CacheFillerListener<>(cache, cacheKey, listener);
                CacheManager cacheManager = getCacheManager((Application) context.getApplicationContext());
                result = cacheManager.loadDataFromCache(req.getResultType(), cacheKey, cacheDuration);
                if (result != null) {
                    Log.d("FETCH", ms(time) + "Instantly request loaded from L2 cache: " + req);
                    // send cached result immediately and return
                    listener.onRequestSuccess(result);
                    return;
                } else {
                    Log.d("FETCH", "Executing Spice request: " + req + " ON " + this);
                    super.execute(req, cacheKey, DurationInMillis.ALWAYS_EXPIRED, listener);
                }
            }
        } else {
            // use network etc.
        }
}

If there is a cache hit either in memory or disk cache (L1 or L2), no RoboSpice mechanism is triggered (request queueing, spice service, asynchronicity...). Instead, request listener's onSuccess will be immediately executed. According to our performance tests, there was a great improvement of using the cache this way, compared to the async use via service.

nkeskinov avatar Oct 16 '14 10:10 nkeskinov

@nkeskinov thanks for sharing your code! I think it would be great if we could find a generic concept which could go into the RoboSpice code. Would be happy to participate in your PR!

stoefln avatar Oct 17 '14 15:10 stoefln