13

我有一个 Parcelable 对象,我用它来将它从 Activity 传递到远程服务。当我使用AIDL接口传递它时,一切听起来都很好。

最近,我尝试从 Activity 中通过Messenger传递它。

// TEST TEST TEST!
StockInfo stockInfo0 = new StockInfo(Code.newInstance("code0"), Symbol.newInstance("symbol0"));
StockInfo stockInfo1 = new StockInfo(Code.newInstance("code1"), Symbol.newInstance("symbol1"));
StockInfo stockInfo2 = new StockInfo(Code.newInstance("code2"), Symbol.newInstance("symbol2"));
List<StockInfo> stockInfos = new ArrayList<StockInfo>();
stockInfos.add(stockInfo0);
stockInfos.add(stockInfo1);
stockInfos.add(stockInfo2);
StockInfosEx stockInfosEx = new StockInfosEx(stockInfos, "abc");
msg.obj = stockInfosEx;

try {
    mService.send(msg);
} catch (RemoteException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

我在远程服务中遇到以下异常。

02-21 22:55:16.546:E/Parcel(8365):解组时找不到类:com.example.testonmessenger.StockInfosEx,e:java.lang.ClassNotFoundException:com.example.testonmessenger.StockInfosEx

我想知道,这两者之间会出现什么问题?这是我的 Parcelable 对象。

public class StockInfosEx implements Parcelable {
    public final List<StockInfo> stockInfos;
    public final String searchedString;

    public StockInfosEx(List<StockInfo> stockInfos, String searchedString) {
        this.stockInfos = stockInfos;
        this.searchedString = searchedString;
    }

    ////////////////////////////////////////////////////////////////////////////
    // Handling Parcelable nicely.

    public static final Parcelable.Creator<StockInfosEx> CREATOR = new Parcelable.Creator<StockInfosEx>() {
        public StockInfosEx createFromParcel(Parcel in) {
            return new StockInfosEx(in);
        }

        public StockInfosEx[] newArray(int size) {
            return new StockInfosEx[size];
        }
    };

    private StockInfosEx(Parcel in) {
        stockInfos = new ArrayList<StockInfo>();
        in.readTypedList(stockInfos, StockInfo.CREATOR);
        searchedString = in.readString();
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int flags) {
        parcel.writeTypedList(stockInfos);
        parcel.writeString(searchedString);
    }

    // Handling Parcelable nicely.    
    ////////////////////////////////////////////////////////////////////////////        
}

要获得完整的源代码,请从https://www.dropbox.com/s/n69yuhddpb8vedz/testonmessenger.zip下载

4

3 回答 3

23

不可行的方法(因为我们的 Parcelable 是自定义的,而不是像 Rect 这样的框架的一部分)

活动

msg.obj = stockInfosEx;

远程服务

StockInfosEx stockInfosEx = (StockInfosEx)msg.obj;

可行的方法

活动

msg.getData().putParcelable("data", stockInfosEx);

远程服务

msg.getData().setClassLoader(StockInfosEx.class.getClassLoader());
StockInfosEx stockInfosEx = (StockInfosEx)msg.getData().getParcelable("data");

现在,在我再次阅读 msg.obj (http://developer.android.com/reference/android/os/Message.html#obj)的文档后,只有我明白它的真正含义Parcelable of a framework class

要发送给收件人的任意对象。当使用 Messenger 跨进程发送消息时,如果它包含一个框架类的 Parcelable(不是应用程序实现的),它只能是非空的。对于其他数据传输,请使用 setData(Bundle)。

请注意,在 FROYO 版本之前,此处不支持 Parcelable 对象。

于 2013-02-21T16:36:28.363 回答
6

您可能没有使用正确的ClassLoader. 您需要首先跟踪ClassLoader正在编组类的内容,并使用 THATClassLoader来解组它。

解组时,您使用的是当前线程的 ClassLoader,它不是您的 UIThread 而是 Android 系统线程,因此没有关于您的自定义类的信息。

我使用了一个包含我的静态类ClassLoader来解决这个问题(可以使用类似的方法,而不需要它是静态的)。

就像是:

ClassLoaderHelper.setClassLoader(Thread.currentThread().getContextClassLoader());

然后在解组时:

public final void readFromParcel(final Parcel in) {
    id = in.readString();
    appInfo = in.readParcelable(ClassLoaderHelper.getClassLoader());
    ...
}

有关更多详细信息,请参阅其他问题(可能是重复的顺便说一句)。

于 2013-02-21T15:32:24.283 回答
3

我在远程服务中遇到以下异常。

如果你真的是从远程服务中得到这个,那是因为远程服务应用程序不包含那个类。如果要使用自定义Parcelable类,客户端和服务器必须具有相同的类定义。

但是,如果您的堆栈跟踪感觉就像您Parcelable正在从核心操作系统进程访问,那么您无法可靠地传递Parcelable对象。obj我只用于进程内对象传递,从不obj用于Message跨进程消息。

于 2013-02-21T15:40:22.413 回答