在LifeUtil项目中,我们的“阅读”模块和“图片”模块都需要请求网络数据。
效果如下图:
无论是图片展示还是右边的文字项,都得获取网络数据。所以,有必要单独拿出来讲讲。这里先声明一下,阅读和图片模块中除美女专题外数据均是用Jsoup去网上爬取,(仅做学习交流,如有侵权,立即删除)。
这里的数据获取有两种方式:
“图片”模块中的美女专题,我在项目中使用了RxJava+Retofit +Gson解析。然后使用Glide加载展示图片。
“其他的”,使用Jsoup爬取。
一、Gson解析Json
下面是RxJava+Retrofit+Gson解析网络数据的代码模板:
- Retofit管理类
封装了Retrofit,并以Gson来解析Json格式的数据。
public class RetrofitManager {
private static RetrofitManager instance;
private static Retrofit retrofit;
private static Gson gson;
private static String cookie = "";
private static final String BASE_URL ="";
public RetrofitManager() {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(httpClient())
.addConverterFactory(GsonConverterFactory.create(gson()))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
}
public static void reset() {
instance = null;
}
public <T> T create(Class<T> service) {
return retrofit.create(service);
}
public static RetrofitManager getInstance() {
if (instance == null) {
synchronized (RetrofitManager.class) {
instance = new RetrofitManager();
}
}
return instance;
}
private static OkHttpClient httpClient() {
return new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build();
}
private Gson gson() {
if (gson == null) {
synchronized (RetrofitManager.class) {
gson = new GsonBuilder().setLenient().create();
}
}
return gson;
}
}
- API工厂类
封装所有的API,并以单例模式返回。
public class ApiFactory {
//用于同步处理
protected static final Object monitor = new Object();
private static GirlsController girlsController;
public static GirlsController getGirlsController(){
if(girlsController==null){
synchronized (monitor){
girlsController =RetrofitManager.getInstance().create(GirlsController.class);
}
}
return girlsController;
}
}
- 具体Retrofit数据接口实现(这里是美女专题的接口)
public interface GirlsController {
@GET ("http://gank.io/api/data/%E7%A6%8F%E5%88%A9/6/{page}")
Observable<BaseGankResponse<List<Girl>>> getGank(@Path("page") String page);
@GET ("http://gank.io/api/data/%E7%A6%8F%E5%88%A9/10/{page}")
Observable<ResponseBody> getGankBody(@Path("page") String page);
}
上面三个步骤创建好了之后,就可以在MainActivity中使用RxJava调用,实现网络数据的请求了。
代码如下:
public void getGank(int curPage) {
ApiFactory.getGirlsController().getGank(curPage + "").subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<BaseGankResponse<List<Girl>>>() {
@Override
public void onCompleted() {
((MainActivity) getActivity()).showSnack("加载完成");
binding.swipRefreshLayout.setRefreshing(false);
}
@Override
public void onError(Throwable e) {
((MainActivity) getActivity()).showSnack("加载失败");
binding.swipRefreshLayout.setRefreshing(false);
}
@Override
public void onNext(BaseGankResponse<List<Girl>> response) {
for (Girl girl : response.datas) {
if (girl.getHeight() == 0) {
girl.setHeight((new Random().nextInt(100)) + 500);
}
}
//Adapter更新数据
if (isRefresh) {
adapter.setNewData(response.datas);
} else {
adapter.addDatas(response.datas);
}
}
});
}
当然,我们不能把Girl类忘掉的,否则Gson是解析不出来数据的。
GirlBean类
public class Girl implements Serializable {
private String url;
@SerializedName("who")
String name ;
@SerializedName("desc")
String date;
public Girl(String url) {
this.url = url;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
这样,数据请求就完成了。然后在Adapter中使用Glide加载显示图片就ok了。可以看到使用RxJava很方便的帮我们解决了异步的问题,而不用在数据加载完成后使用Handler机制切换回到主线程进行UI操作。
二、Jsoup爬取网页
/**
* 从服务器上获取数据
*/
public void getDataFromServer() {
final String url = getArguments().getString("url");
subscription = Observable.just(url).subscribeOn(Schedulers.io()).map(new Func1<String, List<PhotoItem>>() {
@Override
public List<PhotoItem> call(String s) {
List<PhotoItem> photoList = new ArrayList<>();
try {
Document doc = Jsoup.connect(url).timeout(5000).get();
Element element = doc.select("div.wrap").last();
Elements items = element.select("div.kboxgrid");
for (Element ele : items) {
PhotoItem item = new PhotoItem();
Element content = ele.select("div.boxgrid").first();
Element info = ele.select("div.citemqt").first();
String name = info.select("a").first().text();
String imgUrl = content.select("img").first().attr("src");
String from =content.select("a").first().attr("href");
String date =info.select("a").last().text();
item.setName(name);
item.setImg(imgUrl);
item.setFrom(from);
item.setDate(date);
photoList.add(item);
}
} catch (IOException e) {
e.printStackTrace();
}
return photoList;
}
}).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<List<PhotoItem>>() {
@Override
public void onCompleted() {
binding.swipeRefreshLayout.setRefreshing(false);
((MainActivity) getActivity()).showSnack("加载完成");
}
@Override
public void onError(Throwable e) {
((MainActivity) getActivity()).showSnack("加载失败");
binding.swipeRefreshLayout.setRefreshing(false);
}
@Override
public void onNext(List<PhotoItem> list) {
adapter.setNewData(list);
}
});
}
这里主要是在map方法中将url使用Jsoup解析html,然后获取到我们所需的类,设置到Adpater中就搞定了。
上一篇:Android开源项目LifeUtil 之Base类
下一篇:Android开源项目LifeUtil 之数据展示