标签: retrofit2

用于Retrofit 2的定制转换器

我必须处理动态JSON响应.

之前,我正在使用类和注释如下:

public class ChatResponse {

    @SerializedName("status")
    private int status;

    @SerializedName("error")
    private String error;

    @SerializedName("response")
    private Talk response;

    public int getStatus() {
        return status;
    }

    public String getError() {
        return error;
    }

    public Talk getResponse() {
        return response;
    }
}
Run Code Online (Sandbox Code Playgroud)

当状态为1(成功)时,onResponse会触发,我可以获得ChatResponse对象.但是,当状态为0时,JSON表示中的响应为false,并且失败(onFailure被触发).

我想创建我的自定义转换器,这个问题有一个很好的例子,但该示例适用于Retrofit 1.

我必须创建一个扩展的类Converter.Factory,但我不知道如何覆盖此类的方法.

其实我有下一个:

@Override
public Converter<ResponseBody, ?> fromResponseBody(Type type, Annotation[] annotations) {

    return super.fromResponseBody(type, annotations);
}

@Override
public Converter<?, RequestBody> toRequestBody(Type type, Annotation[] annotations) {

    return super.toRequestBody(type, annotations);
} …
Run Code Online (Sandbox Code Playgroud)

android json converter retrofit2

21
推荐指数
2
解决办法
3万
查看次数

改造日志记录拦截器异常

我正在尝试使用Retrofit启用Logging但是我收到此异常:

07-13 12:44:53.278 28698-29248/com.xxxx.debug E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
                                                                                         Process: com.xxxx.debug, PID: 28698
                                                                                         java.lang.NoSuchMethodError: No virtual method log(Ljava/lang/String;)V in class Lokhttp3/internal/Platform; or its super classes (declaration of 'okhttp3.internal.Platform' appears in /data/data/com.xxxx.debug/files/instant-run/dex/slice-realm-optional-api_16b022358933b490d810e358ea76b13cd4d88163-classes.dex)
                                                                                             at okhttp3.logging.HttpLoggingInterceptor$Logger$1.log(HttpLoggingInterceptor.java:109)
                                                                                             at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:157)
                                                                                             at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:190)
                                                                                             at com.xxxx.api.RetrofitClient$1.intercept(RetrofitClient.java:59)
                                                                                             at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:190)
                                                                                             at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:163)
                                                                                             at okhttp3.RealCall.access$100(RealCall.java:30)
                                                                                             at okhttp3.RealCall$AsyncCall.execute(RealCall.java:127)
                                                                                             at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
                                                                                             at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
                                                                                             at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
                                                                                             at java.lang.Thread.run(Thread.java:818)
Run Code Online (Sandbox Code Playgroud)

这就是我这样做的方式:

public class RetrofitClient {

    private static MyService instance;

    public static MyService getInstance(Context context) {
        if (instance == null) {
            instance = newInstance(context);
        }
        return …
Run Code Online (Sandbox Code Playgroud)

android retrofit2

21
推荐指数
2
解决办法
4961
查看次数

Android:动态传递模型类以改进回调

通过改造将json响应映射到pojo通常我们这样做

@POST
Call<User> getDataFromServer(@Url String url, @Body HashMap<String,Object> hashMap);

ApiCalls api = retrofit.create(ApiCalls.class);
    Call<User> call = api.getDataFromServer(StringConstants.URL,hashMap);
    call.enqueue(new Callback<User>() {
         //Response and failure callbacks
    }
Run Code Online (Sandbox Code Playgroud)

用户是我的Pojo课程.但是对于每个其他请求,我需要制作不同的pojo并为改进调用编写相同的代码.我想制作一个单独的方法来调用api并传递相应的pojo类来改进调用.像这样

ApiCalls api = retrofit.create(ApiCalls.class);
Call<*ClassPassed*> call = api.getDataFromServer(StringConstants.URL,hashMap);
call.enqueue(new Callback<*ClassPassed*>() {
     //Response and failure callbacks
}
Run Code Online (Sandbox Code Playgroud)

所以现在我可以将任何pojo类转换为单个方法并获得响应.这只是为了避免一次又一次地重写相同的代码.这是可能的

更新 要详细说明:

假设我需要提出两个请求.第一个是获取userDetails,另一个是patientDetails.所以我必须创建两个模型类User和Patient.所以在改造api我会有类似的东西

@POST
Call<User> getDataFromServer(@Url String url, @Body HashMap<String,Object> hashMap);

@POST
Call<Patient> getDataFromServer(@Url String url, @Body HashMap<String,Object> hashMap);
Run Code Online (Sandbox Code Playgroud)

在我的FragmentUser和FragmentPatient类中,我将这样做

  ApiCalls api = retrofit.create(ApiCalls.class);
Call<User> call = api.getDataFromServer(StringConstants.URL,hashMap);
call.enqueue(new Callback<User>() {
     //Response and failure callbacks
}

ApiCalls …
Run Code Online (Sandbox Code Playgroud)

android pojo retrofit retrofit2

21
推荐指数
3
解决办法
2万
查看次数

使用匕首柄作为依赖注入来处理多个改造客户端?

我想在我的 android 应用程序中使用两个不同的后端,具有不同的响应格式,我使用 hilt 作为依赖注入,并对网络调用进行改造,这非常适合工作。

因为我已经添加了第二个服务器网络文件和应用程序模块,所以它给了我错误,该错误列在最后。

我需要知道在这种情况下的出路,而不需要进行任何显着的架构更改。

@Keep
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Singleton
@Provides
fun provideRetrofit(gson: Gson,@ApplicationContext appContext: Context): Retrofit = Retrofit.Builder()
    .client(
        OkHttpClient().newBuilder()
            .addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)).readTimeout(80,TimeUnit.SECONDS)
            .addInterceptor(
                ChuckerInterceptor.Builder(appContext)
                    .collector(ChuckerCollector(appContext))
                    .maxContentLength(250000L)
                    .redactHeaders(emptySet())
                    .alwaysReadResponseBody(false)
                    .build()
            )
            .build()
    )
    .baseUrl(UtilSingleton.instance!!.GetBaseUrl())
    .addConverterFactory(GsonConverterFactory.create(gson))
    .build()

@Provides
fun provideGson(): Gson = GsonBuilder().create()

@Provides
fun providePostsService(retrofit: Retrofit): ApiService =
    retrofit.create(ApiService::class.java)

@Singleton
@Provides
fun provideApiRemoteDataSource(apiService: ApiService) = ApiRemoteDataSource(apiService)

@Singleton
@Provides
fun provideRepository(
    remoteDataSource: ApiRemoteDataSource
) =
    MainRepo(remoteDataSource)


/**----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------**/

@Singleton
@Provides
fun provideRetrofitEmall(gson: Gson,@ApplicationContext appContext: Context): Retrofit = Retrofit.Builder()
        .client( …
Run Code Online (Sandbox Code Playgroud)

android retrofit2 dagger-hilt

21
推荐指数
2
解决办法
1万
查看次数

启用ProGuard时,Retrofit 2不发送数据

我尝试使用Retrofit 2登录我的用户.(基本上是使用基本标题对登录URL进行GET)它运行良好但是一旦我ProGuard它,标题授权就不再发送了.(见日志输出)

示例代码:

用户模型:

public interface UserService {

    @GET(GET_LOGIN)
    Observable<User> login(@Header("Authorization") String basic);
}
Run Code Online (Sandbox Code Playgroud)

登录活动:

public void onClick(View v) {
    mRetrofit.create(UserService.class)
             .login(Credentials.basic(email, password))
             .subscribeOn(Schedulers.io())
             .observeOn(AndroidSchedulers.mainThread())
             .subscribe(user -> {
                UserHelper.save(LoginActivity.this, user);
             }, throwable -> Dog.d);
}
Run Code Online (Sandbox Code Playgroud)

Proguard文件:

# Retrofit
-dontwarn retrofit2.** 
-dontwarn org.codehaus.mojo.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-keepattributes *Annotation*
-keepclasseswithmembers class * {
    @retrofit.* <methods>;
}

-keepclasseswithmembers interface * {
    @retrofit.* <methods>;
}
Run Code Online (Sandbox Code Playgroud)

日志(proguard):

D/OkHttp: --> GET http://passport-supercairos.rhcloud.com/users/login HTTP/1.1
D/OkHttp: User-Agent: VirtualPassport-Client {Android-23} {Aquaris_E5}
D/OkHttp: …
Run Code Online (Sandbox Code Playgroud)

android proguard retrofit retrofit2

20
推荐指数
5
解决办法
1万
查看次数

Retrofit和RxJava:如何组合两个请求并获得对两个结果的访问权限?

我需要提出两个服务请求并将其结合起来:

ServiceA()=> [{"id":1,"name":"title"},{"id":1,"name":"title"}]

ServiceB(id)=> {"field":"value","field1":"value"}

目前,我已设法将结果组合在一起,但我需要将id参数作为参数传递给ServiceB并获取对第一个结果的访问权限.

到目前为止我尝试了什么:

   Retrofit repo = new Retrofit.Builder()
                .baseUrl("https://api.themoviedb.org/3/genre/")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();

        Observable<GenerosResponse> Genres  = repo
                .create(services.class)
                .getAllGeneros("movie","list","da0d692f7f62a1dc687580f79dc1e6a0")
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread());

        Observable<ResponseMovies> Movies = repo
                .create(services.class)
                .getAllMovies("28","movies","da0d692f7f62a1dc687580f79dc1e6a0",12)
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread());

        Observable<CollectionsMovies> combined = Observable.zip(Genres, Movies, new Func2<GenerosResponse, ResponseMovies, CollectionsMovies>() {
            @Override
            public CollectionsMovies call(GenerosResponse generosResponse, ResponseMovies responseMovies) {
                return new CollectionsMovies(generosResponse, responseMovies);
            }
        });

        combined.
                subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(...);
Run Code Online (Sandbox Code Playgroud)

编辑

解决方案根据@Maxim Ostrovidov的回答:

 private Observable<GenerosResponse> makeRequestToServiceA() {
        return  service.getAllGeneros("movie","list","da0d692f7f62a1dc687580f79dc1e6a0"); //some network call
    } …
Run Code Online (Sandbox Code Playgroud)

java android rx-java retrofit2

20
推荐指数
1
解决办法
1万
查看次数

改造 - android.os.NetworkOnMainThreadException

我正在使用Retrofit 2来获取json并将其解析为POJO.我的目的是获得该对象的一个​​值.

compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
Run Code Online (Sandbox Code Playgroud)

我的REST客户端:

public interface MyClient {

    @GET("/part1/part2")
    Call<MyItem> getMyItem(@Query("param1") String param1,
                                                 @Query("param2") String param2,
                                                 @Query("param3") String param3);

}
Run Code Online (Sandbox Code Playgroud)

在这里,我找到了创建服务的绝佳工具:

public class ServiceGenerator {

    public static final String API_BASE_URL = "http://my.api.com";

    private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

    private static Retrofit.Builder builder =
            new Retrofit.Builder()
                    .baseUrl(API_BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create());

    public static <S> S createService(Class<S> serviceClass) {
        Retrofit retrofit = builder.client(httpClient.build()).build();
        return retrofit.create(serviceClass);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我使用服务生成器类创建新服务:

MyClient api = ServiceGenerator.createService(MyClient.class);
        Call<MyItem> call = api.getMyItem(param1, param2, param3);
        MyItem myItem= …
Run Code Online (Sandbox Code Playgroud)

java android retrofit retrofit2

19
推荐指数
1
解决办法
2万
查看次数

在Retrofit + RxJava中链接请求

我有2个API,我想按顺序请求并将它们的数据存储在SQLite中.

首先,我想向API发出请求A并将其数据存储在SQL表中a.然后请求API B并将其数据存储在表中,b并将一些数据存储在表中a_b.存储的数据a_b仅来自请求B.

我怎么能用RxJava做到这一点.我在这里读到了关于使用flatMap的地方,就像这样

apiService.A()
    // store in DB here? How? maybe use map()?
    .flatMap(modelA -> {
        // or maybe store modelA in DB here?
        return apiService.B().map(modelB -> {
            storeInDB()l // store B here ?
            return modelB;
        });
    });
Run Code Online (Sandbox Code Playgroud)

如果我没有使用lambda函数,这看起来就像普通的嵌套调用一样难看.这是一个更好的方法吗?

android rx-java retrofit2

19
推荐指数
2
解决办法
1万
查看次数

仅使用表单数据进行改造2

我正在尝试使用Retrofit 2发出POST请求.请求类型form-data 不是 application/x-www-form-urlencoded.

我只发布数据而不是请求中的文件,响应采用JSON格式.

我试过了@FormUrlEncoded, @Multipart但是没有用.

我试过以下请求

1.第一次尝试

@FormUrlEncoded
@POST("XXXX")
Call<PlanResponse> getPlanName(@Field(Constants.ACTION_ID) String actionId, @Field(Constants.OFFER_CODE) String offerCode);
Run Code Online (Sandbox Code Playgroud)

2.第二次尝试

@Headers({"Content-Type: multipart/form-data","Content-Type: text/plain"})
@FormUrlEncoded
@POST("XXXX")
Call<PlanResponse> getPlans(@Body @FieldMap(encoded = false) Map<String, String> data);
Run Code Online (Sandbox Code Playgroud)

3.第三次尝试

@Headers("Content-Type: multipart/form-data")
@Multipart
@POST("XXXX")
Call<PlanResponse> myPlans(@Part(Constants.ACTION_ID) String actionId, @Part(Constants.OFFER_CODE) String offerCode);
Run Code Online (Sandbox Code Playgroud)

我只是将身体变为空.它正在与POSTMAN合作.

我也搜索一下form-data,并application/x-www-form-urlencoded发现,如果数据是二进制的,然后使用form-data,如果数据是ASCII然后使用application/x-www-form-urlencoded

我正在尝试查找改造不支持表单数据吗?

POSTMAN请求

Cache-Control: no-cache
Postman-Token: XXXXXXXXXXXX-XXXXXXXXXXXX-XXXXXXXXXXXX-XXXXXXXXXXXX-XXXXXXXXXXXX
Content-Type: multipart/form-data; boundary=----    WebKitFormBoundaryXXXXXXXXXXXX


 ----WebKitFormBoundaryXXXXXXXXXXXX
Content-Disposition: form-data; name="actionId"

1000
 ----WebKitFormBoundaryXXXXXXXXXXXX
Content-Disposition: form-data; name="offerCode"

MYCODE …
Run Code Online (Sandbox Code Playgroud)

android form-data retrofit2

19
推荐指数
4
解决办法
3万
查看次数

ProtocolException:预期的':status'标头不存在

在工作应用程序中突然发生网络调用失败并出现协议异常.该应用程序一直工作到昨天,今天所有的网络呼叫都失败了.这些调用适用于HTTP,但使用HTTPS失败.

这是日志,

java.net.ProtocolException: Expected ':status' header not present
10-18 14:59:01.103 30746-30746/? W/System.err:     at okhttp3.internal.http.Http2xStream.readHttp2HeadersList(Http2xStream.java:262)
10-18 14:59:01.103 30746-30746/? W/System.err:     at okhttp3.internal.http.Http2xStream.readResponseHeaders(Http2xStream.java:145)
10-18 14:59:01.103 30746-30746/? W/System.err:     at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:53)
10-18 14:59:01.103 30746-30746/? W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
10-18 14:59:01.103 30746-30746/? W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
10-18 14:59:01.103 30746-30746/? W/System.err:     at codmob.com.campuswallet.app.ApiClient$1.intercept(ApiClient.java:66)
10-18 14:59:01.103 30746-30746/? W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
10-18 14:59:01.103 30746-30746/? W/System.err:     at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)
10-18 14:59:01.103 30746-30746/? W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
10-18 14:59:01.103 30746-30746/? W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
10-18 14:59:01.103 30746-30746/? W/System.err:     at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:109)
10-18 14:59:01.103 30746-30746/? W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92) …
Run Code Online (Sandbox Code Playgroud)

android protocolexception retrofit retrofit2 okhttp3

19
推荐指数
3
解决办法
1万
查看次数