1

After following Support Caching in Apollo Android here: Support For Cached Responses for Android

And already tried to query offline and it works fine and data is coming from the cache

  • First scenario after opening the app is loading the list of Data using Query from "MyApolloClient" object which is a custom class inherit from "ApolloClient"

  • After getting the data using ".watcher().enqueueAndWatch()" method to callback response from Apollo with new data and update the recyclerView

  • I select item to update or "Mutate" a record from the query data list to change it in cache and database of course.

I can click on any item and then it show a dialog to edit name of that record item

After sending the updated name using Mutation normally, the cache changed and the database online changed too.

The problem here: the UI doesn't changed at all because .watcher() method which returns instance of ApolloQueryWatcher who has a method called enqueueAndWatch doesn't trigger as a listener to any changes to update UI and the list with the new changed value of that record

Here are some snippets from my Code, I am using Kotlin and Java.

  • The Method to get data of users from database using Query

    fun getAllUsers() {
    progress.visibility = VISIBLE
    MyApolloClient.getApolloClient(this).query(GetUsersWithPagesQuery.builder().build())
        .watcher().enqueueAndWatch(object : MyApolloClient.MyCallBack<GetUsersWithPagesQuery.Data>(this) {
            override fun onResponseUI(response: Response<GetUsersWithPagesQuery.Data>) {
                progress.visibility = GONE
                if (response.data() != null) {
                    reachBottom = false
                    users.clear()
                    for (i in response.data()!!.users()) {
                        val u = GetUsersWithPagesQuery.Data1("", i.id(), i.name(), i.email())
                        users.add(u)
                    }
                    adapter.notifyDataSetChanged()
    
                }
            }
    
            override fun onFailureUI(response: ApolloException) {
    
            }
        })
    

    }

  • Custom Callback to use response in UI

    public static abstract class MyCallBack<T> extends ApolloCall.Callback<T> {
    
    Activity activity;
    
    public MyCallBack(Activity activity) {
        this.activity = activity;
    }
    
    @Override
    public void onResponse(@NotNull com.apollographql.apollo.api.Response<T> response) {
        activity.runOnUiThread(() -> onResponseUI(response));
    
    }
    
    public abstract void onResponseUI(@NotNull com.apollographql.apollo.api.Response<T> response);
    
    public abstract void onFailureUI(@NotNull ApolloException response);
    
    @Override
    public void onFailure(@NotNull ApolloException e) {
        activity.runOnUiThread(() -> onFailureUI(e));
    }
    

    }

  • getting object of Apollo Client with Caching support

    public static ApolloClient getApolloClient(Context context) {
    
    HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
    httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
    OkHttpClient.Builder builder = new OkHttpClient.Builder();
    builder.addNetworkInterceptor(httpLoggingInterceptor);
    builder.addNetworkInterceptor(chain -> {
        Request original = chain.request();
        Request.Builder builder1 = original.newBuilder().method(original.method(), original.body());
        builder1.header("Authorization", "Bearer " + PrefManager.getInstance(context).getAPIToken());
        return chain.proceed(builder1.build());
    });
    OkHttpClient okHttpClient = builder.build();
    //Directory where cached responses will be stored
    File file = new File(context.getApplicationContext().getFilesDir(), "apolloCache");
    
    //Size in bytes of the cache
    long size = 1024 * 1024;
    
    //Create the http response cache store
    DiskLruHttpCacheStore cacheStore = new DiskLruHttpCacheStore(file, size);
    
    ApolloSqlHelper apolloSqlHelper = ApolloSqlHelper.create(context, "zari");
    
    //Create NormalizedCacheFactory
    NormalizedCacheFactory cacheFactory = new SqlNormalizedCacheFactory(apolloSqlHelper);
    
    //Create the cache key resolver, this example works well when all types have globally unique ids.
    CacheKeyResolver resolver = new CacheKeyResolver() {
        @NotNull
        @Override
        public CacheKey fromFieldRecordSet(@NotNull ResponseField field, @NotNull Map<String, Object> recordSet) {
            return formatCacheKey((String) recordSet.get("id"));
        }
    
        @NotNull
        @Override
        public CacheKey fromFieldArguments(@NotNull ResponseField field, @NotNull Operation.Variables variables) {
            return formatCacheKey((String) field.resolveArgument("id", variables));
        }
    
        private CacheKey formatCacheKey(String id) {
            if (id == null || id.isEmpty()) {
                return CacheKey.NO_KEY;
            } else {
                return CacheKey.from(id);
            }
        }
    };
    
    apolloClient = ApolloClient.builder()
            .serverUrl(url)
            //.httpCache(new ApolloHttpCache(cacheStore))
            .normalizedCache(cacheFactory, resolver)
            .okHttpClient(okHttpClient)
            .build();
    return apolloClient;
    

    }

  • alert dialog with edit text to update item from list in Recycler Adapter

    builder.setPositiveButton("Change", (dialog, which) -> {
        if (!n.isEmpty())
            MyApolloClient.getApolloClient(activity).mutate(UpdateUserMutation.builder().id(user
                    .id()).name(n).build()).enqueue(new MyApolloClient.MyCallBack<UpdateUserMutation.Data>(activity) {
                @Override
                public void onResponseUI(@NotNull Response<UpdateUserMutation.Data> response) {
                    if (response.errors() != null && response.errors().size() > 0) {
                        StaticMembers.toastMessageShort(activity, response.errors().get(0).message());
                    } else {
                        StaticMembers.toastMessageShort(activity, response.data().updateUser().name() + " updated");
                    }
                }
    
                @Override
                public void onFailureUI(@NotNull ApolloException response) {
    
                }
            });
    
    });
    

So, Can anyone please help?

mbonnin
  • 6,893
  • 3
  • 39
  • 55

1 Answers1

0

Apollo-android has no way to know what node your mutation is going to modify. If your API allows it, you could query the new user as return data from the mutation to force an update of the cache.

Alternatively, you could modify the cache by hand if the request succeeds but that seems more involved.

mbonnin
  • 6,893
  • 3
  • 39
  • 55