使用 Retrofit 和 RxJava 的 Http 请求

Http request with Retrofit and RxJava

我正在请求带有 Retrofit 2 库的 Web 服务 API。我有 API 的 URL 的以下代码:

String ENDPOINT = "https://api.trakt.tv/";

@GET("movies/popular?limit=10&extended=full,images")
public Observable<PopularMoviesResponse> getPopularMovies(@Header("trakt-api-version") String trakt_api_version,
                                                  @Header("trakt-api-key") String trakt_api_key,
                                                  @Query("page") String page);

我正在使用上面的方法:

public Observable<List<PopularMovies>> fetchPopularMovies(String trakt_api_version,
                                                          String trakt_api_key,
                                                          String page) {
    return movieService
            .getPopularMovies(trakt_api_version, trakt_api_key, page)
            .concatMap(new Func1<PopularMoviesResponse, Observable<? extends List<PopularMovies>>>() {
                @Override
                public Observable<? extends List<PopularMovies>> call(final PopularMoviesResponse popularMoviesResponse) {
                    Log.d("uuuuuu", "oooooo");
                    return Observable.create(new Observable.OnSubscribe<List<PopularMovies>>() {
                        @Override
                        public void call(Subscriber<? super List<PopularMovies>> subscriber) {
                            Log.d("uuuuuu", "oooooo");
                            try {
                                if (subscriber.isUnsubscribed()) return;
                                subscriber.onNext(popularMoviesResponse.getPopularMovies());
                                subscriber.onCompleted();
                            } catch (Exception e) {
                                subscriber.onError(e);
                            }
                        }
                    });

                }
            });
}

日志数据显示http状态码为200,okhttp正常记录响应。然而,在第二段代码中,日志没有到达!有什么问题吗?

更新,

这是订阅可观察对象的代码:

public void getPopularMovies(final String page) {
    mDataManager.fetchPopularMovies(TraktAPI.TRAKT_API_VERSION.getValue(), TraktAPI.TRAKT_API_KEY.getValue(), page)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.io())
            .subscribe(new Observer<List<PopularMovies>>() {
                @Override
                public void onCompleted() {
                }

                @Override
                public void onError(Throwable e) {
                    mMvpView.showEmpty();
                }

                @Override
                public void onNext(List<PopularMovies> popularMoviesList) {
                    Log.d("onNext", "pppppppppppp");
                    mMvpView.showListOfPopularMovies(popularMoviesList);
                }
            });
}

我已经在订阅代码中记录了 onError,我得到了以下堆栈跟踪:

07-20 12:15:16.547 2056-2056/org.unrwa.edits W/System.err: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $
07-20 12:15:16.548 2056-2056/org.unrwa.edits W/System.err:     at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:221)
07-20 12:15:16.549 2056-2056/org.unrwa.edits W/System.err:     at com.google.gson.TypeAdapter.fromJson(TypeAdapter.java:260)
07-20 12:15:16.549 2056-2056/org.unrwa.edits W/System.err:     at retrofit2.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:33)
07-20 12:15:16.549 2056-2056/org.unrwa.edits W/System.err:     at retrofit2.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:23)
07-20 12:15:16.550 2056-2056/org.unrwa.edits W/System.err:     at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:154)
07-20 12:15:16.550 2056-2056/org.unrwa.edits W/System.err:     at retrofit2.OkHttpCall.execute(OkHttpCall.java:118)
07-20 12:15:16.550 2056-2056/org.unrwa.edits W/System.err:     at retrofit2.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:107)
07-20 12:15:16.551 2056-2056/org.unrwa.edits W/System.err:     at retrofit2.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:88)
07-20 12:15:16.551 2056-2056/org.unrwa.edits W/System.err:     at rx.Observable.call(Observable.java:162)
07-20 12:15:16.552 2056-2056/org.unrwa.edits W/System.err:     at rx.Observable.call(Observable.java:154)
07-20 12:15:16.552 2056-2056/org.unrwa.edits W/System.err:     at rx.Observable.call(Observable.java:162)
07-20 12:15:16.552 2056-2056/org.unrwa.edits W/System.err:     at rx.Observable.call(Observable.java:154)
07-20 12:15:16.553 2056-2056/org.unrwa.edits W/System.err:     at rx.Observable.call(Observable.java:162)
07-20 12:15:16.553 2056-2056/org.unrwa.edits W/System.err:     at rx.Observable.call(Observable.java:154)
07-20 12:15:16.553 2056-2056/org.unrwa.edits W/System.err:     at rx.Observable.call(Observable.java:162)
07-20 12:15:16.554 2056-2056/org.unrwa.edits W/System.err:     at rx.Observable.call(Observable.java:154)
07-20 12:15:16.555 2056-2056/org.unrwa.edits W/System.err:     at rx.Observable.call(Observable.java:162)
07-20 12:15:16.555 2056-2056/org.unrwa.edits W/System.err:     at rx.Observable.call(Observable.java:154)
07-20 12:15:16.556 2056-2056/org.unrwa.edits W/System.err:     at rx.Observable.unsafeSubscribe(Observable.java:8098)
07-20 12:15:16.556 2056-2056/org.unrwa.edits W/System.err:     at rx.internal.operators.OperatorSubscribeOn.call(OperatorSubscribeOn.java:62)
07-20 12:15:16.556 2056-2056/org.unrwa.edits W/System.err:     at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
07-20 12:15:16.557 2056-2056/org.unrwa.edits W/System.err:     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423)
07-20 12:15:16.557 2056-2056/org.unrwa.edits W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
07-20 12:15:16.558 2056-2056/org.unrwa.edits W/System.err:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269)
07-20 12:15:16.558 2056-2056/org.unrwa.edits W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
07-20 12:15:16.558 2056-2056/org.unrwa.edits W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
07-20 12:15:16.559 2056-2056/org.unrwa.edits W/System.err:     at java.lang.Thread.run(Thread.java:818)

URL 的网络服务 API,可以使用以下 link 找到: https://api.trakt.tv/movies/popular?(page=%271%27)&limit=10&extended=full,images

PopularMoviesResponse POJO class

public class PopularMoviesResponse {

private String OdataContext;
private List<PopularMovies> popularMovies = new ArrayList<PopularMovies>();


/**
 * 
 * @param OdataContext
 *     The @odata.context
 */
public void setOdataContext(String OdataContext) {
    this.OdataContext = OdataContext;
}

/**
 * 
 * @return
 *     The value
 */
public List<PopularMovies> getPopularMovies() {
    return popularMovies;
}

/**
 *
 * @param popularMovies
 */
public void setPopularMovies(List<PopularMovies> popularMovies) {
    this.popularMovies = popularMovies;
}

}

热门电影class

@生成("org.jsonschema2pojo") public class 热门电影 {

@SerializedName("title")
@Expose
private String title;
@SerializedName("year")
@Expose
private long year;
@SerializedName("ids")
@Expose
private Ids ids;
@SerializedName("tagline")
@Expose
private String tagline;
@SerializedName("overview")
@Expose
private String overview;
@SerializedName("released")
@Expose
private String released;
@SerializedName("runtime")
@Expose
private long runtime;
@SerializedName("trailer")
@Expose
private String trailer;
@SerializedName("homepage")
@Expose
private String homepage;
@SerializedName("rating")
@Expose
private double rating;
@SerializedName("votes")
@Expose
private long votes;
@SerializedName("updated_at")
@Expose
private String updatedAt;
@SerializedName("language")
@Expose
private String language;
@SerializedName("available_translations")
@Expose
private List<String> availableTranslations = new ArrayList<String>();
@SerializedName("genres")
@Expose
private List<String> genres = new ArrayList<String>();
@SerializedName("certification")
@Expose
private String certification;
@SerializedName("images")
@Expose
private Images images;

/**
 * No args constructor for use in serialization
 * 
 */
public PopularMovies() {
}

/**
 * 
 * @param trailer
 * @param genres
 * @param availableTranslations
 * @param ids
 * @param votes
 * @param runtime
 * @param homepage
 * @param released
 * @param updatedAt
 * @param certification
 * @param title
 * @param overview
 * @param images
 * @param year
 * @param language
 * @param rating
 * @param tagline
 */
public PopularMovies(String title, long year, Ids ids, String tagline, String overview, String released, long runtime, String trailer, String homepage, double rating, long votes, String updatedAt, String language, List<String> availableTranslations, List<String> genres, String certification, Images images) {
    this.title = title;
    this.year = year;
    this.ids = ids;
    this.tagline = tagline;
    this.overview = overview;
    this.released = released;
    this.runtime = runtime;
    this.trailer = trailer;
    this.homepage = homepage;
    this.rating = rating;
    this.votes = votes;
    this.updatedAt = updatedAt;
    this.language = language;
    this.availableTranslations = availableTranslations;
    this.genres = genres;
    this.certification = certification;
    this.images = images;
}

/**
 * 
 * @return
 *     The title
 */
public String getTitle() {
    return title;
}

/**
 * 
 * @param title
 *     The title
 */
public void setTitle(String title) {
    this.title = title;
}

public PopularMovies withTitle(String title) {
    this.title = title;
    return this;
}

/**
 * 
 * @return
 *     The year
 */
public long getYear() {
    return year;
}

/**
 * 
 * @param year
 *     The year
 */
public void setYear(long year) {
    this.year = year;
}

public PopularMovies withYear(long year) {
    this.year = year;
    return this;
}

/**
 * 
 * @return
 *     The ids
 */
public Ids getIds() {
    return ids;
}

/**
 * 
 * @param ids
 *     The ids
 */
public void setIds(Ids ids) {
    this.ids = ids;
}

public PopularMovies withIds(Ids ids) {
    this.ids = ids;
    return this;
}

/**
 * 
 * @return
 *     The tagline
 */
public String getTagline() {
    return tagline;
}

/**
 * 
 * @param tagline
 *     The tagline
 */
public void setTagline(String tagline) {
    this.tagline = tagline;
}

public PopularMovies withTagline(String tagline) {
    this.tagline = tagline;
    return this;
}

/**
 * 
 * @return
 *     The overview
 */
public String getOverview() {
    return overview;
}

/**
 * 
 * @param overview
 *     The overview
 */
public void setOverview(String overview) {
    this.overview = overview;
}

public PopularMovies withOverview(String overview) {
    this.overview = overview;
    return this;
}

/**
 * 
 * @return
 *     The released
 */
public String getReleased() {
    return released;
}

/**
 * 
 * @param released
 *     The released
 */
public void setReleased(String released) {
    this.released = released;
}

public PopularMovies withReleased(String released) {
    this.released = released;
    return this;
}

/**
 * 
 * @return
 *     The runtime
 */
public long getRuntime() {
    return runtime;
}

/**
 * 
 * @param runtime
 *     The runtime
 */
public void setRuntime(long runtime) {
    this.runtime = runtime;
}

public PopularMovies withRuntime(long runtime) {
    this.runtime = runtime;
    return this;
}

/**
 * 
 * @return
 *     The trailer
 */
public String getTrailer() {
    return trailer;
}

/**
 * 
 * @param trailer
 *     The trailer
 */
public void setTrailer(String trailer) {
    this.trailer = trailer;
}

public PopularMovies withTrailer(String trailer) {
    this.trailer = trailer;
    return this;
}

/**
 * 
 * @return
 *     The homepage
 */
public String getHomepage() {
    return homepage;
}

/**
 * 
 * @param homepage
 *     The homepage
 */
public void setHomepage(String homepage) {
    this.homepage = homepage;
}

public PopularMovies withHomepage(String homepage) {
    this.homepage = homepage;
    return this;
}

/**
 * 
 * @return
 *     The rating
 */
public double getRating() {
    return rating;
}

/**
 * 
 * @param rating
 *     The rating
 */
public void setRating(double rating) {
    this.rating = rating;
}

public PopularMovies withRating(double rating) {
    this.rating = rating;
    return this;
}

/**
 * 
 * @return
 *     The votes
 */
public long getVotes() {
    return votes;
}

/**
 * 
 * @param votes
 *     The votes
 */
public void setVotes(long votes) {
    this.votes = votes;
}

public PopularMovies withVotes(long votes) {
    this.votes = votes;
    return this;
}

/**
 * 
 * @return
 *     The updatedAt
 */
public String getUpdatedAt() {
    return updatedAt;
}

/**
 * 
 * @param updatedAt
 *     The updated_at
 */
public void setUpdatedAt(String updatedAt) {
    this.updatedAt = updatedAt;
}

public PopularMovies withUpdatedAt(String updatedAt) {
    this.updatedAt = updatedAt;
    return this;
}

/**
 * 
 * @return
 *     The language
 */
public String getLanguage() {
    return language;
}

/**
 * 
 * @param language
 *     The language
 */
public void setLanguage(String language) {
    this.language = language;
}

public PopularMovies withLanguage(String language) {
    this.language = language;
    return this;
}

/**
 * 
 * @return
 *     The availableTranslations
 */
public List<String> getAvailableTranslations() {
    return availableTranslations;
}

/**
 * 
 * @param availableTranslations
 *     The available_translations
 */
public void setAvailableTranslations(List<String> availableTranslations) {
    this.availableTranslations = availableTranslations;
}

public PopularMovies withAvailableTranslations(List<String> availableTranslations) {
    this.availableTranslations = availableTranslations;
    return this;
}

/**
 * 
 * @return
 *     The genres
 */
public List<String> getGenres() {
    return genres;
}

/**
 * 
 * @param genres
 *     The genres
 */
public void setGenres(List<String> genres) {
    this.genres = genres;
}

public PopularMovies withGenres(List<String> genres) {
    this.genres = genres;
    return this;
}

/**
 * 
 * @return
 *     The certification
 */
public String getCertification() {
    return certification;
}

/**
 * 
 * @param certification
 *     The certification
 */
public void setCertification(String certification) {
    this.certification = certification;
}

public PopularMovies withCertification(String certification) {
    this.certification = certification;
    return this;
}

/**
 * 
 * @return
 *     The images
 */
public Images getImages() {
    return images;
}

/**
 * 
 * @param images
 *     The images
 */
public void setImages(Images images) {
    this.images = images;
}

public PopularMovies withImages(Images images) {
    this.images = images;
    return this;
}

}

JSON 回应

[ { "title": "The Dark Knight", "year": 2008, "ids": { "trakt": 120, "slug": "the-dark-knight-2008", "imdb": "tt0468569", "tmdb": 155 }, "tagline": "Why So Serious?", "overview": "Batman raises the stakes in his war on crime. With the help of Lt. Jim Gordon and District Attorney Harvey Dent, Batman sets out to dismantle the remaining criminal organizations that plague the streets. The partnership proves to be effective, but they soon find themselves prey to a reign of chaos unleashed by a rising criminal mastermind known to the terrified citizens of Gotham as the Joker.", "released": "2008-07-18", "runtime": 152, "trailer": "http://youtube.com/watch?v=GVx5K8WfFJY", "homepage": "http://thedarkknight.warnerbros.com/dvdsite/", "rating": 9.03781, "votes": 24887, "updated_at": "2016-07-13T10:06:28.000Z", "language": "en", "available_translations": [ "en", "de", "fi", "sv", "zh", "ru", "nl", "it", "fr", "hu", "da", "es", "tr", "pt", "cs", "pl", "bg", "he", "sr", "no", "el", "sk", "ja", "th", "ko", "uk", "fa", "lv", "ro", "id", "bs", "ca" ], "genres": [ "action", "crime", "drama", "thriller" ], "certification": "PG-13", "images": { "fanart": { "full": "https://walter.trakt.us/images/movies/000/000/120/fanarts/original/f7884a908e.jpg", "medium": "https://walter.trakt.us/images/movies/000/000/120/fanarts/medium/f7884a908e.jpg", "thumb": "https://walter.trakt.us/images/movies/000/000/120/fanarts/thumb/f7884a908e.jpg" }, "poster": { "full": "https://walter.trakt.us/images/movies/000/000/120/posters/original/8369bf0d4a.jpg", "medium": "https://walter.trakt.us/images/movies/000/000/120/posters/medium/8369bf0d4a.jpg", "thumb": "https://walter.trakt.us/images/movies/000/000/120/posters/thumb/8369bf0d4a.jpg" }, "logo": { "full": "https://walter.trakt.us/images/movies/000/000/120/logos/original/3e39105d34.png" }, "clearart": { "full": "https://walter.trakt.us/images/movies/000/000/120/cleararts/original/295bcec2cd.png" }, "banner": { "full": "https://walter.trakt.us/images/movies/000/000/120/banners/original/7065417461.jpg" }, "thumb": { "full": "https://walter.trakt.us/images/movies/000/000/120/thumbs/original/6363cb8aeb.jpg" } } },

...

]

请尝试更改

public Observable<PopularMoviesResponse> getPopularMovies

public Observable<List<PopularMovies>> getPopularMovies

Android你的方法那么:

public Observable<List<PopularMovies>> fetchPopularMovies(String trakt_api_version,
                                                          String trakt_api_key,
                                                          String page) {
    return movieService 
            .getPopularMovies(trakt_api_version, trakt_api_key, page)
}

UPD

只是为了确保您的 POJO 匹配 JSON,您可以使用 that service. In that gist 您可以检查完整结果。