在使用RoboSpice执行网络请求之前从缓存获取数据

时间:2014-02-12 17:57:24

标签: android robospice

我正在使用RoboSpice并希望在我的应用中出现以下行为:

  • 用户启动需要服务器数据的活动
  • spiceManager检查数据是否被缓存,如果是,则返回。
  • 无论是否返回缓存数据,都会向服务器发出请求
  • 当新服务从服务器到达时,我用它更新UI(如果活动仍处于活动状态)

它应该像facebook app:当你打开它时,你会立即看到一个过时的时间线,并最终收到更新。

起初我认为spiceManager.getFromCacheAndLoadFromNetworkIfExpired()是实现这一目标的好方法,但如果数据缓存且有效,它只会返回缓存,而不会立即发出网络请求。我已经使用DurationInMillis.ALWAYS_EXPIREDDurationInMillis.ALWAYS_RETURNED进行了尝试。

我应该使用getFromCache()来检索缓存数据,然后在onRequestSuccess()内,使用always_expired作为参数调用spiceManager.execute()吗?或者有更好/更简单的方法来做到这一点?

提前感谢您的帮助!

[编辑] 这些链接可能会增加讨论: https://groups.google.com/forum/#!topic/robospice/n5ffupPIpkE/discussion https://groups.google.com/forum/#!topic/robospice/LtoqIXk5JpA

3 个答案:

答案 0 :(得分:3)

我有同样的任务,并使用here的方法:

  1. 从缓存加载视图数据(如果存在)
  2. 同时,请求从网络加载新版本的请求。如果数据已更改,请更新视图。
  3. 以下是示例代码

    SpecialOffersRequest request = new SpecialOffersRequest();
    spiceManager.getFromCache(SpecialOffer.List.class, request.getCacheKey(), ALWAYS_RETURNED, new SpecialOffersRequestListener());
    spiceManager.execute(request, request.getCacheKey(), request.getCacheExpiryDuration(), new SpecialOffersRequestListener());
    

    如您所见,一个SpecialOffersRequestListener用于从缓存中获取和从网络获取请求。但是,我必须做一个小技巧(参见下面的 dataInCache 用法)来处理离线情况,如果缓存中有某些东西,不要担心用户“无连接”显示:

    private final class SpecialOffersRequestListener implements RequestListener<SpecialOffer.List> {
        @Override
        public void onRequestFailure(SpiceException spiceException) {
            if (spiceException instanceof NoNetworkException && dataInCache) {
                // Ignore network problems if there is some data in the cache.
                return;
            }
    
            ActionHelper.showError(getActivity(), "Failed to load special offers.", spiceException);
        }
    
        @Override
        public void onRequestSuccess(SpecialOffer.List result) {
            dataInCache = true;
            ...
        }
    }
    

答案 1 :(得分:2)

Aka_sh的方法有一个重要的缺点:当你的应用程序重新启动时(无论是用户还是Android),你的dataInCache标志将被重置并返回false,尽管可能有数据缓存在永久存储器中(如文件或数据库) )。

更好的解决方案是使用1.4.6-SNAPSHOT中引入的SpiceManager的isDataInCachegetDateOfDataInCache。这些方法检查数据在给定的有效期内是否在缓存中可用,并返回数据放入缓存的日期。

要记住一件事:两种方法都可以异步处理,然后返回Future<Boolean> / Future<Data>,所以如果你想等待一个结果(它不需要很长时间才能得到它),使用Future.get(),例如:

spiceManager.isDataInCache(MyCachedObj.class, cacheKey, DurationInMillis.ALWAYS_RETURNED).get();

答案 2 :(得分:0)

我使用以下方法来解决此问题。此外,下面的代码将解决您的活动A加载时的问题,并且您的用户在后台加载robospice的同时决定导航到活动B.当用户导航回活动A时,您的信息将可供使用(问题2)。

第1步:添加以下代码,在onStart方法中添加PendingRequestListener。这将允许您解决问题2,因为@Override public void onStart() { super.onStart(); FragmentPostActivity.spiceManagerPlaces.addListenerIfPending(Post.class, "POSTS", pendingRequestListener); } 将侦听robospice中的所有pendingRequest并适当地处理它们。

PendingRequestListener

第2步:创建PendingRequestListener pendingRequestListener = new PendingRequestListener() { @Override public void onRequestNotFound() { //This is when no request is found at all - this method will be triggered. Notice that I have //placed this method within the onStart method which means that when your app onStarts - when you //click on the app icon on your phone, this method will actually be triggered so therefore it will first //get the data from cache by using the cacheKey "POSTS", then it will trigger a separate spiceRequest for network //operations to fetch the data from the server. Notice that the second spiceRequest does not have a cacheKey. //The reason is that we are not going to return back the results of the network operations - we will return //the results of our cache that we will manually create at a later stage PostSpiceRequest postSpiceRequest = new PostSpiceRequest(getActivity(), postid); FragmentPostActivity.spiceManagerPlaces.getFromCache(EmbedPost.class, "POSTS", DurationInMillis.ONE_WEEK, new PostListener()); FragmentPostActivity.spiceManagerPlaces.execute(PostSpiceRequest,new PostListener()); } @Override public void onRequestFailure(SpiceException spiceException) { //This is if your request failed when you navigate back to Activity A from Activity B Log.e("PendingRequestRS", "request failed for pending requests"); } @Override public void onRequestSuccess(Object o) { //This is if your request succeed when you navigate back to Activity A from Activity B Log.e("PendingRequestRS", "pending request successful"); FragmentPostActivity.spiceManagerPlaces.getFromCache(Post.class, "POSTS", DurationInMillis.ONE_WEEK, new PostListener()); } };

@Override
public void onPause() {
    super.onPause();
    //If you are using a spiceManager from your activity class, you will needs to put this code into onPause and not in onStop. 
    //Inside your activity, you would have stopped the spicemanager in onStop, which means that your cache would not be stored
    //at all.
    //If you are using a spiceManager in your fragment class, you are free to put this code within your onStop method but make
    //sure that it is place in front of the spiceManager.onStop() so that the method will execute before it spicemanager is stopped

    LinkedList<Post> cachedPosts = new LinkedList<>();
    if (posts.size() > 20) {
        for (int i = 0; i <= 20; i++) {
            cachedPosts.add(posts.get(i));
        }
    } else {
        for (int i = 0; i < posts.size(); i++) {
            cachedPosts.add(posts.get(i));
        }
    }
    PostActivity.spiceManager.removeDataFromCache(Post.class, "POSTS");
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                FragmentPostActivity.spiceManagerPlaces.putDataInCache("POSTS", cachedPosts);
            } catch (CacheSavingException e) {
                e.printStackTrace();
            } catch (CacheCreationException e) {
                e.printStackTrace();
            }
        }
    }).start();
}

第3步:添加手动方法来缓存数据,以便在应用再次启动时检索数据。下面的方法最多可以计算20个帖子,然后将它们放入缓存中。如果它少于20个帖子,它将缓存到该数量。

{{1}}

希望我对使用Robospice的这个主题有所了解,因为关于如何做到这一点的文档很少。