Android 数据交换解析框架Gson使用详解

Json 是一种文本形式的数据交换格式,比 xml 更为轻量。Json 的解析和生成的方式很多,在 Android 平台上最常用的类库有 Gson 和 FastJson 两种,这里要介绍的是 Gson。

Gson主页:https://github.com/google/gson

一、Gson的基本用法

1.1、Gson对象

在进行序列化与反序列操作前,需要先实例化一个 com .google.gson.Gson 对象,获取 Gson 对象的方法有两种

        //通过构造函数来获取        Gson gson = new Gson();        //通过 GsonBuilder 来获取,可以进行多项特殊配置        Gson gson = new GsonBuilder().create();

1.2、生成 Json

利用 Gson 可以很方便地生成 Json 字符串,通过使用 addProperty 的四个重载方法

    public static void main(String[] args) {        JsonObject jsonObject = new JsonObject();        jsonObject.addProperty("String", "leavesC");        jsonObject.addProperty("Number_Integer", 23);        jsonObject.addProperty("Number_Double", 22.9);        jsonObject.addProperty("Boolean", true);        jsonObject.addProperty("Char", 'c');        System.out.println();        System.out.println(jsonObject);    }

addProperty 方法底层调用的是 add(String property, JsonElement value) 方法,即将基本数据类型转化为了 JsonElement 对象,JsonElement 是一个抽象类,而 JsonObject 继承了 JsonElement ,因此我们可以通过 JsonObject 自己来构建一个 JsonElement

    public static void main(String[] args) {        JsonObject jsonObject = new JsonObject();        jsonObject.addProperty("String", "leavesC");        jsonObject.addProperty("Number", 23);        jsonObject.addProperty("Number", 22.9);        jsonObject.addProperty("Boolean", true);        jsonObject.addProperty("Char", 'c');        JsonObject jsonElement = new JsonObject();        jsonElement.addProperty("Boolean", false);        jsonElement.addProperty("Double", 25.9);        jsonElement.addProperty("Char", 'c');        jsonObject.add("JsonElement", jsonElement);        System.out.println();        System.out.println(jsonObject);    }

1.3、Json与数组、List的转化

Json数组 与 字符串数组

    public static void main(String[] args) {        //Json数组 转为 字符串数组        Gson gson = new Gson();        String jsonArray = "[\"https://github.com/leavesC\",\"https://www.jianshu.com/u/9df45b87cfdf\",\"Java\",\"Kotlin\",\"Git\",\"GitHub\"]";        String[] strings = gson.fromJson(jsonArray, String[].class);        System.out.println("Json数组 转为 字符串数组: ");        for (String string : strings) {            System.out.println(string);        }        //字符串数组 转为 Json数组        jsonArray = gson.toJson(jsonArray, new TypeToken<String>() {        }.getType());        System.out.println("\n字符串数组 转为 Json数组: ");        System.out.println(jsonArray);    }

Json数组 与 List

    public static void main(String[] args) {        //Json数组 转为 List        Gson gson = new Gson();        String jsonArray = "[\"https://github.com/leavesC\",\"https://www.jianshu.com/u/9df45b87cfdf\",\"Java\",\"Kotlin\",\"Git\",\"GitHub\"]";        List<String> stringList = gson.fromJson(jsonArray, new TypeToken<List<String>>() {        }.getType());        System.out.println("\nJson数组 转为 List: ");        for (String string : stringList) {            System.out.println(string);        }        //List 转为 Json数组        jsonArray = gson.toJson(stringList, new TypeToken<List<String>>() {        }.getType());        System.out.println("\nList 转为 Json数组: ");        System.out.println(jsonArray);    }

1.4、序列化与反序列化

Gson 也提供了 toJson() 和 fromJson() 两个方法用于转化 Model 与 Json,前者实现了序列化,后者实现了反序列化
首先,声明一个 User 类

/** * 作者:chenZY * 时间:2018/3/17 18:32 * 描述:https://github.com/leavesC */public class User {    private String name;    private int age;    private boolean sex;    public User(String name, int age, boolean sex) {        this.name = name;        this.age = age;        this.sex = sex;    }    @Override    public String toString() {        return "User{" +                "name='" + name + '\'' +                ", age=" + age +                ", sex=" + sex +                '}';    }}

序列化的方法很简单,调用 gson 对象的 toJson 方法,传入要序列化的对象

    public static void main(String[] args) {        //序列化        User user = new User("leavesC", 24, true);        Gson gson = new Gson();        System.out.println();        System.out.println(gson.toJson(user));    }

反序化的方式也类似

    public static void main(String[] args) {        //反序列化        String userJson = "{\"name\":\"leavesC\",\"age\":24,\"sex\":true}";        Gson gson = new Gson();        User user = gson.fromJson(userJson, User.class);        System.out.println();        System.out.println(user);    }

二、属性重命名

继续使用上一节声明的 User 类,根据 User 类声明的各个属性名,移动端的开发者希望接口返回的数据格式即是如下这样的

{"name":"leavesC","age":24,"sex":true}

如果没有和服务器端沟通好或者是 API 改版了,接口返回的数据格式可能是这样的

{"Name":"leavesC","age":24,"sex":true}
{"userName":"leavesC","age":24,"sex":true}

如果继续使用上一节介绍的方法,那无疑会解析出错
例如

    public static void main(String[] args) {        //反序列化        String userJson = "{\"userName\":\"leavesC\",\"age\":24,\"sex\":true}";        Gson gson = new Gson();        User user = gson.fromJson(userJson, User.class);        System.out.println();        System.out.println(user);    }

name 属性值解析不到,所以为 null

此时为了兼顾多种格式的数据,就需要使用 SerializedName 注解
根据 SerializedName 的声明来看,SerializedName 包含两个属性值,一个是字符串,一个是字符串数组,而字符串数组含有默认值

@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD, ElementType.METHOD})public @interface SerializedName {    String value();    String[] alternate() default {};}

SerializedName 的作用是为了在序列化或反序列化时,指导 Gson 如果将原有的属性名和其它特殊情况下的属性名联系起来

例如,修改 User 类,为 name 声明 SerializedName 注解,注解值为 userName

/** * 作者:chenZY * 时间:2018/3/17 18:32 * 描述:https://github.com/leavesC */public class User {    @SerializedName("userName")    private String name;    private int age;    private boolean sex;}

在序列时,Json 格式就会相应改变

    public static void main(String[] args) {        //序列化        User user = new User("leavesC", 24, true);        Gson gson = new Gson();        System.out.println();        System.out.println(gson.toJson(user));    }

在反序列化时也一样,能够解析到正确的属性值

    public static void main(String[] args) {        //反序列化        String userJson = "{\"userName\":\"leavesC\",\"age\":24,\"sex\":true}";        Gson gson = new Gson();        User user = gson.fromJson(userJson, User.class);        System.out.println();        System.out.println(user);    }

还有个问题没解决,为了应对多种属性名不一致的情况,难道我们要声明多个 User 类吗?这显然是不现实的,所以还需要为 User 类设置多个备选属性名,这就需要用到 SerializedName 注解的另一个属性值alternate 了。

/** * 作者:chenZY * 时间:2018/3/17 18:32 * 描述:https://github.com/leavesC */public class User {    @SerializedName(value = "userName", alternate = {"user_name", "Name"})    private String name;    private int age;    private boolean sex;}

以下几种情况都能够被正确的反序列化

    public static void main(String[] args) {        //反序列化        Gson gson = new Gson();        String userJson = "{\"userName\":\"leavesC\",\"age\":24,\"sex\":true}";        User user = gson.fromJson(userJson, User.class);        System.out.println();        System.out.println(user);        userJson = "{\"user_name\":\"leavesC\",\"age\":24,\"sex\":true}";        user = gson.fromJson(userJson, User.class);        System.out.println();        System.out.println(user);        userJson = "{\"Name\":\"leavesC\",\"age\":24,\"sex\":true}";        user = gson.fromJson(userJson, User.class);        System.out.println();        System.out.println(user);    }

三、字段过滤

有时候并不是所有的字段都需要进行系列化和反序列化,因此需要对某些字段进行排除,有四种方法可以来实现这种需求。

3.1、基于@Expose注解

Expose 注解包含两个属性值,且均声明了默认值。Expose 的含义即为“暴露”,即用于对外暴露字段,serialize 用于指定是否进行序列化,deserialize 用于指定是否进行反序列化。如果字段不声明 Expose 注解,则意味着不进行序列化和反序列化操作,相当于两个属性值均为 false 。此外,Expose 注解需要和 GsonBuilder 构建的 Gson 对象一起使用才能生效。

@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD})public @interface Expose {    boolean serialize() default true;    boolean deserialize() default true;}

Expose 注解的注解值声明情况有四种

    @Expose(serialize = true, deserialize = true)   //序列化和反序列化都生效    @Expose(serialize = false, deserialize = true)  //序列化时不生效,反序列化时生效    @Expose(serialize = true, deserialize = false)  //序列化时生效,反序列化时不生效    @Expose(serialize = false, deserialize = false) //序列化和反序列化都不生效,和不写注解一样

现在来看个例子,修改 User 类

/** * 作者:chenZY * 时间:2018/3/17 18:32 * 描述:https://github.com/leavesC */public class User {    @Expose(serialize = true, deserialize = true)   //序列化和反序列化都生效    private String a;    @Expose(serialize = false, deserialize = true)  //序列化时不生效,反序列化时生效    private String b;    @Expose(serialize = true, deserialize = false)  //序列化时生效,反序列化时不生效    private String c;    @Expose(serialize = false, deserialize = false) //序列化和反序列化都不生效,和不写注解一样    private String d;    private String e;    public User(String a, String b, String c, String d, String e) {        this.a = a;        this.b = b;        this.c = c;        this.d = d;        this.e = e;    }    @Override    public String toString() {        return "User{" +                "a='" + a + '\'' +                ", b='" + b + '\'' +                ", c='" + c + '\'' +                ", d='" + d + '\'' +                ", e='" + e + '\'' +                '}';    }}

按照如上的注解值,只有声明了 Expose 注解且 serialize 值为 true 的字段才能被序列化,只有声明了 Expose 注解且 deserialize 值为 true 的字段才能被反序列化

    public static void main(String[] args) {        Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();        User user = new User("A", "B", "C", "D", "E");        System.out.println();        System.out.println(gson.toJson(user));        String json = "{\"a\":\"A\",\"b\":\"B\",\"c\":\"C\",\"d\":\"D\",\"e\":\"E\"}";        user = gson.fromJson(json, User.class);        System.out.println();        System.out.println(user.toString());    }

3.2、基于版本

Gson 提供了 @Since 和 @Until 两个注解基于版本对字段进行过滤,@Since 和 @Until 都包含一个 Double 属性值,用于设置版本号。Since 的意思是“自……开始”,Until 的意思是“到……为止”,一样要和 GsonBuilder 配合使用。

@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD, ElementType.TYPE})public @interface Since {    double value();}@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD, ElementType.TYPE})public @interface Until {    double value();}

当版本( GsonBuilder 设置的版本) 大于或等于 Since 属性值或小于 Until 属性值时字段会进行序列化和反序列化操作,而没有声明注解的字段都会加入序列化和反序列操作

现在来看个例子,修改 User 类

/** * 作者:chenZY * 时间:2018/3/17 18:32 * 描述:https://github.com/leavesC */public class User {    @Since(1.4)    private String a;    @Since(1.6)    private String b;    @Since(1.8)    private String c;    @Until(1.6)    private String d;    @Until(2.0)    private String e;    public User(String a, String b, String c, String d, String e) {        this.a = a;        this.b = b;        this.c = c;        this.d = d;        this.e = e;    }    @Override    public String toString() {        return "User{" +                "a='" + a + '\'' +                ", b='" + b + '\'' +                ", c='" + c + '\'' +                ", d='" + d + '\'' +                ", e='" + e + '\'' +                '}';    }}
    public static void main(String[] args) {        Gson gson = new GsonBuilder().setVersion(1.6).create();        User user = new User("A", "B", "C", "D", "E");        System.out.println();        System.out.println(gson.toJson(user));        String json = "{\"a\":\"A\",\"b\":\"B\",\"c\":\"C\",\"d\":\"D\",\"e\":\"E\"}";        user = gson.fromJson(json, User.class);        System.out.println();        System.out.println(user.toString());    }

3.3、基于访问修饰符

访问修饰符由 java.lang.reflect.Modifier 提供 int 类型的定义,而 GsonBuilder 对象的excludeFieldsWithModifiers方法接收一个 int 类型可变参数,指定不进行序列化和反序列化操作的访问修饰符字段
看个例子

/** * 作者:chenZY * 时间:2018/3/17 18:32 * 描述:https://github.com/leavesC */public class ModifierSample {    public String publicField = "public";    protected String protectedField = "protected";    private String privateField = "private";    String defaultField = "default";    final String finalField = "final";    static String staticField = "static";}
    public static void main(String[] args) {        Gson gson = new GsonBuilder().excludeFieldsWithModifiers(Modifier.PRIVATE, Modifier.STATIC).create();        ModifierSample modifierSample = new ModifierSample();        System.out.println(gson.toJson(modifierSample));    }

3.4、基于策略

GsonBuilder 类包含 setExclusionStrategies(ExclusionStrategy... strategies)方法用于传入不定长参数的策略方法,用于直接排除指定字段名或者指定字段类型
看个例子

/** * 作者:chenZY * 时间:2018/3/17 18:32 * 描述:https://github.com/leavesC */public class Strategies {    private String stringField;    private int intField;    private double doubleField;    public Strategies(String stringField, int intField, double doubleField) {        this.stringField = stringField;        this.intField = intField;        this.doubleField = doubleField;    }    @Override    public String toString() {        return "Strategies{" +                "stringField='" + stringField + '\'' +                ", intField=" + intField +                ", doubleField=" + doubleField +                '}';    }}
public static void main(String[] args) {        Gson gson = new GsonBuilder().setExclusionStrategies(new ExclusionStrategy() {            @Override            public boolean shouldSkipField(FieldAttributes fieldAttributes) {                //排除指定字段名                return fieldAttributes.getName().equals("intField");            }            @Override            public boolean shouldSkipClass(Class<?> aClass) {                //排除指定字段类型                return aClass.getName().equals(double.class.getName());            }        }).create();        Strategies strategies = new Strategies("stringField", 111, 11.22);        System.out.println();        System.out.println(gson.toJson(strategies));        String json = "{\"stringField\":\"stringField\",\"intField\":111,\"doubleField\":11.22}";        strategies = gson.fromJson(json, Strategies.class);        System.out.println();        System.out.println(strategies);    }

字段名为 "intField" 和字段类型为 double 的字段都会被排除掉

setExclusionStrategies 方法在序列化和反序列化时都会生效,如果只是想指定其中一种情况下的排除策略或分别指定排除策略,可以改为使用以下两个方法

addSerializationExclusionStrategy(ExclusionStrategy strategy);

addDeserializationExclusionStrategy(ExclusionStrategy strategy);

四、个性化配置

4.1、输出 null

对于 Gson 而言,在序列化时如果某个属性值为 null 的话,那么在序列化时该字段不会参与进来,如果想要显示输出该字段的话,可以通过 GsonBuilder 进行配置

/** * 作者:chenZY * 时间:2018/3/17 18:32 * 描述:https://github.com/leavesC */public class Strategies {    private String stringField;    private int intField;    private double doubleField;}
 public static void main(String[] args) {        Gson gson = new GsonBuilder()                .serializeNulls() //输出null                .create();        Strategies strategies = new Strategies(null, 24, 22.333);        System.out.println();        System.out.println(gson.toJson(strategies)); }

4.2、格式化输出Json

默认的序列化后的 Josn 字符串并不太直观,可以选择格式化输出

    public static void main(String[] args) {        Gson gson = new GsonBuilder()                .serializeNulls() //输出null                .setPrettyPrinting()//格式化输出                .create();        Strategies strategies = new Strategies(null, 24, 22.333);        System.out.println();        System.out.println(gson.toJson(strategies));    }

4.3、格式化时间

Gson 也可以对时间值进行格式化

/** * 作者:chenZY * 时间:2018/3/17 18:32 * 描述:https://github.com/leavesC */public class Strategies {    private Date date;    private Date date2;    public Strategies(Date date, Date date2) {        this.date = date;        this.date2 = date2;    }    @Override    public String toString() {        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS", Locale.CHINA);        return "Strategies{" +                "date=" + simpleDateFormat.format(date) +                ", date2=" + simpleDateFormat.format(date2) +                '}';    }}
public static void main(String[] args) {        Gson gson = new GsonBuilder()                .setPrettyPrinting()//格式化输出                .setDateFormat("yyyy-MM-dd HH:mm:ss:SSS")//格式化时间                .create();        Date date = new Date();        Strategies strategies = new Strategies(date, new Date(date.getTime() + 1000000));        System.out.println();        System.out.println(gson.toJson(strategies));        String json = "{\n" +                "  \"date\": \"2018-03-17 19:38:50:033\",\n" +                "  \"date2\": \"2018-03-17 19:55:30:033\"\n" +                "}";        System.out.println();        System.out.println(gson.fromJson(json, Strategies.class));    }

五、TypeAdapter

TypeAdapter 是一个泛型抽象类,用于接管某种类型的序列化和反序列化过程,包含两个抽象方法,分别用于自定义序列化和反序列化过程

public abstract void write(JsonWriter var1, T var2) throws IOException;public abstract T read(JsonReader var1) throws IOException;

下面看个简单的例子

/** * 作者:chenZY * 时间:2018/3/17 18:32 * 描述:https://github.com/leavesC */public class User {    private String name;    private int age;    private boolean sex;    public User() {    }    public User(String name, int age, boolean sex) {        this.name = name;        this.age = age;        this.sex = sex;    }    @Override    public String toString() {        return "User{" +                "name='" + name + '\'' +                ", age=" + age +                ", sex=" + sex +                '}';    }}

定义 TypeAdapter 的子类 UserTypeAdapter 来接管 User 类的序列化和反序列化过程
这里设定当 User 类序列化时 Json 中的Key值都是大写字母开头,反序列化时支持“name”和“Name”两种不同的 Json 风格

public class UserTypeAdapter extends TypeAdapter<User> {    @Override    public void write(JsonWriter jsonWriter, User user) throws IOException {        //流式序列化成对象开始        jsonWriter.beginObject();        //将Json的Key值都指定为大写字母开头        jsonWriter.name("Name").value(user.getName());        jsonWriter.name("Age").value(user.getAge());        jsonWriter.name("Sex").value(user.isSex());        //流式序列化结束        jsonWriter.endObject();    }    @Override    public User read(JsonReader jsonReader) throws IOException {        User user = new User();        //流式反序列化开始        jsonReader.beginObject();        while (jsonReader.hasNext()) {            switch (jsonReader.nextName()) {                //首字母大小写均合法                case "name":                case "Name":                    user.setName(jsonReader.nextString());                    break;                case "age":                    user.setAge(jsonReader.nextInt());                    break;                case "sex":                    user.setSex(jsonReader.nextBoolean());                    break;            }        }        //流式反序列化结束        jsonReader.endObject();        return user;    }}
    public static void main(String[] args) {        Gson gson = new GsonBuilder().registerTypeAdapter(User.class, new UserTypeAdapter()).create();        User user = new User("leavesC", 24, true);        System.out.println();        System.out.println(gson.toJson(user));        String json = "{\"Name\":\"leavesC\",\"age\":24,\"sex\":true}";        user = gson.fromJson(json, User.class);        System.out.println();        System.out.println(user);    }

可以看到 User 类按照预定义的策略来完成序列化和反序列化了

六、JsonSerializer 和 JsonDeserializer

TypeAdapter 将序列化和反序列操作都接管了过来,其实 Gson 还提供了只接管序列化过程的接口,即 JsonSerializer
看个例子

    public static void main(String[] args) {        Gson gson = new GsonBuilder().registerTypeAdapter(User.class, new JsonSerializer<User>() {            @Override            public JsonElement serialize(User user, Type type, JsonSerializationContext jsonSerializationContext) {                JsonObject jsonObject = new JsonObject();                jsonObject.addProperty("NameHi", user.getName());                jsonObject.addProperty("Sex", user.isSex());                jsonObject.addProperty("Age", user.getAge());                return jsonObject;            }        }).create();        User user = new User("leavesC", 24, true);        System.out.println();        System.out.println(gson.toJson(user));    }

相对应的,JsonDeserializer 接口提供了反序列化的接口

public static void main(String[] args) {        Gson gson = new GsonBuilder().registerTypeAdapter(User.class, new JsonDeserializer<User>() {            @Override            public User deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {                JsonObject jsonObject = jsonElement.getAsJsonObject();                String name = null;                //同时支持 userName 和 name 两种情况                if (jsonObject.has("userName")) {                    name = jsonObject.get("userName").getAsString();                } else if (jsonObject.has("name")) {                    name = jsonObject.get("name").getAsString();                }                int age = jsonObject.get("age").getAsInt();                boolean sex = jsonObject.get("sex").getAsBoolean();                return new User(name, age, sex);            }        }).create();        String json = "{\"userName\":\"leavesC\",\"sex\":true,\"age\":24}";        User user = gson.fromJson(json, User.class);        System.out.println();        System.out.println(user);        json = "{\"name\":\"leavesC\",\"sex\":true,\"age\":24}";        user = gson.fromJson(json, User.class);        System.out.println();        System.out.println(user);    }

这里有个比较麻烦的地方,那就是在使用 TypeAdapter 、JsonSerializer 和 JsonDeserializer 时,总需要调用 registerTypeAdapter 方法进行注册,那有没有更简单的注册方法呢?
有的,Gosn 还提供了另一个注解 @JsonAdapter 用于进行简单的声明

类似于这样,声明了 User 类的序列化或反序列化操作由 UserTypeAdapter 完成,注解的优先级高于registerTypeAdapter 方法

@JsonAdapter(UserTypeAdapter.class)public class User {}

七、TypeAdapterFactory

TypeAdapterFactory 是用于创建 TypeAdapter 的工厂类,通过参数 TypeToken 来查找确定对应的 TypeAdapter,如果没有就返回 null 并由 Gson 默认的处理方法来进行序列化和反序列化操作,否则就由用户预定义的 TypeAdapter 来进行处理

        Gson gson = new GsonBuilder().registerTypeAdapterFactory(new TypeAdapterFactory() {            @Override            public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {                //如果 Gson 需要与 User 类相关的 TypeAdapter ,则返回我们自己定义的 TypeAdapter 对象                if (typeToken.getType().getTypeName().equals(User.class.getTypeName())) {                    return (TypeAdapter<T>) new UserTypeAdapter();                }                //找不到则返回null                return null;            }        }).create();

Android系统(96)---Android 数据交换解析框架Gson使用详解相关推荐

  1. Android系统架构-[Android取经之路]

    摘要:本节主要来讲解Android的系统架构 阅读本文大约需要花费10分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Android的平台设计,欢迎关注我,谢谢! 欢 ...

  2. android 服务端技术,移动应用服务器端开发(基于JSP技术)-2017 Android系统构架 Android系统构架.docx...

    Android系统构架 PAGE 1 目 录 TOC \o "1-3" \h \z \u 一.Android系统构架 1 二.Linux内核层 2 三.系统运行库层 3 (一)系统 ...

  3. 【android系统】android系统升级流程分析(二)---update升级包分析

    接下来我们将通过几篇文章来分析update.zip包在具体Android系统升级的过程,来理解Android系统中Recovery模式服务的工作原理.今天让我先来分析下升级包update.zip. 一 ...

  4. Android自动化大讲堂34--终极自动化框架UIAutomator使用详解

    <深入理解Android自动化测试> 又双叒叕重印咯!!! 无以为报,只能改版得更漂亮一点来答谢各位的厚爱! 好了,废话少说,咱们开始吧! 终极自动化框架UIAutomator使用详解 注 ...

  5. 【android系统】android系统升级流程分析(一)---recovery模式中进行update包升级流程分析

    今天我们直接来看下android中具体的升级过程是如何的. 升级流程概述 升级的流程图: 升级流程分析 第一步:升级包获取 升级获取可以通过远程下载,也可直接拷贝到指定目录即可. 第二步:准备升级 然 ...

  6. android log抓取方法,Android系统之Android抓取各种log的方法

    Android系统之Android抓取各种log的方法 2018年11月25日 | 萬仟网移动技术 | 我要评论 android之android抓取各种log的方法 1.logcat (四类log b ...

  7. 银行应用系统间的数据交换

    在核心业务系统与外围系统之间批量交互数据是银行应用系统中最常见的任务之一,由于通常要受到多方面因素的制约,这是一个十分复杂而且耗费精力的工作.本文对其中的技术困难和应对策略进行了总结. 尽管目前银行正 ...

  8. layui数据表格解析html,layui框架table 数据表格的方法级渲染详解

    layui框架table 数据表格的方法级渲染详解 如下所示: //js 规范书写 var tst=table.render({ elem: '#test11' ,cols: [[ //标题栏 {ch ...

  9. android相册和拍照并裁剪图片大小,Android 拍照并对照片进行裁剪和压缩实例详解...

    Android 拍照并对照片进行裁剪和压缩实例详解 本文主要介绍 Android 调用摄像头拍照并对照片进行裁剪和压缩,文中给出了主要步骤和关键代码. 调用摄像头拍照,对拍摄照片进行裁剪,代码如下. ...

最新文章

  1. Nginx搭建静态网站
  2. 邬贺铨院士:十问边缘计算!
  3. Swift监听网络状态
  4. arcgis js api proxy java 版本配置
  5. SAP UI5 Tools 里配置文件 ui5-local.yaml 的配置要点
  6. SAP CRM WebClient UI的cancel按钮处理
  7. java buqi_Java 异常
  8. hdu4848 求到达每一个点总时间最短(sum[d[i]])。
  9. 10道经典MySQL面试题
  10. 城市管网 GIS 数据表的存储
  11. 避免无法预知和依赖于实现环境的行为
  12. qt mysql驱动不能用了,Qt使用msvc编译MySQL驱动_MySQL
  13. python鼠标点击脚本_python模拟鼠标点击脚本
  14. 搜狗浏览器收藏夹在什么位置?搜狗浏览器收藏夹路径在哪?
  15. 编写一个压缩软件(Java实现版本)
  16. mysql 取差值_mysql计算两条数据差值,求大神解答
  17. python添加win32com包,将ppt转换为图片
  18. echarts 饼状图 (数据为0或很小的扇形显示问题、扇形间隔)
  19. 从0开始学习 GitHub 系列之「04.向GitHub 提交代码」----转载自stormzhang 原创文章
  20. python中怎么创建一个词典_如何在Python中创建字典词典

热门文章

  1. S3C2440裸奔篇之MMU
  2. S3C6410 时钟初始化
  3. “手把手教你学linux驱动开发”OK6410系列之02---虚拟字符设备
  4. 基坑监测日报模板_深基坑又出事,广西工地 10m深 基坑坍塌,4名钢筋工被埋,3人遇难!...
  5. 【JAVA SE】第九章 接口
  6. Java笔记(二十) 注解
  7. 初识生成器与生成器表达式 Day12
  8. NLP(paper + code)
  9. (转载)关于ASCII和GB2312、GBK、GB18030、UNICODE
  10. 常见网站CSS样式重置