为啥 ApolloQueryWatcher 在突变更改数据后不触发?

Posted

技术标签:

【中文标题】为啥 ApolloQueryWatcher 在突变更改数据后不触发?【英文标题】:Why doesnot ApolloQueryWatcher trigger after a mutation change data?为什么 ApolloQueryWatcher 在突变更改数据后不触发? 【发布时间】:2019-11-17 04:13:12 【问题描述】:

在 Apollo android 中关注支持缓存之后 这里:Support For Cached Responses for Android

并且已经尝试离线查询并且工作正常并且数据来自缓存

打开应用程序后的第一个场景是使用“MyApolloClient”对象的查询加载数据列表,该对象是从“ApolloClient”继承的自定义类

使用“.watcher().enqueueAndWatch()”方法获取数据后,用新数据回调来自Apollo的响应并更新recyclerView

我从查询数据列表中选择要更新或“变异”记录的项目,当然可以在缓存和数据库中更改它。

我可以点击任何项目,然后它会显示一个对话框来编辑该项目的名称 记录项

正常使用Mutation发送更新后的名称后,缓存发生了变化,在线数据库也发生了变化。

这里的问题: UI 根本没有改变,因为 .watcher() 方法返回 ApolloQueryWatcher 的实例,该实例有一个名为 enqueueAndWatch 的方法 不会触发 作为任何更改的侦听器以更新 UI 和具有该记录的新更改值的列表

这是我的代码中的一些 sn-ps, 我正在使用 Kotlin 和 Java。

使用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) 

        
    )

自定义回调以在 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));

获取支持缓存的 Apollo Client 对象

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;

带有编辑文本的警报对话框以从 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) 

            
        );

);

那么,有人可以帮忙吗?

【问题讨论】:

【参考方案1】:

Apollo-android 无法知道您的变异将修改哪个节点。如果您的 API 允许,您可以查询新用户作为突变的返回数据以强制更新缓存。

或者,如果请求成功,您可以手动修改缓存,但这似乎更复杂。

【讨论】:

以上是关于为啥 ApolloQueryWatcher 在突变更改数据后不触发?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 vue 3 watch 上不调用对象突变?

我的突变适用于 Amplify,但不适用于 Apollo。为啥?

Kodein + Ktor = 冻结 kotlin.collections.HashMap 的突变尝试 - 为啥?

为啥当状态发生突变时 mapStateToProps 返回空对象?

为啥 Youtube 评论不会触发 DOM 突变?

为啥每个 GraphQL 查询/突变都有“两个名称”?