JSON数据解析,Gson简要使用笔记

2020-03-14 05:40 来源:未知

APP使用 XX加固助手 加固之后,在安卓 7.x.x 系统中会崩溃:错误信息为 java.lang.AssertionError: illegal type variable reference。

    JSON是一种轻量级的数据交换格式,它的全称为JavaScript Object Notation,轻量级的数据交换格式,主要用于跟服务器进行交换数据。我所做的项目来看,当下的服务器与客户端数据交换几乎都是用JSON了,所以作为移动开发者的我们务必要吃透JSON解析。

不怕跌倒,所以飞翔

经过比较,gson和其他现有java json类库最大的不同时gson需要序列化得实体类不需要使用annotation来标识需要序列化得字段,同时gson又可以通过使用annotation来灵活配置需要序列化的字段。

未加固之前并没有出现这个问题。

JSON的特点:

1、JSON比XML的数据传递的有效性高;
2、JSON完全独立于编程语言;
3、JSON的本质是具有特定格式的字符串;
4、易于人阅读和编写,同时也易于机器解析和生成。

组件化开发

下面是一个简单的例子:

方案一:

网络搜索发现,大部分都说是开启混淆之后没配置好导致的,所以,根据网络搜索结果先检查 module 的 build.gradle 和 proguard-rules.pro 中的配置。

  • 如果 buid.gradle 中开启了 minifyEnabled ,那么 proguard-rules.pro 中需要添加如下内容
-keepattributes EnclosingMethod

如果添加了上述内容之后依旧不生效,可添加下面的内容:

-keepattributes Exceptions,InnerClasses,Signature,Deprecated, SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
  • 如果该方案没能解决问题或没开启混淆,请参考方案二。

JSON数据格式(JSON对象、JSON数组):

1、JSON对象:{ }

结构:{key1:value1,key2:value2,key3:value3}
key的数据类型:字符串
value的数据类型:字符串、数值、null、JSON对象、JSON数组
例子:

{  " name " : " luoweichao ", " blogUrl " : " luoweichao.top "  } 

//以key/value键值对形式构建的,正确

{  " name " : " luoweichao ", " luoweichao.top "  }

//没有以key/value键值对形式构建的,错误
2、JSON数组:[ ]

结构:[value1,value2,value3]
value的数据类型:字符串、数值、null、JSON对象、JSON数组
例子:

[ " 1 " , " csdn " , {  " name " : " luoweichao ", " blogUrl " : " luoweichao.top "  }  ] 

//正确

[ " 1 " , " name " : " luoweichao "  ]  //错误

JSON解析方向:
1、将Java对象(包括集合)转换成JSON格式字符串;(服务端)
2、将JSON格式字符串转换成Java对象(包括集合)。(客户端)
3、JSON和Java之间的转换关系:JSON中的对象对应着Java中的对象;JSON中的数组对应这Java中的集合。
用Android原生技术解析JSON:特点:很麻烦,对于复杂的json数据解析很容易出错!(不推荐使用)
1、解析JSON对象的API:JsonObjectJSONObject(String json);将Json字符串解析成Json对象;XxxgetXxx(String name) ;根据name在json对象中得到相应的value。示例代码:(1)获取或创建JSON数据(为了方便,这里就直接创建了):
[java] view plain copy
String json = "{n" "t"id":2, "name":"金鱼", n" "t"price":12.3, n" "t"imagePath":"http://blog.csdn.net/qq_29269233/L05_Server.jpg"\n" "}n";
ShopInfo shopInfo = null;

(2)解析Json对象:
[java] view plain copy

try {JSONObject jsonObject = new JSONObject(json);// int id = jsonObject.getInt("id");int id1 = jsonObject.optInt("id");
String name = jsonObject.optString("name"); double price = jsonObject.optDouble("price"); String imagePath = jsonObject.optString("imagePath"); // 封装Java对象  shopInfo = new ShopInfo(id1, name, price, imagePath); } catch (JSONException e) { e.printStackTrace(); }

注意:这里记得要加try_catch异常处理。(3)创建JavaBean类,并显示解析后的数据:
[java] view plain copy
tv_native_last.setText(shopInfo.toString());
2、解析Json数组的API:JSONArrayJSONArray(String json);将json字符串解析成json数组;int length();得到json数组中元素的个数;XxxgetXxx(int s) ;根据下标得到json数组中对应的元素数据。示例代码:(1)获取或创建JSON数据:
[java] view plain copy
String json = "[n" " {n" " "id": 1,n" " "imagePath": "http://blog.csdn.net/qq_29269233/f1.jpg",\n" " "name": "金鱼1",n" " "price": 12.3n" " },n" " {n" " "id": 2,n" " "imagePath": "http://blog.csdn.net/qq_29269233/f2.jpg",\n" " "name": "金鱼2",n" " "price": 12.5n" " }n" "]";
(2)解析json数组:
[java] view plain copy

try {JSONArray jsonArray = new JSONArray(json);
for (int i = 0; i < jsonArray.length(); i  ) {  JSONObject jsonObject = jsonArray.getJSONObject(i);  if (jsonObject != null) { int id = jsonObject.optInt("id");  String name = jsonObject.optString("name");  double price = jsonObject.optDouble("price");  String imagePath = jsonObject.optString("imagePath");  // 封装Java对象 ShopInfo shopInfo = new ShopInfo(id, name, price, imagePath);  shops.add(shopInfo);  } } } catch (JSONException e) { e.printStackTrace();  }

(3)显示解析后的数据:
[java] view plain copy
tv_native_last.setText(shops.toString());
到此为止,这就是用原生的技术去解析json了,至于复杂特殊的json数据怎样去解析,也是大同小异了,一层一层解析就对了!
用Gson框架技术解析JSON:特点:解析没那么麻烦,代码量简洁,可以很方便地解析复杂的Json数据,而且谷歌官方也推荐使用。先放出jar包的下载地址:https://mvnrepository.com/artifact/com.google.code.gson/gson

图片 1

如过用Android Studio做开发的话,可以通过Gradle,直接添加依赖,不用下载jar包,很方便,如下:

图片 2

1、用Gson解析JSON对象:(1)将gson的jar包导入到项目libs目录下,或者直接通过Gradle添加依赖:
[java] view plain copy
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0'
(2)创建Gson对象:[java] view plain copy
Gson gson = new Gson();
(3)通过创建的Gson对象调用fromJson()方法,返回该json数据对象的Java对象;
[java] view plain copy
ShopInfo shopInfo = gson.fromJson(json, ShopInfo.class);
注意要记得创建对象的JavaBean类;要求json对象中的key的名称与Java对象的JavaBean类中的属性名要相同,否则解析不成功!示例代码如下:[java] view plain copy
// 1 获取或创建JSON数据String json = "{n" "t"id":2, "name":"金鱼", n" "t"price":12.3, n" "t"imagePath":"http://blog.csdn.net/qq_29269233/L05_Server.jpg"\n" "}n";
// 2 解析JSON数据 Gson gson = new Gson(); ShopInfo shopInfo = gson.fromJson(json, ShopInfo.class); // 3 展示数据 tv_gson_last.setText(shopInfo.toString());

2、用Gson解析JSON数组:(1)(2)与上面相同,要用Gson就要先添加依赖,然后创建Gson对象;(3)通过创建的Gson对象调用fromJson()方法,返回该json数据对应的Java集合。这里但强调一下:要记得创建对象的JavaBean类;要求json对象中的key的名称与Java对象的JavaBean类中的属性名要相同,否则解析不成功!
示例代码如下:
[java] view plain copy
// 1 获取或创建JSON数据String json = "[n" " {n" " "id": 1,n" " "imagePath": "http://blog.csdn.net/qq_29269233/f1.jpg",\n" " "name": "金鱼1",n" " "price": 12.3n" " },n" " {n" " "id": 2,n" " "imagePath": "http://blog.csdn.net/qq_29269233/f2.jpg",\n" " "name": "金鱼2",n" " "price": 12.5n" " }n" "]";
// 2 解析JSON数据 Gson gson = new Gson(); List<ShopInfo> shops = gson.fromJson(json, new TypeToken<List<ShopInfo>>() { }.getType()); // 3 展示数据 tv_gson_last.setText(shops.toString());

还是那句话,复杂特殊的都是大同小异,理解了方法就没问题了!3、Gson还可以将Java对象、Java对象的List 转换为json字符串{};有兴趣的就去研究一下哈。
用Fastjson框架技术解析JSON:特点:Fastjson是用Java语言编写的高性能功能完善的JSON库。它采用了一种“假定有序、快速匹配”的算法,把JSON Parse的性能提升到极致,是目前Java语言中最快的JSON库。Fastjson是阿里巴巴开源框架,已经开源到github上了,地址为:https://github.com/alibaba/fastjson

图片 3

图片 4

在github上,我还专门留意了这个,哈哈,gson和fastjson比起来,gson就是“乌龟”

图片 5

要使用Fastjson,也是想Gson一样,先导入jar包,或者在Gradle中添加依赖:
[java] view plain copy
compile 'com.alibaba:fastjson:1.1.55.android'
添加好依赖后就可以使用Fastjson了!1、用Fastjson解析JSON对象:利用Fastjson的JSON调用parseObject()方法,获取转换后的Java对象。注意要记得创建对象的JavaBean类;要求json对象中的key的名称与Java对象的JavaBean类中的属性名要相同,否则解析不成功!示例代码:
[java] view plain copy
// 1 获取或创建json数据String json = "{n" "t"id":2, "name":"金鱼", n" "t"price":12.3, n" "t"imagePath":"http://blog.csdn.net/qq_29269233/L05_Server.jpg"\n" "}n";
// 2 解析JSON数据 ShopInfo shopInfo = JSON.parseObject(json, ShopInfo.class); // 3 显示数据 tv_fastjson_last.setText(shopInfo.toString());

2.用Fastjson解析JSON数组:利用Fastjson的JSON调用parseArray()方法,获取转换后的Java集合。这里但强调一下:要记得创建对象的JavaBean类;要求json对象中的key的名称与Java对象的JavaBean类中的属性名要相同,否则解析不成功!示例代码:
[java] view plain copy
// 1 获取或创建json数据String json = "[n" " {n" " "id": 1,n" " "imagePath": "http://blog.csdn.net/qq_29269233/f1.jpg",\n" " "name": "金鱼1",n" " "price": 12.3n" " },n" " {n" " "id": 2,n" " "imagePath": "http://blog.csdn.net/qq_29269233/f2.jpg",\n" " "name": "金鱼2",n" " "price": 12.5n" " }n" "]";
// 2 解析JSON数据 List<ShopInfo> shopInfos = JSON.parseArray(json, ShopInfo.class); // 3 显示数据 tv_fastjson_last.setText(shopInfos.toString());

3、同样Fastjson也可以将Java对象、Java对象的List 转换为json字符串{};有兴趣的就去研究一下哈。到此为止,算是比较详细地介绍了json解析了。

前言:

最近为了统一项目中使用的框架,发现项目中用到了两种json解析框架,他们就是当今非常主流的json解析框架:google的Gson 和阿里巴巴的FastJson,为了废除其中一个所以来个性能和使用的大比拼。

FastJson简介:Fastjson是一个Java语言编写的JSON处理器,由阿里巴巴公司开发。

当前版本: fastjson-1.2.14.jar

下载地址http://repo1.maven.org/maven2/com/alibaba/fastjson/1.2.14/

对象转化成json:

/**
 * 对象转化为json fastjson 使用方式
 *
 * @return
 */
public static String objectToJsonForFastJson(Object object) {
    if (object == null) {
        return "";
    }
    try {
        return JSON.toJSONString(object);
    } catch (JSONException e) {
    } catch (Exception e) {
    }
    return "";
}

json转化成对象:

/**
* json转化为对象 fastjson 使用方式
*
* @return
*/
public static <T> T jsonToObjectForFastJson(String jsonData, Class<T> clazz) {
if (TextUtils.isEmpty(jsonData)) {
return null;
}
try {
return parseObject(jsonData, clazz);
} catch (Exception e) {
}
return null;
}
json转化成List:

/**
*json转化为List fastjson 使用方式
*/
public static List jsonToListForFastJson(String jsonData) {
if (TextUtils.isEmpty(jsonData)) {
return null;
}
List arrayList = null;
try {
arrayList = parseObject(jsonData,new TypeReference<ArrayList>(){});
} catch (Exception e) {
}
return arrayList;

}

json转化这Map:

/**
 *json转化为Map  fastjson 使用方式
 */
public static Map jsonToMapForFastJson(String jsonData){
    if (TextUtils.isEmpty(jsonData)) {
        return null;
    }
    Map map = null;
    try{
        map =  parseObject(jsonData,new TypeReference<Map>(){});
    }catch (Exception e){
        e.printStackTrace();
    }
    return map;
}

Gson 简介:Gson由谷歌研发,可以把Java对象转换成JSON,也可以把JSON字符串转换成一个相等的Java对象。Gson支持任意复杂Java对象包括没有源代码的对象。

当前版本2.40

使用方式 build.gradle 中配置 compile 'com.google.code.gson:gson:2.4'

对象转化json:

/**
* 对象转化为json对象 Gson 使用方式
*
* @return
*/
public static String objectToJsonForGson(Object object) {
if (object == null) {
return "";
}
Gson gson;
try {
gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
return gson.toJson(object);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
json转化成对象:

/**
* json转化为对象 Gson 使用方式
*
* @return
*/

public static <T> T jsonToObjectForGson(String jsonData, Class<T> clazz) {
    if (TextUtils.isEmpty(jsonData)) {
        return null;
    }
    T finalResult = null;
    try {
        Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
        finalResult = gson.fromJson(jsonData, clazz);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return finalResult;
}

json转化成List:

/**
*json转化为集合 Gson 使用方式
*/
public static List jsonToListForForGson(String jsonData) {
if (TextUtils.isEmpty(jsonData)) {
return null;
}
List list = null;
try {
Type listType = new TypeToken<ArrayList>() {
}.getType();
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
list = gson.fromJson(jsonData, listType);
} catch (Exception e) {
}
return list;
}
json转化为Map:

/**
*json转化为Map fastjson 使用方式
*/
public static Map jsonToMapForForGson(String jsonData){
if (TextUtils.isEmpty(jsonData)) {
return null;
}
Map map = null;
try {
Type listType = new TypeToken<Map>() {
}.getType();
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
map = gson.fromJson(jsonData, listType);
} catch (Exception e) {
}
return map;
}
测试性能程序:

第一步:首先创建一个实体对象Person

public class Person {

private String name;//姓名
private int age;//年龄

public int getAge() {
    return age;
}

public void setAge(int age) {
    this.age = age;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

}
第二部:创建一个测试集合:

  List<Person> personList=new ArrayList<>();
    int testMaxCount=1000;//测试的最大数据条数 
    //添加测试数据
    for(int i=0;i<testMaxCount;i  ){
        Person person =new Person();
        person.setAge(i);
        person.setName(String.valueOf(i));
        personList.add(person);
    }

分别执行两者的转化和解析代码:

    //FastJson生成json数据
    long start=System.currentTimeMillis();
    String jsonData=JsonUtils.objectToJsonForFastJson(personList);
    long end=System.currentTimeMillis();
    Log.e("MainActivity","FastJson生成json数据 cost time---->" (end-start));


    //FastJson解析json数据
    start=System.currentTimeMillis();
    List<Person> tempPersons=JsonUtils.jsonToListForFastJson(jsonData);
    end=System.currentTimeMillis();
    Log.e("MainActivity","FastJson解析json数据 cost time---->" (end-start));

    //Gson生成json数据
     start=System.currentTimeMillis();
     jsonData=JsonUtils.objectToJsonForGson(personList);
     end=System.currentTimeMillis();
     Log.e("MainActivity","Gson生成json数据 cost time---->" (end-start));

    //Gson解析json数据
    start=System.currentTimeMillis();
    List<Person> tempPersons1=JsonUtils.jsonToListForForGson(jsonData);
    end=System.currentTimeMillis();
    Log.e("MainActivity","Gson解析json数据 cost time---->" (end-start));

重点看执行结果:单位毫秒(执行时间)

两者转换性能对比:1000条 10000条 100000条 200000条

fastJson : 45 289 4010 8396

Gson : 60 724 4071 8803

两者解析性能对比:1000条 10000条 100000条 200000条

fastJson : 55 552 3826 8638

Gson : 45 465 5942 9668

总结:在数据量比较小的情况下,两者性能相差无几,在数据量比较大的情况下FastJson还是有优势的。

插曲:为了项目省事,本人把FastJson给删除了,结果项目中遗留了一些代码编写不规范的情况,比如userId 写成了useid 但是json数据中返回的是userId,之前用FastJson一直正常这才发现原来FastJson对实体属性是忽略大小写的,真是一个神奇的东西。

参考资源

  1. Android组件化方案

图片 6

、方案二

如果方案一中该配置的都处理了,但是在使用第三方加固时报错了,那说明第三方加固中配置了混淆参数,所以,此时我们只能修改我们代码中的内容。

通过LOG或者BUGGLY查看具体的错误位置。如下图:

图片 7输入图片说明

在上图中,我们可以定位到问题所在,是我们内部AFragment中的第159行和另一个BFragment中的132行。最终问题是指向 AFragment中的159行,那么,这里干了啥呢?

//GsonUtil.stringToList是我们自己封装的一个工具类List<String> settingList = GsonUtil.stringToList(userSetting);

stringToList的具体逻辑为:

 public static <T> ArrayList<T> stringToList(String gsonString) { ArrayList<T> list = null; //gson即Gson对象 if (gson != null) { list = gson.fromJson(gsonString, new TypeToken<ArrayList<T>>() { }.getType; } return list; }

然后重复测试发现如下规律:

  • 在没有使用 xxx加固助手之前,正常打包的APP在这地方并不会报错,可以正常运行;
  • 除 7.x.x 之外的系统,加固之后也不会报错;

根据上述规律猜测大致的问题原因如下:

  • 加固助手中对代码进行了二次混淆
  • 二次混淆之后,7.x.x系统中在调用 fromJson的转换时,虽然调用了获取类型的 TypeToken<ArrayList<T>>().getType(),但这个getType()并没有生效——fromJson转换时会进行类型擦除,getType()不生效就表示没能获取到类型。然后,就挂掉了。。。
  • 为啥只有7.x.x 的系统中 getType()不生效呢?这个真的没想出来为啥。。。。

在 B 中我们分析了问题原因应该是没有获取到数据类型,那么我们就需要想法子让 getType()拿到具体的数据类型。

为什么要组件化开发

图片 8

A:首先我们做了如下尝试:
List<String> settingList = new ArrayList<>();list = new Gson().fromJson(userSetting, new TypeToken<ArrayList<String>>() { }.getType;

上述代码中,在构造 TypeToken 对象时,我们指定了 ArrayList 接收参数的类型为 String,而不再是T。重新加固并安装运行 —— 不再报错!!

解决问题

  • 实际业务变化非常快,但是单一工程的业务模块耦合度太高,牵一发而动全身;
  • 对工程所做的任何修改都必须要编译整个工程;
  • 功能测试和系统测试每次都要进行;
  • 团队协同开发存在较多的冲突.不得不花费更多的时间去沟通和协调,并且在开发过程中,任何一位成员没办法专注于自己的功能点,影响开发效率;
  • 不能灵活的对业务模块进行配置和组装;

public class Person {

B: 然后又做了如下尝试:
/** * 转成list */public static <T> ArrayList<T> stringToList(String gsonString, Class<T> cls) { ArrayList<T> list = new ArrayList<>(); if (gson != null) { JsonArray array = new JsonParser().parse(gsonString).getAsJsonArray(); for (final JsonElement elem : array) { list.add(gson.fromJson(elem, cls)); } } return list;}

在上述代码中,我们不再直接转换为List,而是使用GSON解析每一个对象,并且传入 .class —— 有了 .class 也就可以确定类型。重新加固并安装运行——不再报错!

对于为啥加固之后只有7.x.x 的系统报错,这个一直没有想明白,如果你知道,请务必留言告知,谢谢!

本文到此结束,谢谢观看!如有不足,敬请指正!

CnPeng 微信公众号上线了!!

我们不仅可以聊软件,还可以聊硬件;我们不仅可以聊技术,还可以聊人生。这,是一个不羁的公众号。欢迎扫描下方二维码调戏!

图片 9

好处

  • 加快业务迭代速度,各个业务模块组件更加独立,不再出现业务耦合情况;
  • 稳定的公共模块采用依赖库方式,提供给各个业务线使用,减少重复开发和维护工作量;
  • 迭代频繁的业务模块采用组件方式,各业务研发可以互不干扰、提升协作效率,并控制产品质量;
  • 为新业务随时集成提供了基础,所有业务可上可下,灵活多变;
  • 降低团队成员熟悉项目的成本,降低项目的维护难度;
  • 加快编译速度,提高开发效率;
  • 控制代码权限,将代码的权限细分到更小的粒度;

private String name;
private int age;

具体实现方案

/**
* @return the name
*/
public String getName() {
return name;
}

1.组件模式和集成模式的转换

/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}

android studio 中的Module主要又两种属性

  • application属性,可以单独运行的Android程序,也就是我们的APP

     //这个是在build.gradle中进行设置的(就是最顶上那一行)
     apply plugin: 'com.android.application'
    
  • library属性,不可以单独运行,一般是Android程序依赖的库文件

    //这个是在build.gradle中进行设置的(就是最顶上那一行)
    apply plugin: ‘com.android.library’
    

/**
* @return the age
*/
public int getAge() {
return age;
}

组件化和集成模式的转换

说到这里我不想去讲解gradle的语法,因为我也不会,但是可以告诉你怎么去弄!!!

这里是引用张华洋的说明:博客地址

Module的属性是在每个组件的 build.gradle 文件中配置的,当我们在组件模式开发时,业务组件应处于application属性,这时的业务组件就是一个 Android App,可以独立开发和调试;而当我们转换到集成模式开发时,业务组件应该处于 library 属性,这样才能被我们的“app壳工程”所依赖,组成一个具有完整功能的APP;
但是我们如何让组件在这两种模式之间自动转换呢?总不能每次需要转换模式的时候去每个业务组件的 Gralde 文件中去手动把 Application 改成 library 吧?如果我们的项目只有两三个组件那么这个办法肯定是可行的,手动去改一遍也用不了多久,但是在大型项目中我们可能会有十几个业务组件,再去手动改一遍必定费时费力,这时候就需要程序员发挥下懒的本质了。
试想,我们经常在写代码的时候定义静态常量,那么定义静态常量的目的什么呢?当一个常量需要被好几处代码引用的时候,把这个常量定义为静态常量的好处是当这个常量的值需要改变时我们只需要改变静态常量的值,其他引用了这个静态常量的地方都会被改变,做到了一次改变,到处生效;根据这个思想,那么我们就可以在我们的代码中的某处定义一个决定业务组件属性的常量,然后让所有业务组件的build.gradle都引用这个常量,这样当我们改变了常量值的时候,所有引用了这个常量值的业务组件就会根据值的变化改变自己的属性;可是问题来了?静态常量是用Java代码定义的,而改变组件属性是需要在Gradle中定义的,Gradle能做到吗?
Gradle自动构建工具有一个重要属性,可以帮助我们完成这个事情。每当我们用AndroidStudio创建一个Android项目后,就会在项目的根目录中生成一个文件 gradle.properties,我们将使用这个文件的一个重要属性:在Android项目中的任何一个build.gradle文件中都可以把gradle.properties中的常量读取出来;那么我们在上面提到解决办法就有了实际行动的方法,首先我们在gradle.properties中定义一个常量值 isModule(是否是组件开发模式,true为是,false为否):

/**
* @param age the age to set
*/
public void setAge(int age) {
this.age = age;
}

在gradle.properties中添加是否组件化的判断

PS:首先gradle.properties这个文件有一个重要的功能:在Android项目中的任何一个build.gradle文件中都可以把gradle.properties中的常量读取出来(但是读取出来的时候是String格式的字符串,这一点要切记)

在gradle.properties中添加

# 是否组件化的标识,注意啊这里要用"#"号注释
isModule = false 

然后在相应的Module中的build.gradle去添加相应的逻辑

//这里说明一下就是如果是组件化的
if (isModule.toBoolean()) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}

这样写完了之后就会在每次改变*isModule赋值的化就可以更改相应的模块是否能单独运行了(为了保证单独组件的单独运行,会创建一个公用的Module,存放网络请求或者图片处理等一些公共的资源,从而确保module的单独运行)

@Override
public String toString()
{
return name ":" age;
}
}

组件之间AndroidManifest合并问题

这里是引用张华洋的说明:博客地址

但是大家应该注意到这个问题是在组件开发模式和集成开发模式之间转换引起的问题,而在上一节中我们已经解决了组件模式和集成模式转换的问题,另外大家应该都经历过将 Android 项目从 Eclipse 切换到 AndroidStudio 的过程,由于 Android 项目在 Eclipse 和 AndroidStudio开发时 AndroidManifest.xml 文件的位置是不一样的,我们需要在build.gradle 中指定下 AndroidManifest.xml 的位置,AndroidStudio 才能读取到 AndroidManifest.xml,这样解决办法也就有了,我们可以为组件开发模式下的业务组件再创建一个 AndroidManifest.xml,然后根据isModule指定AndroidManifest.xml的文件路径,让业务组件在集成模式和组件模式下使用不同的AndroidManifest.xml,这样表单冲突的问题就可以规避了。

图片 10

创建一个新的AndroidManifest.xml

具体的解决方案就是在相应的Module中在根路径添加一个Module文件夹,直接创建一份AndroidManifest.xml,这里面的这个文件,直接像你平时写项目一样去写就可以了

实体很简单,两个字段,当然实体中的字段也可以是List或者Set类型的。

修改相应的build.gradle
在android标签内创建
 sourceSets {
        main {
            if (isModule.toBoolean()) {/*是组件化*/
                manifest.srcFile 'src/main/AndroidManifest.xml'
                java {/*集成开发模式下排除debug文件加中的所有java文件*/
                    exclude 'debug/**'//这个相应的debug文件是在java文件目录下的
                }
            } else {
                manifest.srcFile 'src/main/module/AndroidManifest.xml'
            }
        }
    }

图片 11生成Json字符串

全局Context的获取及组件数据初始化

其实我理解的全局Context的理解就是->先创建一个所有module都引用的一个module(common这个module是每个module都会引用的一个module,这里要处理重复的问题,后面补充),这个module就存放一些都能用到的东西,然后引入到module或者主项目中,这样所有的module都会包含一些公共的内容:如请求网络,图片处理等一些相应的内容,这样既保证了每个module的单独运行,也保证了项目的耦合程度

这里有一个存在一个技巧,在前面没有去理解,就是在组件之间AndroidManifest合并问题处有这样一段代码

 java {/*集成开发模式下排除debug文件加中的所有java文件*/
                    exclude 'debug/**'
                }

这段代码的主要问题就是解决全局Context的问题,为什么呢???

我们想一下场景啊!当你某一个模块单独运行的时候,存在登陆获取token的问题,但是你要是单独运行的时候呢,可能这个模块没有token你怎么办呢?其实解决办法就是创建一个debug文件夹,这里呢可以自己创建一个相应的Application去请求登陆的接口这样你的module单独运行的时候就会有token了具体值
(这里我看张华洋的博客时我觉的处理挺好的,他在公共的类中去创建了一个BaseApplication所有module中的Application(在debug文件夹下创建的,但是要在清单文件中去配置啊!!!)都去继承这个Application,这样既解决了没有Application的情况,又解决了集成打包时候多次创建Application的情况,觉得比较不错所以借鉴一下)
上面那行代码会在集成开发模式的情况下把debug文件夹下的内容删除,这里就成功的解决了单独运行的token问题,也解决了集成打包的时候会出现多个Application的问题

上面的代码重点是Gson对象,它提供了toJason()方法将对象转换成Json字符串,上面代码的str对象值为:

library依赖问题

解决library的重复引用问题又两种方式:

  • 根据组件名称排除
  • 根据包名排除
    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        compile("com.jude:easyrecyclerview:$rootProject.easyRecyclerVersion") {
            exclude module: 'support-v4'//根据组件名排除
            exclude group: 'android.support.v4'//根据包名排除
        }
    }

这里说明一点:基础的控件一般都在common中去引用,然后住项目和其他的项目都导入common就可以了,但是这里应该存在一个问题就是Common存在导入多次的问题
其实在构建APP的过程中Gradle会自动将重复的arr包排除,APP中也就不会存在相同的代码了;

[{"name":"name0","age":0},{"name":"name1","age":5},{"name":"name2","age":10},{"name":"name3","age":15},{"name":"name4","age":20},{"name":"name5","age":25},{"name":"name6","age":30},{"name":"name7","age":35},{"name":"name8","age":40},{"name":"name9","age":45}]

组件之间的调用和通信

这里是引用张华洋的说明:博客地址

在组件化开发的时候,组件之间是没有依赖关系,我们不能在使用显示调用来跳转页面了,因为我们组件化的目的之一就是解决模块间的强依赖问题,
假如现在要从A业务组件跳转到业务B组件,并且要携带参数跳转,这时候怎么办呢?
而且组件这么多怎么管理也是个问题,这时候就需要引入“路由”的概念了,由本文开始的组件化模型下的业务关系图可知路由就是起到一个转发的作用。
这里我将介绍开源库的“ActivityRouter” ,有兴趣的同学情直接去ActivityRouter的Github主页学习:ActivityRouter,ActivityRouter支持给Activity定义 URL,
这样就可以通过 URL 跳转到Activity,并且支持从浏览器以及 APP 中跳入我们的Activity,而且还支持通过 url 调用方法。
下面将介绍如何将ActivityRouter集成到组件化项目中以实现组件之间的调用;

这里涉及到路由的问题后续在进行补充

很标准的json数据,很简单吧,呵呵。

组件之间资源名称冲突的问题

这里是引用张华洋的说明:博客地址

因为我们拆分出了很多业务组件和功能组件,在把这些组件合并到“app壳工程”时候就有可能会出现资源名冲突问题,
例如A组件和B组件都有一张叫做“ic_back”的图标,这时候在集成模式下打包APP就会编译出错,解决这个问题最简单的办法就是在项目中约定资源文件命名规约,
比如强制使每个资源文件的名称以组件名开始,这个可以根据实际情况和开发人员制定规则。当然了万能的Gradle构建工具也提供了解决方法,
通过在在组件的build.gradle中添加如下的代码:

```
//设置了resourcePrefix值后,所有的资源名必须以指定的字符串做前缀,否则会报错。
//但是resourcePrefix这个值只能限定xml里面的资源,并不能限定图片资源,所有图片资源仍然需要手动去修改资源名。
resourcePrefix "girls_"
```

但是设置了这个属性后有个问题,所有的资源名必须以指定的字符串做前缀,否则会报错,
而且resourcePrefix这个值只能限定xml里面的资源,并不能限定图片资源,所有图片资源仍然需要手动去修改资源名;
所以我并不推荐使用这种方法来解决资源名冲突。

下面来看看gson的反序列化,Gson提供了fromJson()方法来实现从Json相关对象到java实体的方法。

2.组件化项目的工程类型

在组件化工程模型中主要有:app壳工程、业务组件和功能组件3种类型,而业务组件中的Main组件和功能组件中的Common组件比较特殊,下面将分别介绍。

在日常应用中,我们一般都会碰到两种情况,转成单一实体对象和转换成对象列表或者其他结构。

1.app壳工程

app壳工程相当于一个空壳的项目,没有任何业务代码,也不能又Activity,但是它又必须单独划分一个组件,而且不能融合其他组件中;
因为它又几点重要的功能:

  • app壳工程中声明了我们Android应用的Application 但是这个Application必须是继承Common组件中的BaseApplication(如果无需事先自己的Application可以直接在表单生命BaseApplication),
    因为只有这样,在打包应用后才能让BaseApplication中的Context生效,当然你也可以在这个Application中初始化我们工程中使用的库文件,还可以在这里面解决Android引用方法数超过65535的限制,
    对于崩溃事件的捕获和发送也可以在这里面声明

  • app壳工程的AndroidManifest.xml是我们Android应用的根表单 应用的名,图标依稀是否支持备份等等属性都是在这份表单中配置的,
    其他组件中的表单最终在集成开发模式下都被合并到这份AndroidManifest.xml中

  • app壳工程的build.gradle是比较特殊的 app壳不管是在集成开发模式还是组件开发模式,它的属性始终都是:
    com.android.application,因为最终其它的组件都要被app壳工程所依赖,被打包进app壳工程中,这一点从组件化工程模型图中就能体现出来,
    所以app壳工程是不需要单独调试单独开发的.另外Android应用的打包签名,以及build.gradle和defaultConfig都需要在这里面配置,
    而它的dependencies则需要根据isModule的值分别依赖不同的组件,在组件开发模式下app壳工程只需要依赖Common组件,
    或者为了防止报错也可以根据实际情况依赖其他功能组件,而在集成模式下app壳工程必须依赖所有在应用Application中声明的业务组件,并且不需要再依赖任何功能组件。

这里是引用张华洋的说明:博客地址

一份工程的build.gradle文件

apply plugin: 'com.android.application'

static def buildTime() {
    return new Date().format("yyyyMMdd");
}

android {
    signingConfigs {
        release {
            keyAlias 'guiying712'
            keyPassword 'guiying712'
            storeFile file('/mykey.jks')
            storePassword 'guiying712'
        }
    }

    compileSdkVersion rootProject.ext.compileSdkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion
    defaultConfig {
        applicationId "com.guiying.androidmodulepattern"
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode rootProject.ext.versionCode
        versionName rootProject.ext.versionName
        multiDexEnabled false
        //打包时间
        resValue "string", "build_time", buildTime()
    }

    buildTypes {
        release {
            //更改AndroidManifest.xml中预先定义好占位符信息
            //manifestPlaceholders = [app_icon: "@drawable/icon"]
            // 不显示Log
            buildConfigField "boolean", "LEO_DEBUG", "false"
            //是否zip对齐
            zipAlignEnabled true
            // 缩减resource文件
            shrinkResources true
            //Proguard
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            //签名
            signingConfig signingConfigs.release
        }

        debug {
            //给applicationId添加后缀“.debug”
            applicationIdSuffix ".debug"
            //manifestPlaceholders = [app_icon: "@drawable/launch_beta"]
            buildConfigField "boolean", "LOG_DEBUG", "true"
            zipAlignEnabled false
            shrinkResources false
            minifyEnabled false
            debuggable true
        }
    }


}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    annotationProcessor "com.github.mzule.activityrouter:compiler:$rootProject.annotationProcessor"
    if (isModule.toBoolean()) {
        compile project(':lib_common')
    } else {
        compile project(':module_main')
        compile project(':module_girls')
        compile project(':module_news')
    }
}

先来看第一种:

2.功能组件和Common组件

功能组件是为了支撑业务组件的某些功能而独立划分出来的组件,功能组件和第三方库是一样的,
拥有如下特征:

比如json字符串为:[{"name":"name0","age":0}]

功能组件
  • 功能组件的AndroidManifest.xml是一张空表,这张表只有功能组件的包名;

  • 功能组件不管是在集成开发还是组件开发模式下属性始终是:com.android.library,
    所以功能组件不需要读取gradle.properties 中的isModule值的;另外功能组件的build.gradle也无需设置buildType是,
    只需要dependencies这个共鞥组件需要的jar包和开源库.

这里是引用张华洋的说明:博客地址

一份 普通 的功能组件的 build.gradle文件:

apply plugin: 'com.android.library'

android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion

    defaultConfig {
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode rootProject.ext.versionCode
        versionName rootProject.ext.versionName
    }

}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
}

代码:

Common组件

Common组件除了有功能组件的普遍属性外,还具有其他功能:

  • Common组件的 AndroidManifest.xml 不是一张空表,这张表中声明了我们 Android应用用到的所有使用权限 uses-permission 和 uses-feature,放到这里是因为在组件开发模式下,所有业务组件就无需在自己的 AndroidManifest.xm 声明自己要用到的权限了。
  • Common组件的 build.gradle 需要统一依赖业务组件中用到的 第三方依赖库和jar包,例如我们用到的ActivityRouter、Okhttp等等。
  • Common组件中封装了Android应用的 Base类和网络请求工具、图片加载工具等等,公用的 widget控件也应该放在Common 组件中;业务组件中都用到的数据也应放于Common组件中,例如保存到 SharedPreferences 和 DataBase 中的登陆数据;
  • Common组件的资源文件中需要放置项目公用的 Drawable、layout、sting、dimen、color和style 等等,另外项目中的 Activity 主题必须定义在 Common中,方便和 BaseActivity 配合保持整个Android应用的界面风格统一。

这里是引用张华洋的说明:博客地址

一份 Common 的功能组件的 build.gradle文件:

apply plugin: 'com.android.library'

android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion

    defaultConfig {
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode rootProject.ext.versionCode
        versionName rootProject.ext.versionName
    }

}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    //Android Support
    compile "com.android.support:appcompat-v7:$rootProject.supportLibraryVersion"
    compile "com.android.support:design:$rootProject.supportLibraryVersion"
    compile "com.android.support:percent:$rootProject.supportLibraryVersion"
    //网络请求相关
    compile "com.squareup.retrofit2:retrofit:$rootProject.retrofitVersion"
    compile "com.squareup.retrofit2:retrofit-mock:$rootProject.retrofitVersion"
    compile "com.github.franmontiel:PersistentCookieJar:$rootProject.cookieVersion"
    //稳定的
    compile "com.github.bumptech.glide:glide:$rootProject.glideVersion"
    compile "com.orhanobut:logger:$rootProject.loggerVersion"
    compile "org.greenrobot:eventbus:$rootProject.eventbusVersion"
    compile "com.google.code.gson:gson:$rootProject.gsonVersion"
    compile "com.github.chrisbanes:PhotoView:$rootProject.photoViewVersion"

    compile "com.jude:easyrecyclerview:$rootProject.easyRecyclerVersion"
    compile "com.github.GrenderG:Toasty:$rootProject.toastyVersion"

    //router
    compile "com.github.mzule.activityrouter:activityrouter:$rootProject.routerVersion"
}

Person person = gson.fromJson(str, Person.class);

3.业务组件和Main组件

提供两个参数,分别是json字符串以及需要转换对象的类型。

业务组件

业务组件就是根据业务逻辑的不同拆分出来的组件,业务组件的特征如下:

  • 业务组件中要有两张AndroidManifest.xml,分别对应组件开发模式和集成开发模式,这两张表的区别请查看 组件之间AndroidManifest合并问题 小节。
  • 业务组件在集成模式下是不能有自己的Application的,但在组件开发模式下又必须实现自己的Application并且要继承自Common组件的BaseApplication,并且这个Application不能被业务组件中的代码引用,因为它的功能就是为了使业务组件从BaseApplication中获取的全局Context生效,还有初始化数据之用。
  • 业务组件有debug文件夹,这个文件夹在集成模式下会从业务组件的代码中排除掉,所以debug文件夹中的类不能被业务组件强引用,例如组件模式下的 Application 就是置于这个文件夹中,还有组件模式下开发给目标 Activity 传递参数的用的 launch Activity 也应该置于 debug 文件夹中;
  • 业务组件必须在自己的 Java文件夹中创建业务组件声明类,以使 app壳工程 中的 应用Application能够引用,实现组件跳转,具体请查看 组件之间调用和通信 小节;
  • 业务组件必须在自己的 build.gradle 中根据 isModule 值的不同改变自己的属性,在组件模式下是:com.android.application,而在集成模式下com.android.library;同时还需要在build.gradle配置资源文件,如 指定不同开发模式下的AndroidManifest.xml文件路径,排除debug文件夹等;业务组件还必须在dependencies中依赖Common组件,并且引入ActivityRouter的注解处理器annotationProcessor,以及依赖其他用到的功能组件。

这里是引用张华洋的说明:博客地址

一份普通业务组件的 build.gradle文件:

if (isModule.toBoolean()) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}

android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion

    defaultConfig {
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode rootProject.ext.versionCode
        versionName rootProject.ext.versionName
    }

    sourceSets {
        main {
            if (isModule.toBoolean()) {
                manifest.srcFile 'src/main/module/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/AndroidManifest.xml'
                //集成开发模式下排除debug文件夹中的所有Java文件
                java {
                    exclude 'debug/**'
                }
            }
        }
    }

    //设置了resourcePrefix值后,所有的资源名必须以指定的字符串做前缀,否则会报错。
    //但是resourcePrefix这个值只能限定xml里面的资源,并不能限定图片资源,所有图片资源仍然需要手动去修改资源名。
    //resourcePrefix "girls_"


}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    annotationProcessor "com.github.mzule.activityrouter:compiler:$rootProject.annotationProcessor"
    compile project(':lib_common')
}

第二种,转换成列表类型:

Main组件

Main组件集成模式下的AndroidManifest.xml是跟其他业务组件不一样的,Main组件的表单中声明了我们整个Android应用的launch Activity,这就是Main组件的独特之处;所以我建议SplashActivity、登陆Activity以及主界面都应属于Main组件,也就是说Android应用启动后要调用的页面应置于Main组件。

这里是引用张华洋的说明:博客地址

一份Main业务组件的 build.gradle文件:

        <activity
            android:name=".splash.SplashActivity"
            android:launchMode="singleTop"
            android:screenOrientation="portrait"
            android:theme="@style/SplashTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

代码:

3.组件化项目的混淆方案

组件化项目的Java代码混淆方案采用在集成模式下集中在app壳工程中混淆,各个业务组件不配置混淆文件。 集成开发模式下在app壳工程中build.gradle文件的release构建类型中开启混淆属性,其他buildTypes配置方案跟普通项目保持一致,Java混淆配置文件也放置在app壳工程中,各个业务组件的混淆配置规则都应该在app壳工程中的混淆配置文件中添加和修改。
之所以不采用在每个业务组件中开启混淆的方案,是因为 组件在集成模式下都被 Gradle 构建成了 release 类型的arr包,一旦业务组件的代码被混淆,而这时候代码中又出现了bug,将很难根据日志找出导致bug的原因;另外每个业务组件中都保留一份混淆配置文件非常不便于修改和管理,这也是不推荐在业务组件的 build.gradle 文件中配置 buildTypes (构建类型)的原因。

图片 12

4.工程的build.gradle和gradle.properties文件

List<Person> ps = gson.fromJson(str, new TypeToken<List<Person>>(){}.getType());
for(int i = 0; i < ps.size() ; i )
{
Person p = ps.get(i);
System.out.println(p.toString());
}

组件化工程的build.gradle文件

在组件化项目中因为每个组件的 build.gradle 都需要配置 compileSdkVersion、buildToolsVersion和defaultConfig 等的版本号,而且每个组件都需要用到 annotationProcessor,为了能够使组件化项目中的所有组件的 build.gradle 中的这些配置都能保持统一,并且也是为了方便修改版本号,我们统一在Android工程根目录下的build.gradle中定义这些版本号,当然为了方便管理Common组件中的第三方开源库的版本号,最好也在这里定义这些开源库的版本号,然后在各个组件的build.gradle中引用Android工程根目录下的build.gradle定义的版本号,组件化工程的 build.gradle 文件代码如下:

这里是引用张华洋的说明:博客地址

buildscript {
    repositories {
        jcenter()
        mavenCentral()
    }

    dependencies {
        //classpath "com.android.tools.build:gradle:$localGradlePluginVersion"
        //$localGradlePluginVersion是gradle.properties中的数据
        classpath "com.android.tools.build:gradle:$localGradlePluginVersion"
    }
}

allprojects {
    repositories {
        jcenter()
        mavenCentral()
        //Add the JitPack repository
        maven { url "https://jitpack.io" }
        //支持arr包
        flatDir {
            dirs 'libs'
        }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

// Define versions in a single place
//时间:2017.2.13;每次修改版本号都要添加修改时间
ext {
    // Sdk and tools
    //localBuildToolsVersion是gradle.properties中的数据
    buildToolsVersion = localBuildToolsVersion
    compileSdkVersion = 25
    minSdkVersion = 16
    targetSdkVersion = 25
    versionCode = 1
    versionName = "1.0"
    javaVersion = JavaVersion.VERSION_1_8

    // App dependencies version
    supportLibraryVersion = "25.3.1"
    retrofitVersion = "2.1.0"
    glideVersion = "3.7.0"
    loggerVersion = "1.15"
    eventbusVersion = "3.0.0"
    gsonVersion = "2.8.0"
    photoViewVersion = "2.0.0"

    //需检查升级版本
    annotationProcessor = "1.1.7"
    routerVersion = "1.2.2"
    easyRecyclerVersion = "4.4.0"
    cookieVersion = "v1.0.1"
    toastyVersion = "1.1.3"
}

图片 13

组件化工程的gradle.properties文件

在组件化实施流程中我们了解到gradle.properties有两个属性对我们非常有用:

  • 在Android项目中的任何一个build.gradle文件中都可以把gradle.properties中的常量读取出来,不管这个build.gradle是组件的还是整个项目工程的build.gradle;
  • gradle.properties中的数据类型都是String类型,使用其他数据类型需要自行转换;

利用gradle.properties的属性不仅可以解决集成开发模式和组件开发模式的转换,而且还可以解决在多人协同开发Android项目的时候,因为开发团队成员的Android开发环境(开发环境指Android SDK和AndroidStudio)不一致而导致频繁改变线上项目的build.gradle配置。

在每个Android组件的 build.gradle 中有一个属性:buildToolsVersion,表示构建工具的版本号,这个属性值对应 AndroidSDK 中的 Android SDK Build-tools,正常情况下 build.gradle 中的 buildToolsVersion 跟你电脑中 Android SDK Build-tools 的最新版本是一致的,比如现在 Android SDK Build-tools 的最新的版本是:25.0.3,那么我的Android项目中 build.gradle 中的 buildToolsVersion 版本号也是 25.0.3,但是一旦一个Android项目是由好几个人同时开发,总会出现每个人的开发环境 Android SDK Build-tools 是都是不一样的,并不是所有人都会经常升级更新 Android SDK,而且代码是保存到线上环境的(例如使用 SVN/Git 等工具),某个开发人员提交代码后线上Android项目中 build.gradle 中的 buildToolsVersion 也会被不断地改变。

另外一个原因是因为Android工程的根目录下的 build.gradle 声明了 Android Gradle 构建工具,而这个工具也是有版本号的,而且 Gradle Build Tools 的版本号跟 AndroidStudio 版本号一致的,但是有些开发人员基本很久都不会升级自己的 AndroidStudio 版本,导致团队中每个开发人员的 Gradle Build Tools 的版本号也不一致。

如果每次同步代码后这两个工具的版本号被改变了,开发人员可以自己手动改回来,并且不要把改动工具版本号的代码提交到线上环境,这样还可以勉强继续开发;但是很多公司都会使用持续集成工具(例如Jenkins)用于持续的软件版本发布,而Android出包是需要 Android SDK Build-tools 和 Gradle Build Tools 配合的,一旦提交到线上的版本跟持续集成工具所依赖的Android环境构建工具版本号不一致就会导致Android打包失败。

为了解决上面问题就必须将Android项目中 build.gradle 中的 buildToolsVersion 和 GradleBuildTools 版本号从线上代码隔离出来,保证线上代码的 buildToolsVersion 和 Gradle Build Tools 版本号不会被人为改变。

具体的实施流程大家可以查看这篇博文: AndroidStudio本地化配置gradle的buildToolsVersion和gradleBuildTools

上面这些要感谢章华洋的博客,基本是按照他的写法自己写了一遍,体会了一下,里面的只是还是很多了,仅作备份,如果楼主有意见,马上删除!!!

可以看到上面的代码使用了TypeToken,它是gson提供的数据类型转换器,可以支持各种数据集合类型转换。

Gson的基本使用就是这么多,至于annotation方面可以参考gson的官方文档,希望能对初学java和gson的同学有所帮助。

TAG标签:
版权声明:本文由美高梅网投平台发布于美高梅简介,转载请注明出处:JSON数据解析,Gson简要使用笔记