Android Java如何调用API获取维基共享资源的图片标题与链接
Android Java 实现Wikimedia Commons图片资源抓取方案
1. 接口结构说明
该接口为典型的MediaWiki API返回结构,query.pages不是数组而是以页面ID为key的对象,同时接口采用分页返回逻辑,单次请求最多返回50条数据,需要通过返回的continue字段拉取全量数据。
2. 依赖引入
首先在模块级build.gradle中引入常用的网络请求和JSON解析库:
dependencies { // 网络请求库 implementation 'com.squareup.okhttp3:okhttp:4.11.0' // JSON解析库 implementation 'com.google.code.gson:gson:2.10.1' // 安卓异步任务工具,避免阻塞主线程 implementation 'androidx.concurrent:concurrent-futures:1.1.0' }
添加网络权限到AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
3. 实体类定义
按照接口返回结构定义对应的Java类,重点处理pages的Map结构:
// 根返回实体 public class ApiResponse { @SerializedName("batchcomplete") private String batchComplete; @SerializedName("continue") private ContinueBean continueData; private QueryBean query; // 自行添加get、set方法 } // 分页参数实体 public class ContinueBean { private String gcmcontinue; @SerializedName("continue") private String continueStr; // 自行添加get、set方法 } // 查询结果实体 public class QueryBean { // 核心:用Map接收key为页面ID的对象集合 private Map<String, PageBean> pages; // 自行添加get、set方法 } // 单张图片页面实体 public class PageBean { private String title; @SerializedName("imageinfo") private List<ImageInfoBean> imageInfo; // 自行添加get、set方法 } // 图片信息实体 public class ImageInfoBean { private String url; // 自行添加get、set方法 } // 最终需要的图片结果实体 public class ImageItem { private String title; private String imageUrl; public ImageItem(String title, String imageUrl) { this.title = title; this.imageUrl = imageUrl; } // 自行添加get、set方法 }
4. 核心抓取逻辑
分单页解析和分页拉取全量数据两部分实现:
public class WikimediaFetcher { private static final String BASE_API = "https://commons.wikimedia.org/w/api.php?action=query&prop=imageinfo&iiprop=timestamp|user|url&generator=categorymembers&gcmtype=file&gcmtitle=Category:Featured_pictures_on_Wikimedia_Commons&format=json&utf8"; private final OkHttpClient okHttpClient = new OkHttpClient(); private final Gson gson = new Gson(); // 全量结果存储 private final List<ImageItem> allImageItems = new ArrayList<>(); // 对外调用入口,需运行在子线程 public List<ImageItem> fetchAllImages() throws IOException { allImageItems.clear(); String nextContinueParam = ""; do { String requestUrl = BASE_API; // 拼接分页参数 if (!nextContinueParam.isEmpty()) { requestUrl += "&gcmcontinue=" + nextContinueParam; } // 发起网络请求 Request request = new Request.Builder() .url(requestUrl) .build(); try (Response response = okHttpClient.newCall(request).execute()) { if (!response.isSuccessful() || response.body() == null) { break; } String jsonStr = response.body().string(); ApiResponse apiResponse = gson.fromJson(jsonStr, ApiResponse.class); // 解析当前页数据 if (apiResponse.getQuery() != null && apiResponse.getQuery().getPages() != null) { for (Map.Entry<String, PageBean> entry : apiResponse.getQuery().getPages().entrySet()) { PageBean page = entry.getValue(); if (page.getImageInfo() != null && !page.getImageInfo().isEmpty()) { String title = page.getTitle(); // 可按需去掉标题开头的File:前缀 if (title.startsWith("File:")) { title = title.substring(5); } String url = page.getImageInfo().get(0).getUrl(); allImageItems.add(new ImageItem(title, url)); } } } // 检查是否存在下一页 if (apiResponse.getContinueData() != null && apiResponse.getContinueData().getGcmcontinue() != null) { nextContinueParam = apiResponse.getContinueData().getGcmcontinue(); } else { nextContinueParam = ""; } } } while (!nextContinueParam.isEmpty()); return allImageItems; } }
5. 安卓端调用注意事项
网络请求不能在主线程执行,可通过Thread+Handler实现线程切换:
// Activity中调用示例 new Thread(() -> { try { List<ImageItem> images = new WikimediaFetcher().fetchAllImages(); // 切换到主线程更新UI runOnUiThread(() -> { // 此处更新列表UI逻辑 }); } catch (IOException e) { e.printStackTrace(); } }).start();
内容的提问来源于stack exchange,提问作者Mohammad Mustafa Raza
相关产品推荐
相关产品推荐

