14.4 总结
1.点击ADM不能查看data文件夹,android device monitor不能查看/data目录。
2.不要忘记china后面是有/。
String address="http://guolin.tech/api/china/"+provincecode+"/"+citycode;
3.ProgressDialog在24以上的是用不了的。
4.setselection(int position)的作用就是把第position位置的数据显示在listview的最上面一项。来自ListView的setSelection用法。下文代码就是把第一项放在最上面一项。假如你设置1,就是把第二位的数据显示在listview的最上面一项,那么第一项呢,向上滑动就可以看到。
listView.setSelection(0);
5.OkHttp 建立一个新方法,使程序可以多次调用,并带有回调参数callback,同时在client.newCall(request)没有调用excuter()方法,而是调用enqueue()方法,该方法的内部已经开好子线程了,在子线程中去执行HTTP请求,并将最终的请求结果回调OKhttp.Callback当中,在调用它的时候要重写onResponse(),得到服务器返回的具体内容,重写onFailure()方法,在这里对异常情况进行处理。不可以再这里进行UI操作。
public class HttpUtil {
public static void sendOkHttpRequest(String address,okhttp3.Callback callback){
OkHttpClient client=new OkHttpClient();
Request request=new Request.Builder().url(address).build();
client.newCall(request).enqueue(callback);
}
那么我们在调用sendOkHttpRequest()方法的时候就可以这样写
HttpUtil。sendOkHttpRequest("http://www.baidu.com",new okhhtp3.Callback())
{
@Override
public void onResponse(Call call,Response response)throws IOException{
//得到服务器返回的具体内容
String responseData =response.body().string();
}
@Override
public void onFailure(Call call,IOException e){
//在这里对异常情况进行处理
}
}
在coolweather中,重写了onFailure()方法,onResponse()方法。
-
onFailure()方法
如果加载失败,要返回UI线程,去关闭加载框,并提示加载失败字样。
-
onResponse()方法
首先去判断要去服务器查询什么type的数据,包含三个种类,去调用相应解析json的方法。之后数据库中已经包含数据了,所以调用对应type的读取数据库数据的方法。
HttpUtil.sendOkHttpRequest(address, new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//失败了,返回UI线程处理逻辑
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
//关闭加载框
// closeProgressBar();
closeProgressDialog();
Toast.makeText(getContext(),"加载失败",Toast.LENGTH_SHORT).show();
}
});
}
//得到服务器返回的具体内容
@Override
public void onResponse(Call call, Response response) throws IOException {
String responseText=response.body().string();
boolean result=false;
if("province".equals(type))
result = Utility.handleProvinceResponse(responseText);
else if("city".equals(type)){
result=Utility.handleCityResponse(responseText,selectedProvince.getId());
}
else if("county".equals(type)){
result=Utility.handleCountyResponse(responseText,selectedCity.getId());
}
//解析完数据牵涉到UI操作,因此必须要在主线程中调用。
//数据库中有了,可以显示了。
if(result){
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
///关闭进度框
// closeProgressBar();
closeProgressDialog();
if("province".equals(type))
queryProvinces();
else if("city".equals(type)){
queryCities();
}
else if("county".equals(type)){
queryCounties();
}
}
});
}
}
});
- 和风天气默认让你去使用sdk类型的key,所以要注意我们使用的key要是Web API类型,刚开始我注册后,一直不好使,最后才发现申请的key是sdk类型。和风天气注册地址。
14.5总结
1. gson
1.1 gson基本用法
回顾gson的使用,并找一些json格式的数据进行解析。
String response="[{img=0.0,name=非会员,qualify_amount=0.0}," +
"{img=1.0,name=一级会员,qualify_amount=100.0}," +
"{img=2.0, name=二级会员,qualify_amount=300.0}]";
由于是数组中有多个对象,所以可以用List的方法进行解析,解析方法如下:
Gson gson=new Gson();
//数组的话可以这么做
List<User>users=gson.fromJson(response,new TypeToken<List<User>>(){
}.getType());
for (User user:users){
System.out.println(user.img+" "+user.name+" "+user.qualify_amount);
1.2 属性重命名
这里参考自Gson用法详解。当我们的接口返回的数据与我们期望的数据不同时,我们可以使用属性重命名。或者下述的json数据中有一个tz,我们怕忘记它的意思想给他改成time,就需要使用@SerializedName 来建立与java字段的联系。
/**
* admin_area : 北京
* tz : +8.00
* location : 北京
* lon : 116.4052887
* parent_city : 北京
* cnty : 中国
* lat : 39.90498734
* cid : CN101010100
*/
private String admin_area;
@SerializedName("tz")
private String time;
SerializeName远比你想象的更强大,假如,json数据如下:userName,user_name,Name,都是指向一个值,此时我们可以使用alternate属性。很奇怪的是,我翻看了我的SerializedName类发现竟然没有alternate这个方法,黑人问号脸,为什么问号它围绕着我?
{
\"userName\":\"leavesC\",\"age\":24,\"sex\":true}
{
\"user_name\":\"leavesC\",\"age\":24,\"sex\":true}
{
\"Name\":\"leavesC\",\"age\":24,\"sex\":true}
@SerializedName(value = "userName", alternate = {
"user_name", "Name"})
private String name;
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.google.gson.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({
ElementType.FIELD})
public @interface SerializedName {
String value();
}
1.3 JsonDeserializer
参考自Gson 解析复杂数据。首先有一个Json对象,表示一本书的基本信息。
{
'title': 'Java Puzzlers: Traps, Pitfalls, and Corner Cases',
'isbn-10': '032133678X',
'isbn-13': '978-0321336781',
'authors': ['Joshua Bloch', 'Neal Gafter']
}
java的变量名不容许有‘-’符号的,我们可以使用@SerializedName注解来处理,不过对于一些复杂情况是难以处理的,所以我们使用JsonDeserializer。我们需要自定义一个JsonDeserializer,然后注册到GsonBuilder,GsonBuilder在解析时就会自动使用我们自定义的JsonDeserializer。
首先我们需要创建一个BookJsonDeserializer。它负责把Book对应的Json对象,解析为Java对象。
public class BookDeserializer implements JsonDeserializer<Book> {
@Override
public Book deserialize(final JsonElement jsonElement, final Type typeOfT, final JsonDeserializationContext context)
throws JsonParseException {
//todo 解析字段
final Book book = new Book();
book.setTitle(title);
book.setIsbn10(isbn10);
book.setIsbn13(isbn13);
book.setAuthors(authors);
return book;
}
}
简单介绍下JsonDeserializer,它需要有一个Type,那肯定是我们的Book。我们要重写deserialize()函数,并在其中解析json数据,最后返回一个Book对象。这里比较重要的是,Gson解析Json对象在内部表示为JsonElement,虽然element是元素的意思,但JsonElement可以表示为下列的任何一种:
1. JsonPrimitive :Java 基本类型的包装类,以及 String
2. JsonObject:类比 Js 中 Object的表示,或者 Java 中的 Map<String, JsonElement>,一个键值对结构。
3. JsonArray:JsonElement 组成的数组,注意:这里是 JsonElement,说明这个数组是混合类型的。
4. JsonNull:值为 null
完整代码如下,根据上述所讲,就可以解释,为什么要用getAsString和getAsJsonArray了。使用getAsString时是这个JsonElement表示为JsonPrimitive。使用getAsJsonArray时,虽然读取的是[‘Joshua Bloch’, ‘Neal Gafter’]这个数组,但表示为JsonElement所以,要给他转化一下。
class BookDeserializer implements JsonDeserializer<Book>{
@Override
public Book deserialize(final JsonElement jsonElement, final Type typeOfT,
final JsonDeserializationContext context)throws JsonParseException{
final JsonObject jsonObject=jsonElement.getAsJsonObject();
JsonElement titleElement=jsonObject.get("title");
final String title=titleElement.getAsString();
JsonElement isbn10Element=jsonObject.get("isbn-10");
final String isbn10=isbn10Element.getAsString();
JsonElement isbn13Element=jsonObject.get("isbn-13");
final String isbn13=isbn13Element.getAsString();
//虽然是个数组,但Gson解析json对象并在内部表示为JsonElement,
// 这里的其实是表示为JsonElement的JsonArray,所以要在get之后用getAsJsonArray();
JsonArray authors=jsonObject.get("authors").getAsJsonArray();
String[]Authors=new String[authors.size()];