HY! 我使用YouTube Search API进行练习任务。 我想搜索视频,然后播放。所以我使用retrofit和rx进行服务通信。 我的问题是:
如果我在第一次搜索时没有互联网,请发送unkwon主机异常。 (没关系,因为我可以重试搜索,如果我有互联网连接获取新数据!)
如果我有互联网,我正在通过我的查询寻找第一个视频,它总是好的。当我从互联网断开连接并且我想要通过新查询或“旧”查询(+ pagetoken)的新视频时,总是抛出SocketTimeoutException。然后我再次使用互联网连接进行新查询抛出SocketTimeoutException。为什么? 有人有任何想法!?
我的YouTubeServiceImpl课程用于沟通:
YouTubeWebService youTubeWebService;
@Inject
public YouTubeServiceImpl(YouTubeWebService youTubeWebService) {
this.youTubeWebService = youTubeWebService;
}
@Override
public Observable<VideoSearchResult> search(String query) {
Map<String,String> queryMap = createBaseQueryMap(query);
return createVideoSearchResult(VideoSearchResultCode.THERE_ARE_NO_VIDEOS_BY_QUERY,R.string.no_videos_found,queryMap);
}
@Override
public Observable<VideoSearchResult> search(String query, String pageToken) {
Map<String,String> queryMap = createBaseQueryMap(query);
queryMap.put(YOUTUBE_SEARCH_PAGE_TOKEN_KEY,pageToken);
return createVideoSearchResult(VideoSearchResultCode.NO_MORE_PAGES,R.string.no_more_pages,queryMap);
}
private Observable<VideoSearchResult> createVideoSearchResult(final VideoSearchResultCode zeroItemsResultCode,
final int zeroItemMsgId,Map<String,String> queryMap){
return youTubeWebService.search(queryMap).map(new Function<SearchResponse, VideoSearchResult>() {
@Override
public VideoSearchResult apply(SearchResponse response) {
if (response.items.size() <= 0){
return new VideoSearchResult(zeroItemsResultCode,zeroItemMsgId);
}
return new VideoSearchResult(createVideoItemList(response.items),response.nextPageToken);
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}
private Map<String,String> createBaseQueryMap(String query){
Map<String,String> queryMap = new HashMap<>();
queryMap.put(YOUTUBE_SEARCH_PART_KEY,YOUTUBE_SEARCH_PART_SNIPPET_KEY);
queryMap.put(YOUTUBE_SEARCH_KEY_KEY,YOUTUBE_SEARCH_API_KEY_VALUE);
queryMap.put(YOUTUBE_SEARCH_TYPE_KEY,YOUTUBE_SEARCH_VIDEO_TYPE_KEY);
queryMap.put(YOUTUBE_SEARCH_Q_KEY,query);
queryMap.put(YOUTUBE_SEARCH_MAX_RESULTS_KEY,YOUTUBE_SEARCH_MAX_RESULTS_VALUE_KEY);
return queryMap;
}
private List<VideoItem> createVideoItemList(List<SearchResponse.Item> items){
List<VideoItem> videoItems = new ArrayList<>();
for (SearchResponse.Item item : items) {
///TODO: Create item and add to list
videoItems.add(new VideoItem(item.id.videoId,item.snippet.title,
item.snippet.description,item.snippet.thumbnails.aDefault.url));
}
return videoItems;
}
YouTube网站服务由Dagger2提供:
@Provides
@Singleton
static YouTubeWebService provideYouTubeWebService(){
return createYouTubeRetrofit().create(YouTubeWebService.class);
}
private static Retrofit createYouTubeRetrofit(){
return new Retrofit.Builder()
.baseUrl(YOUTUBE_API_BASE_URL_KEY)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(createYouTubeOkHttpClient())
.build();
}
private static OkHttpClient createYouTubeOkHttpClient(){
return new OkHttpClient.Builder().addNetworkInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
// try the request
Response response = chain.proceed(request);
int tryCount = 0;
while (!response.isSuccessful() && tryCount < 3) {
Log.d("intercept", "Request is not successful - " + tryCount);
tryCount++;
// retry the request
response = chain.proceed(request);
}
// otherwise just pass the original response on
return response;
}
}).build();
}
VideoItemDataSource(用于分页库)中的基本服务用法
private static final String LOG_TAG = "VideoItemDataSource";
YouTubeService youTubeService;
String query;
String pageToken;
public VideoItemDataSource(YouTubeService youTubeService,String query) {
this.youTubeService = youTubeService;
this.query = query;
}
@Override
public void loadInitial(@NonNull LoadInitialParams<String> params, @NonNull LoadInitialCallback<VideoItem> callback) {
youTubeService.search(query).subscribe(new DisposableObserver<VideoSearchResult>() {
@Override
public void onNext(VideoSearchResult result) {
Log.d(LOG_TAG,"loadInitial onNext: " + result.toString());
pageToken = result.getPageToken();
callback.onResult(result.getVideoItemList());
}
@Override
public void onError(Throwable e) {
Log.d(LOG_TAG,"loadInitial onError: " + e.toString());
e.printStackTrace();
}
@Override
public void onComplete() {
Log.d(LOG_TAG,"loadInitial onComplete: ");
}
});
}
@Override
public void loadAfter(@NonNull LoadParams<String> params, @NonNull LoadCallback<VideoItem> callback) {
youTubeService.search(query,pageToken).subscribe(new DisposableObserver<VideoSearchResult>() {
@Override
public void onNext(VideoSearchResult result) {
Log.d(LOG_TAG,"loadAfter onNext: " + result.toString());
pageToken = result.getPageToken();
callback.onResult(result.getVideoItemList());
}
@Override
public void onError(Throwable e) {
Log.d(LOG_TAG,"loadAfter onError: " + e.toString());
e.printStackTrace();
}
@Override
public void onComplete() {
Log.d(LOG_TAG,"loadAfter onComplete: ");
}
});
}
@Override
public void loadBefore(@NonNull LoadParams<String> params, @NonNull LoadCallback<VideoItem> callback) {
}
@NonNull
@Override
public String getKey(@NonNull VideoItem item) {
return item.getId();
}
所以我想要没有sockettimeoutexception的新搜索,如果我有互联网但以前的搜索没有互联网。 有没有人知道解决方案是什么? 重要!我的Android虚拟设备遇到此问题(API22,27) 但我的真实设备没有经验(小米Redmi 3 PRO API 22 [?])