Android应用集成AWS Amplify后无法从DynamoDB获取数据
问题分析
你遇到的错误核心是:Amplify DataStore依赖_deleted、_lastChangedAt、_version三个系统字段实现数据同步和订阅功能,但你的DynamoDB表中没有这些字段,导致GraphQL订阅请求的字段校验失败。
解决方案
根据你的需求(保留现有表/重新创建表),提供三种可行方案:
方案1:通过Amplify重新创建带系统字段的表(推荐)
如果允许重构数据表,直接用Amplify的GraphQL schema定义模型,Amplify会自动生成包含所需系统字段的DynamoDB表和GraphQL API:
- 在本地项目的
amplify/backend/api/<api-name>/schema.graphql中定义Todo模型:
type Todo @model { id: ID! name: String! priority: Int! updatedAt: AWSDateTime! }
- 运行
amplify push命令,Amplify会自动创建带_deleted、_lastChangedAt、_version字段的DynamoDB表,并更新GraphQL API。 - 重新生成Android端的模型类:运行
amplify codegen models,替换项目中现有的Todo类。 - 重新运行查询代码即可正常工作。
方案2:给现有DynamoDB表添加缺失字段
如果必须保留现有表,需要手动补全系统字段并更新GraphQL配置:
- 登录AWS控制台,找到你的DynamoDB表,添加三个字段:
_deleted:布尔类型,默认值设为false_lastChangedAt:数字类型(存储Unix时间戳)_version:数字类型,默认值设为1
- 更新本地GraphQL schema,显式声明这些字段:
type Todo @model { id: ID! name: String! priority: Int! updatedAt: AWSDateTime! _deleted: Boolean _lastChangedAt: Int _version: Int }
- 运行
amplify push更新API,再运行amplify codegen models更新Android模型类。 - 给现有表中的所有数据补全这三个字段的值(比如
_deleted设为false,_version设为1,_lastChangedAt设为当前时间戳)。
方案3:跳过DataSync,直接操作DynamoDB
如果不需要离线同步和订阅功能,可直接使用Amplify的DynamoDB客户端或GraphQL查询,绕过DataStore的系统字段校验:
直接使用GraphQL查询示例
private void fetchTodo() { String todoId = "your-todo-id"; Amplify.API.query( ModelQuery.get(Todo.class, todoId), response -> { if (response.hasData()) { Todo todo = response.getData(); runOnUiThread(() -> { name.setText(todo.getName()); // 注意:ordinal()返回int,需转成字符串再设置 priority.setText(String.valueOf(todo.getPriority().ordinal())); update.setText(String.valueOf(todo.getUpdatedAt().getOffsetTotalSeconds())); }); } else { Log.i("Tutorial", "No Todo found with the specified ID."); } }, failure -> Log.e("Tutorial", "Could not query", failure) ); }
直接使用DynamoDB客户端示例
private void fetchTodoDirectly() { String todoId = "your-todo-id"; HashMap<String, AttributeValue> itemKey = new HashMap<>(); itemKey.put("id", AttributeValue.builder().s(todoId).build()); Amplify.DynamoDB.getItem( "YourTableName", itemKey, result -> { Map<String, AttributeValue> item = result.getItem(); if (item != null) { String name = item.get("name").getS(); int priority = Integer.parseInt(item.get("priority").getN()); String updatedAt = item.get("updatedAt").getS(); runOnUiThread(() -> { name.setText(name); priority.setText(String.valueOf(priority)); update.setText(updatedAt); }); } }, error -> Log.e("Tutorial", "Failed to get item", error) ); }
额外代码修正
你的原代码中priority.setText(todo.getPriority().ordinal());存在问题:setText()方法接收字符串参数,直接传入int会被当成资源ID导致崩溃,需修改为priority.setText(String.valueOf(todo.getPriority().ordinal()))。
内容的提问来源于stack exchange,提问作者Bikash Gupta
相关产品推荐
相关产品推荐

