我如何在 android 中使用 GraphQl?
How can I use from GraphQl in android?
我需要一个在 android 中使用 GraphQl
的简单示例。
如何在 android(教程)中使用来自 GraphQl
的内容。
为了使用 GraphQL(通常),您需要两件事:
1。 GraphQL 服务器
有几种方法可以解决这个问题。当然,您可以简单地使用您喜欢的任何服务器端语言 implement one yourself。
其他(更快的)方法是利用现有工具并使用 graphql-up or create-graphql-server or even services like Graphcool 等服务生成 GraphQL API(免责声明:我为他们工作)。
2。 GraphQL 客户端库
虽然这不是绝对必要的,你也可以通过纯 HTTP 简单地与 GraphQL 服务器交互(在 POST 请求的正文中发送你的查询和变更),使用它肯定是有益的现有工具可以让您摆脱缓存或 UI 集成等重复性工作。目前最流行的 GraphQL 客户端之一也是 Apollo, and they're very actively working on a version for Android。但是,这尚未 正式 发布。因此,您要么必须使用他们现有的开发版本,要么暂时选择使用纯 HTTP 的前一种方法。
这里是一个从客户端查询GraphQl的例子。在此示例中,我使用的是 Retrofit 2:
// QueryHelper.java
// This line below is the simple format of Gql query
query = "query{me{name, location, majorOfInterest,profilePhoto{url(size: 400) }}}";
//Post the query using Retrofit2
GqlRetrofitClient.getInstance(getContext()).fetchUserDetails(new GqlQueryRequest(queryUserDetails)).enqueue(new Callback<UserDetails>() {
@Override
public void onResponse(Call<UserDetails> call, Response<UserDetails> response) {
//OnResponse do something();
}
@Override
public void onFailure(Call<UserDetails> call, Throwable t) {
Log.d(TAG, "Failed to fetch User details");
}
});
//GqlClient.java
public class GqlRetrofitClient {
public static final String BASE_URL = BuildConfig.DOMAIN;
private static GqlRetrofitClient sInstance;
private GqlRetrofitService mGqlRetrofitService;
Gson gson = new GsonBuilder().create();
private GqlRetrofitClient(final Context context) {
// Network Interceptor for logging
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addNetworkInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request().newBuilder()
.addHeader("X-User-Token", "AUTH_TOKEN")
.addHeader("X-User_Email", "Email")
.addHeader("content-type", "application/json")
.build();
return chain.proceed(request);
}
})
.addInterceptor(httpLoggingInterceptor)
.build();
// Retrofit initialization
final Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.client(okHttpClient)
.build();
mGqlRetrofitService = retrofit.create(GqlRetrofitService.class);
}
// Create an instance of GqlRetrofitClient to create retrofit service
public static GqlRetrofitClient getInstance(Context context){
if(sInstance == null){
sInstance = new GqlRetrofitClient(context.getApplicationContext());
}
return sInstance;
}
// Method call to get User details
public Call<UserDetails> fetchUserDetails(GqlQueryRequest queryUserDetails){
return mGqlRetrofitService.getUserDetails(queryUserDetails);
}
}
//GqlRetrofitService.java
public interface GqlRetrofitService{
@POST("/api/graph.json")
Call<UserDetails> getUserDetails(@Body GqlQueryRequest body);
}
我个人使用 Retrofit,我采用了这个 Link Credits
并改变了一些东西。
这是代码:
在文件“GraphQLConverter.java”中:
public class GraphQLConverter extends Converter.Factory {
private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
private GraphQueryProcessor graphProcessor;
private final Gson mGson;
private GraphQLConverter(Context context) {
graphProcessor = new GraphQueryProcessor(context);
mGson = new GsonBuilder()
.enableComplexMapKeySerialization()
.setLenient()
.create();
}
public static GraphQLConverter create(Context context) {
return new GraphQLConverter(context);
}
/** Override Converter.Factory Methods **/
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
if(type == QueryContainerBuilder.class){
return new GraphRequestConverter(methodAnnotations);
} else {
return null;
}
}
/** RequestConverter Class **/
private class GraphRequestConverter implements Converter<QueryContainerBuilder, RequestBody> {
private Annotation[] mAnnotations;
private GraphRequestConverter(Annotation[] annotations) {
mAnnotations = annotations;
}
@Override
public RequestBody convert(@NonNull QueryContainerBuilder containerBuilder) {
QueryContainerBuilder.QueryContainer queryContainer = containerBuilder
.setQuery(graphProcessor.getQuery(mAnnotations))
.build();
return RequestBody.create(MEDIA_TYPE, mGson.toJson(queryContainer).getBytes());
}
}
}
在文件“GraphQuery.java”中:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface GraphQuery {
String value() default "";
}
在文件“GraphQueryProcessor.java”中:
class GraphQueryProcessor {
private static final String TAG = GraphQueryProcessor.class.getSimpleName();
// GraphQl Constants
private static final String EXT_GRAPHQL = ".graphql";
private static final String ROOT_FOLDER_GRAPHQL = "graphql";
private final Map<String, String> mGraphQueries;
private Context mContext;
GraphQueryProcessor(Context context) {
mGraphQueries = new WeakHashMap<>();
mContext = context;
populateGraphQueries(ROOT_FOLDER_GRAPHQL);
}
/** Package-Private Methods **/
String getQuery(Annotation[] annotations) {
if(mGraphQueries == null || mGraphQueries.isEmpty()){
populateGraphQueries(ROOT_FOLDER_GRAPHQL);
}
GraphQuery graphQuery = null;
for (Annotation annotation : annotations) {
if (annotation instanceof GraphQuery) {
graphQuery = (GraphQuery) annotation;
break;
}
}
if (graphQuery != null) {
String fileName = String.format("%s%s", graphQuery.value(), EXT_GRAPHQL);
if (mGraphQueries != null && mGraphQueries.containsKey(fileName)) {
return mGraphQueries.get(fileName);
}
}
return null;
}
/** Private Methods **/
private void populateGraphQueries(@NonNull String path) {
try {
String[] paths = mContext.getAssets().list(path);
if (paths != null && paths.length > 0x0) {
for (String item : paths) {
String absolute = path + "/" + item;
if (!item.endsWith(EXT_GRAPHQL)) {
populateGraphQueries(absolute);
} else {
mGraphQueries.put(item, getFileContents(mContext.getAssets().open(absolute)));
}
}
}
} catch (IOException ioE) {
BaseEnvironment.onExceptionLevelLow(TAG, ioE);
}
}
private String getFileContents(InputStream inputStream) {
StringBuilder queryBuffer = new StringBuilder();
try {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
for (String line; (line = bufferedReader.readLine()) != null; )
queryBuffer.append(line);
inputStreamReader.close();
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
return queryBuffer.toString();
}
}
在文件“QueryContainerBuilder.java”中:
public class QueryContainerBuilder {
// Mask Types
private static final byte MASK_REPLACE_QUERY_ARGUMENTS = 0b1; // Invece di inviare il json con le variabili va a inserirle nella query i valori sostituendo i tipi degli argomenti.
private static final byte MASK_REPLACE_EXPLICIT_QUOTES = MASK_REPLACE_QUERY_ARGUMENTS << 0b1; // Alle stringhe non vengono automaticamente messe le virgolette ma devono essere aggiunte nei valori passati per le variabili.
private static final byte MASK_REPLACE_WITH_PLACEHOLDERS = MASK_REPLACE_EXPLICIT_QUOTES << 0b1; // Va a sostituire i placeholders "<key_var_name>" presenti nella query con i valori delle variabili.
private QueryContainer mQueryContainer;
private byte mMask;
public QueryContainerBuilder() {
mQueryContainer = new QueryContainer();
}
/** Setter Methods **/
public QueryContainerBuilder setQuery(String query) {
mQueryContainer.setQuery(query);
return this;
}
public QueryContainerBuilder setReplaceQueryArguments(){
mMask = MASK_REPLACE_QUERY_ARGUMENTS;
return this;
}
public QueryContainerBuilder setReplaceExplicitQuotes(){
mMask = MASK_REPLACE_QUERY_ARGUMENTS | MASK_REPLACE_EXPLICIT_QUOTES;
return this;
}
public QueryContainerBuilder setReplaceWithPlaceholders(){
mMask = MASK_REPLACE_QUERY_ARGUMENTS | MASK_REPLACE_WITH_PLACEHOLDERS;
return this;
}
/** Public Methods **/
public QueryContainerBuilder putVariable(String key, Object value) {
mQueryContainer.putVariable(key, value);
return this;
}
public boolean containsVariable(String key) {
return mQueryContainer.containsVariable(key);
}
/** Builder Methods **/
public QueryContainer build() {
if((mMask & MASK_REPLACE_QUERY_ARGUMENTS) != 0x0){
if((mMask & MASK_REPLACE_WITH_PLACEHOLDERS) != 0x0){
mQueryContainer.replaceVariablesPlaceholdersInQuery();
} else {
mQueryContainer.replaceVariablesInQuery(mQueryContainer.mVariables, 0x0);
}
mQueryContainer.mVariables = null;
}
return mQueryContainer;
}
/** Public Static Classes **/
public class QueryContainer {
@SerializedName("variables")
private LinkedHashMap<String, Object> mVariables;
@SerializedName("query")
private String mQuery;
QueryContainer() {
mVariables = new LinkedHashMap<>();
}
/** Private Methods **/
private void setQuery(String query) {
mQuery = query;
}
private void putVariable(String key, Object value) {
mVariables.put(key, value);
}
private boolean containsVariable(String key) {
return mVariables != null && mVariables.containsKey(key);
}
private void replaceVariablesInQuery(LinkedHashMap<String, Object> map, int index){
if(!TextUtils.isEmpty(mQuery) && map.size() > 0x0){
List<String> keys = new ArrayList<>(map.keySet());
for(String key : keys){
Object value = map.get(key);
if(value instanceof LinkedHashMap){
replaceVariablesInQuery((LinkedHashMap<String, Object>) value, index);
} else {
int i = mQuery.indexOf(key + ":", index) + key.length() + 0x1;
int z;
if(keys.indexOf(key) < keys.size() - 0x1){
z = mQuery.indexOf(",", i);
} else {
z = mQuery.indexOf(")", i);
int x = mQuery.substring(i, z).indexOf('}');
if(x != -0x1){
if(mQuery.substring(i, i + 0x4).contains("{")){
x++;
}
z -= ((z - i) - x);
}
}
String replace;
if((mMask & MASK_REPLACE_EXPLICIT_QUOTES) != 0x0){
replace = String.valueOf(value);
} else {
replace = value instanceof String ?
"\"" + value.toString() + "\"" : String.valueOf(value);
}
String sub = mQuery.substring(i, z)
.replaceAll("[\\]?\[", "\\\[").replaceAll("[\\]?\]", "\\\]")
.replaceAll("[\\]?\{", "\\\{").replaceAll("[\\]?\}", "\\\}");
mQuery = mQuery.replaceFirst(sub.contains("{}") ? sub.replace("{}", "").trim() : sub.trim(), replace);
index = z + 0x1;
}
}
}
}
private void replaceVariablesPlaceholdersInQuery(){
if(!TextUtils.isEmpty(mQuery) && mVariables.size() > 0x0){
for(String key : mVariables.keySet()){
mQuery = mQuery.replaceFirst("\<" + key + "\>", mVariables.get(key) != null ? mVariables.get(key).toString() : "null");
}
mVariables = null;
}
}
}
}
将您的查询放在“assets”文件夹中的“graphql”目录中,查询文件的扩展名为“.graphql”。您可以通过更改“GraphQueryProcessor” 中的“EXT_GRAPHQL”或“ROOT_FOLDER_GRAPHQL”常量来更改扩展名或文件夹。您可以使用这些格式进行查询:
query {
myQuery(param1: <myParam1>) {
....
}
}
如果您使用此格式,则需要在您的 QueryContainerBuilder 中使用 "MASK_REPLACE_WITH_PLACEHOLDERS"。您还需要将不带“<...>”的占位符名称作为 HashMap 键传递,因此在本例中为“myParam1”。
其他格式只是常见的 GraphQL 查询,例如:
query ($p1: String!) {
muQuery(p1: $id) {
...
}
}
使用此格式,您可以使用 正常的 QueryContainerBuilder 行为(未应用掩码,因此它将传递并生成“变量”json 对象。) 或 "MASK_REPLACE_QUERY_ARGUMENTS" 这将删除 "$id" 并放置值。
当你init Retrofit 添加“GraphQLConverter”。 注意“ConvertFactories”顺序!您可以放置更多 ConvertFactory,但它们会消耗输入,因此如果在这种情况下您将“Gson”放在“GraphQL”之前,“GsonConverted”将消耗输入数据:
new Retrofit.Builder()
.baseUrl(mBaseUrl)
.addConverterFactory(GraphQLConverter.create(context))
.addConverterFactory(GsonConverterFactory.create(gson))
.client(getBaseHttpClient(interceptor))
.build();
在你的改造中API:
@POST(AppConstants.SERVICE_GQL)
@GraphQuery(AppConstants.MY_GRAPHQL_QUERY_FILENAME)
fun callMyGraphQlQuery(@Body query: QueryContainerBuilder): Call<MyGraphQlResponse>
调用示例[=65=]:
val query = QueryContainerBuilder()
.putVariable("myParam1", myValue)
.setReplaceWithPlaceholders()
createService(API::class.java).callMyGraphQlQuery(query)
val query = QueryContainerBuilder()
.putVariable("p1", myValue)
.setReplaceQueryArguments()
createService(API::class.java).callMyGraphQlQuery(query)
val query = QueryContainerBuilder()
.putVariable("p1", myValue)
createService(API::class.java).callMyGraphQlQuery(query)
我知道如果“MASK_REPLACE_QUERY_ARGUMENTS”工作正常,我只用了 2/3 次,然后 back-end 被更改并写得更好。
我做了那些案例(掩码)来处理查询,因为我有这 3 个查询案例与我正在调用的 back-end。
您只需添加另一个掩码和“QueryContainerBuilder”中的代码即可添加其他查询处理行为。
如果有人使用此代码并对其进行更改使其变得更好,请将更改写给我,这样我也会更改我的库中的代码。
谢谢你,
有一个很好的编码和一天 :D
再见!
在您的清单中添加
<uses-permission android:name="android.permission.INTERNET"/>
您的依赖关系
// Kotlin Coroutines
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.4'
//OkHttp
implementation ("com.squareup.okhttp3:okhttp:3.12.12"){
force = true //API 19 support
}
implementation 'com.squareup.okhttp3:logging-interceptor:3.12.12'
//retrofit
implementation "com.squareup.retrofit2:retrofit:2.7.1"
implementation "com.squareup.retrofit2:converter-scalars:.7.1"
还有Java8兼容性
android {
...
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
有服务
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.Headers
import retrofit2.http.POST
interface GraphQLService {
@Headers("Content-Type: application/json")
@POST("/")
suspend fun postDynamicQuery(@Body body: String): Response<String>
}
你可以创建一个对象
import retrofit2.Retrofit
import retrofit2.converter.scalars.ScalarsConverterFactory
object GraphQLInstance {
private const val BASE_URL: String = "http://192.155.1.55:2000/"
val graphQLService: GraphQLService by lazy {
Retrofit
.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(ScalarsConverterFactory.create())
.build().create(GraphQLService::class.java)
}
}
在activity中你可以创建这个方法
private fun post(userId: String){
val retrofit = GraphQLInstance.graphQLService
val paramObject = JSONObject()
paramObject.put("query", "query {users(userid:$userId){username}}")
GlobalScope.launch {
try {
val response = retrofit.postDynamicQuery(paramObject.toString())
Log.e("response", response.body().toString())
}catch (e: java.lang.Exception){
e.printStackTrace()
}
}
}
你可以查看the example in GitHub and my post
注意:如果你需要突变应该是改变这一行
paramObject.put("query", "query {users(userid:$userId){username}}")
到
paramObject.put("query", "mutation {users(userid:$userId){username}}")
我需要一个在 android 中使用 GraphQl
的简单示例。
如何在 android(教程)中使用来自 GraphQl
的内容。
为了使用 GraphQL(通常),您需要两件事:
1。 GraphQL 服务器
有几种方法可以解决这个问题。当然,您可以简单地使用您喜欢的任何服务器端语言 implement one yourself。 其他(更快的)方法是利用现有工具并使用 graphql-up or create-graphql-server or even services like Graphcool 等服务生成 GraphQL API(免责声明:我为他们工作)。
2。 GraphQL 客户端库
虽然这不是绝对必要的,你也可以通过纯 HTTP 简单地与 GraphQL 服务器交互(在 POST 请求的正文中发送你的查询和变更),使用它肯定是有益的现有工具可以让您摆脱缓存或 UI 集成等重复性工作。目前最流行的 GraphQL 客户端之一也是 Apollo, and they're very actively working on a version for Android。但是,这尚未 正式 发布。因此,您要么必须使用他们现有的开发版本,要么暂时选择使用纯 HTTP 的前一种方法。
这里是一个从客户端查询GraphQl的例子。在此示例中,我使用的是 Retrofit 2:
// QueryHelper.java
// This line below is the simple format of Gql query
query = "query{me{name, location, majorOfInterest,profilePhoto{url(size: 400) }}}";
//Post the query using Retrofit2
GqlRetrofitClient.getInstance(getContext()).fetchUserDetails(new GqlQueryRequest(queryUserDetails)).enqueue(new Callback<UserDetails>() {
@Override
public void onResponse(Call<UserDetails> call, Response<UserDetails> response) {
//OnResponse do something();
}
@Override
public void onFailure(Call<UserDetails> call, Throwable t) {
Log.d(TAG, "Failed to fetch User details");
}
});
//GqlClient.java
public class GqlRetrofitClient {
public static final String BASE_URL = BuildConfig.DOMAIN;
private static GqlRetrofitClient sInstance;
private GqlRetrofitService mGqlRetrofitService;
Gson gson = new GsonBuilder().create();
private GqlRetrofitClient(final Context context) {
// Network Interceptor for logging
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addNetworkInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request().newBuilder()
.addHeader("X-User-Token", "AUTH_TOKEN")
.addHeader("X-User_Email", "Email")
.addHeader("content-type", "application/json")
.build();
return chain.proceed(request);
}
})
.addInterceptor(httpLoggingInterceptor)
.build();
// Retrofit initialization
final Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.client(okHttpClient)
.build();
mGqlRetrofitService = retrofit.create(GqlRetrofitService.class);
}
// Create an instance of GqlRetrofitClient to create retrofit service
public static GqlRetrofitClient getInstance(Context context){
if(sInstance == null){
sInstance = new GqlRetrofitClient(context.getApplicationContext());
}
return sInstance;
}
// Method call to get User details
public Call<UserDetails> fetchUserDetails(GqlQueryRequest queryUserDetails){
return mGqlRetrofitService.getUserDetails(queryUserDetails);
}
}
//GqlRetrofitService.java
public interface GqlRetrofitService{
@POST("/api/graph.json")
Call<UserDetails> getUserDetails(@Body GqlQueryRequest body);
}
我个人使用 Retrofit,我采用了这个 Link Credits 并改变了一些东西。
这是代码:
在文件“GraphQLConverter.java”中:
public class GraphQLConverter extends Converter.Factory {
private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
private GraphQueryProcessor graphProcessor;
private final Gson mGson;
private GraphQLConverter(Context context) {
graphProcessor = new GraphQueryProcessor(context);
mGson = new GsonBuilder()
.enableComplexMapKeySerialization()
.setLenient()
.create();
}
public static GraphQLConverter create(Context context) {
return new GraphQLConverter(context);
}
/** Override Converter.Factory Methods **/
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
if(type == QueryContainerBuilder.class){
return new GraphRequestConverter(methodAnnotations);
} else {
return null;
}
}
/** RequestConverter Class **/
private class GraphRequestConverter implements Converter<QueryContainerBuilder, RequestBody> {
private Annotation[] mAnnotations;
private GraphRequestConverter(Annotation[] annotations) {
mAnnotations = annotations;
}
@Override
public RequestBody convert(@NonNull QueryContainerBuilder containerBuilder) {
QueryContainerBuilder.QueryContainer queryContainer = containerBuilder
.setQuery(graphProcessor.getQuery(mAnnotations))
.build();
return RequestBody.create(MEDIA_TYPE, mGson.toJson(queryContainer).getBytes());
}
}
}
在文件“GraphQuery.java”中:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface GraphQuery {
String value() default "";
}
在文件“GraphQueryProcessor.java”中:
class GraphQueryProcessor {
private static final String TAG = GraphQueryProcessor.class.getSimpleName();
// GraphQl Constants
private static final String EXT_GRAPHQL = ".graphql";
private static final String ROOT_FOLDER_GRAPHQL = "graphql";
private final Map<String, String> mGraphQueries;
private Context mContext;
GraphQueryProcessor(Context context) {
mGraphQueries = new WeakHashMap<>();
mContext = context;
populateGraphQueries(ROOT_FOLDER_GRAPHQL);
}
/** Package-Private Methods **/
String getQuery(Annotation[] annotations) {
if(mGraphQueries == null || mGraphQueries.isEmpty()){
populateGraphQueries(ROOT_FOLDER_GRAPHQL);
}
GraphQuery graphQuery = null;
for (Annotation annotation : annotations) {
if (annotation instanceof GraphQuery) {
graphQuery = (GraphQuery) annotation;
break;
}
}
if (graphQuery != null) {
String fileName = String.format("%s%s", graphQuery.value(), EXT_GRAPHQL);
if (mGraphQueries != null && mGraphQueries.containsKey(fileName)) {
return mGraphQueries.get(fileName);
}
}
return null;
}
/** Private Methods **/
private void populateGraphQueries(@NonNull String path) {
try {
String[] paths = mContext.getAssets().list(path);
if (paths != null && paths.length > 0x0) {
for (String item : paths) {
String absolute = path + "/" + item;
if (!item.endsWith(EXT_GRAPHQL)) {
populateGraphQueries(absolute);
} else {
mGraphQueries.put(item, getFileContents(mContext.getAssets().open(absolute)));
}
}
}
} catch (IOException ioE) {
BaseEnvironment.onExceptionLevelLow(TAG, ioE);
}
}
private String getFileContents(InputStream inputStream) {
StringBuilder queryBuffer = new StringBuilder();
try {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
for (String line; (line = bufferedReader.readLine()) != null; )
queryBuffer.append(line);
inputStreamReader.close();
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
return queryBuffer.toString();
}
}
在文件“QueryContainerBuilder.java”中:
public class QueryContainerBuilder {
// Mask Types
private static final byte MASK_REPLACE_QUERY_ARGUMENTS = 0b1; // Invece di inviare il json con le variabili va a inserirle nella query i valori sostituendo i tipi degli argomenti.
private static final byte MASK_REPLACE_EXPLICIT_QUOTES = MASK_REPLACE_QUERY_ARGUMENTS << 0b1; // Alle stringhe non vengono automaticamente messe le virgolette ma devono essere aggiunte nei valori passati per le variabili.
private static final byte MASK_REPLACE_WITH_PLACEHOLDERS = MASK_REPLACE_EXPLICIT_QUOTES << 0b1; // Va a sostituire i placeholders "<key_var_name>" presenti nella query con i valori delle variabili.
private QueryContainer mQueryContainer;
private byte mMask;
public QueryContainerBuilder() {
mQueryContainer = new QueryContainer();
}
/** Setter Methods **/
public QueryContainerBuilder setQuery(String query) {
mQueryContainer.setQuery(query);
return this;
}
public QueryContainerBuilder setReplaceQueryArguments(){
mMask = MASK_REPLACE_QUERY_ARGUMENTS;
return this;
}
public QueryContainerBuilder setReplaceExplicitQuotes(){
mMask = MASK_REPLACE_QUERY_ARGUMENTS | MASK_REPLACE_EXPLICIT_QUOTES;
return this;
}
public QueryContainerBuilder setReplaceWithPlaceholders(){
mMask = MASK_REPLACE_QUERY_ARGUMENTS | MASK_REPLACE_WITH_PLACEHOLDERS;
return this;
}
/** Public Methods **/
public QueryContainerBuilder putVariable(String key, Object value) {
mQueryContainer.putVariable(key, value);
return this;
}
public boolean containsVariable(String key) {
return mQueryContainer.containsVariable(key);
}
/** Builder Methods **/
public QueryContainer build() {
if((mMask & MASK_REPLACE_QUERY_ARGUMENTS) != 0x0){
if((mMask & MASK_REPLACE_WITH_PLACEHOLDERS) != 0x0){
mQueryContainer.replaceVariablesPlaceholdersInQuery();
} else {
mQueryContainer.replaceVariablesInQuery(mQueryContainer.mVariables, 0x0);
}
mQueryContainer.mVariables = null;
}
return mQueryContainer;
}
/** Public Static Classes **/
public class QueryContainer {
@SerializedName("variables")
private LinkedHashMap<String, Object> mVariables;
@SerializedName("query")
private String mQuery;
QueryContainer() {
mVariables = new LinkedHashMap<>();
}
/** Private Methods **/
private void setQuery(String query) {
mQuery = query;
}
private void putVariable(String key, Object value) {
mVariables.put(key, value);
}
private boolean containsVariable(String key) {
return mVariables != null && mVariables.containsKey(key);
}
private void replaceVariablesInQuery(LinkedHashMap<String, Object> map, int index){
if(!TextUtils.isEmpty(mQuery) && map.size() > 0x0){
List<String> keys = new ArrayList<>(map.keySet());
for(String key : keys){
Object value = map.get(key);
if(value instanceof LinkedHashMap){
replaceVariablesInQuery((LinkedHashMap<String, Object>) value, index);
} else {
int i = mQuery.indexOf(key + ":", index) + key.length() + 0x1;
int z;
if(keys.indexOf(key) < keys.size() - 0x1){
z = mQuery.indexOf(",", i);
} else {
z = mQuery.indexOf(")", i);
int x = mQuery.substring(i, z).indexOf('}');
if(x != -0x1){
if(mQuery.substring(i, i + 0x4).contains("{")){
x++;
}
z -= ((z - i) - x);
}
}
String replace;
if((mMask & MASK_REPLACE_EXPLICIT_QUOTES) != 0x0){
replace = String.valueOf(value);
} else {
replace = value instanceof String ?
"\"" + value.toString() + "\"" : String.valueOf(value);
}
String sub = mQuery.substring(i, z)
.replaceAll("[\\]?\[", "\\\[").replaceAll("[\\]?\]", "\\\]")
.replaceAll("[\\]?\{", "\\\{").replaceAll("[\\]?\}", "\\\}");
mQuery = mQuery.replaceFirst(sub.contains("{}") ? sub.replace("{}", "").trim() : sub.trim(), replace);
index = z + 0x1;
}
}
}
}
private void replaceVariablesPlaceholdersInQuery(){
if(!TextUtils.isEmpty(mQuery) && mVariables.size() > 0x0){
for(String key : mVariables.keySet()){
mQuery = mQuery.replaceFirst("\<" + key + "\>", mVariables.get(key) != null ? mVariables.get(key).toString() : "null");
}
mVariables = null;
}
}
}
}
将您的查询放在“assets”文件夹中的“graphql”目录中,查询文件的扩展名为“.graphql”。您可以通过更改“GraphQueryProcessor” 中的“EXT_GRAPHQL”或“ROOT_FOLDER_GRAPHQL”常量来更改扩展名或文件夹。您可以使用这些格式进行查询:
query {
myQuery(param1: <myParam1>) {
....
}
}
如果您使用此格式,则需要在您的 QueryContainerBuilder 中使用 "MASK_REPLACE_WITH_PLACEHOLDERS"。您还需要将不带“<...>”的占位符名称作为 HashMap 键传递,因此在本例中为“myParam1”。
其他格式只是常见的 GraphQL 查询,例如:
query ($p1: String!) {
muQuery(p1: $id) {
...
}
}
使用此格式,您可以使用 正常的 QueryContainerBuilder 行为(未应用掩码,因此它将传递并生成“变量”json 对象。) 或 "MASK_REPLACE_QUERY_ARGUMENTS" 这将删除 "$id" 并放置值。
当你init Retrofit 添加“GraphQLConverter”。 注意“ConvertFactories”顺序!您可以放置更多 ConvertFactory,但它们会消耗输入,因此如果在这种情况下您将“Gson”放在“GraphQL”之前,“GsonConverted”将消耗输入数据:
new Retrofit.Builder()
.baseUrl(mBaseUrl)
.addConverterFactory(GraphQLConverter.create(context))
.addConverterFactory(GsonConverterFactory.create(gson))
.client(getBaseHttpClient(interceptor))
.build();
在你的改造中API:
@POST(AppConstants.SERVICE_GQL)
@GraphQuery(AppConstants.MY_GRAPHQL_QUERY_FILENAME)
fun callMyGraphQlQuery(@Body query: QueryContainerBuilder): Call<MyGraphQlResponse>
调用示例[=65=]:
val query = QueryContainerBuilder()
.putVariable("myParam1", myValue)
.setReplaceWithPlaceholders()
createService(API::class.java).callMyGraphQlQuery(query)
val query = QueryContainerBuilder()
.putVariable("p1", myValue)
.setReplaceQueryArguments()
createService(API::class.java).callMyGraphQlQuery(query)
val query = QueryContainerBuilder()
.putVariable("p1", myValue)
createService(API::class.java).callMyGraphQlQuery(query)
我知道如果“MASK_REPLACE_QUERY_ARGUMENTS”工作正常,我只用了 2/3 次,然后 back-end 被更改并写得更好。
我做了那些案例(掩码)来处理查询,因为我有这 3 个查询案例与我正在调用的 back-end。 您只需添加另一个掩码和“QueryContainerBuilder”中的代码即可添加其他查询处理行为。
如果有人使用此代码并对其进行更改使其变得更好,请将更改写给我,这样我也会更改我的库中的代码。
谢谢你, 有一个很好的编码和一天 :D
再见!
在您的清单中添加
<uses-permission android:name="android.permission.INTERNET"/>
您的依赖关系
// Kotlin Coroutines
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.4'
//OkHttp
implementation ("com.squareup.okhttp3:okhttp:3.12.12"){
force = true //API 19 support
}
implementation 'com.squareup.okhttp3:logging-interceptor:3.12.12'
//retrofit
implementation "com.squareup.retrofit2:retrofit:2.7.1"
implementation "com.squareup.retrofit2:converter-scalars:.7.1"
还有Java8兼容性
android {
...
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
有服务
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.Headers
import retrofit2.http.POST
interface GraphQLService {
@Headers("Content-Type: application/json")
@POST("/")
suspend fun postDynamicQuery(@Body body: String): Response<String>
}
你可以创建一个对象
import retrofit2.Retrofit
import retrofit2.converter.scalars.ScalarsConverterFactory
object GraphQLInstance {
private const val BASE_URL: String = "http://192.155.1.55:2000/"
val graphQLService: GraphQLService by lazy {
Retrofit
.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(ScalarsConverterFactory.create())
.build().create(GraphQLService::class.java)
}
}
在activity中你可以创建这个方法
private fun post(userId: String){
val retrofit = GraphQLInstance.graphQLService
val paramObject = JSONObject()
paramObject.put("query", "query {users(userid:$userId){username}}")
GlobalScope.launch {
try {
val response = retrofit.postDynamicQuery(paramObject.toString())
Log.e("response", response.body().toString())
}catch (e: java.lang.Exception){
e.printStackTrace()
}
}
}
你可以查看the example in GitHub and my post
注意:如果你需要突变应该是改变这一行
paramObject.put("query", "query {users(userid:$userId){username}}")
到
paramObject.put("query", "mutation {users(userid:$userId){username}}")