解决Android开发中,ActiveAndroid和Gson同时使用,对象序列化失败的问题

ActiveAndroid是安卓开发常用的ORM框架。

Gson则是Google提供的轻量级序列化框架,非常适合Android开发使用。

但这两者同时使用,会产生序列化失败的问题。你通常会收到如下信息:

java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: [your model]. Forgot to register a type adapter?

这是由于ActiveAndroid框架需要模型继承com.activeandroid.Model类,而这个类貌似不能序列化,具体原因未深究,有兴趣的同学可以看看ActiveAndroid的源码。
在ActiveAndroid的Git上查阅了Issue后,发现有开发者遇到类似问题,但没有有效解决办法。

翻阅了Gson API之后,发现Google已经提供了解决途径。

假设我们有一个基础类ClassBase:

import java.io.Serializable;

public class ClassBase implements Serializable {
    /**
     * -6454847757470885679L
     */
    private static final long serialVersionUID = -6454847757470885679L;
    private String name;
    private int count;

    public String getName() {
        return name;
    }

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

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

}

另有一个扩展类Cnblogs:

import java.io.Serializable;

public class Cnblogs extends ClassBase implements Serializable {
    /**
     * 8568957562120574502L
     */
    private static final long serialVersionUID = 8568957562120574502L;
    private String welcome;
    private int members;
    private String url;

    public String getGuid() {
        return welcome;
    }

    public void setGuid(String welcome) {
        this.welcome = welcome;
    }

    public int getMembers() {
        return members;
    }

    public void setMembers(int members) {
        this.members = members;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}

如果我们在序列化时想要忽略父类的属性,怎么办呢?
这时候,你需要com.google.gson.ExclusionStrategy接口来处理这个问题。

import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;

public class SpecificClassExclusionStrategy implements ExclusionStrategy {

    private final Class<?> excludedThisClass;
    private final Class<?> excludedThisClassFields;

    /***
     * 过滤器初始化
     * 
     * @param excludedThisClass
     *            该类和继承自该类的对象实例将被忽略
     * @param excluedThisClassFields
     *            该类的属性将不被序列化
     */
    public SpecificClassExclusionStrategy(Class<?> excludedThisClass, Class<?> excluedThisClassFields) {
        this.excludedThisClass = excludedThisClass;
        this.excludedThisClassFields = excluedThisClassFields;
    }

    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        if (clazz == null) return false;
        if (clazz.equals(excludedThisClass)) return true;
        return shouldSkipClass(clazz.getSuperclass());
    }

    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        return f.getDeclaringClass().equals(excludedThisClassFields);
    }

}

再看看这个如何使用,

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class Main {

    public static void main(String[] args) {
        Cnblogs bl = new Cnblogs();
        bl.setName("Cnblogs"); // 设置父类属性
        bl.setCount(1);
        
        bl.setWelcome("代码改变世界"); // 设置当前类属性
        bl.setMembers(176473);
        bl.setUrl("http://www.cnblogs.com");
Gson gson
= new Gson(); // 通常我们使用的初始化方法 System.out.println(gson.toJson(bl));
     // 使用了过滤器的初始化方法 Gson gson2
= new GsonBuilder().setExclusionStrategies(new SpecificClassExclusionStrategy(null, ClassBase.class)).create(); System.out.println(gson2.toJson(bl)); } }

两条打印语句结果如下:

{"welcome":"代码改变世界","members":2030103,"url":"http://www.cnblogs.com","name":"Cnblogs","count":1}
{"welcome":"代码改变世界","members":2030103,"url":"http://www.cnblogs.com"}

因此,我们只需要在项目中,将gson实例的创建方式改为gson2,并将过滤类的构造函数第二个参数设为com.activeandroid.Model.class,序列化就成功了!

至于第一个参数,比如类A,则任何类A的实例或者继承自类A的类的实例,在序列化时都会返回null值,即不被序列化。

更复杂的序列化过滤规则,可以通过调整SpecificClassExclusionStrategy类中,两个重写方法来实现。

 

 

posted on 2014-05-12 15:23  飞扬的尘埃  阅读(6061)  评论(1编辑  收藏  举报

导航