Подтвердить что ты не робот

Класс не обнаружен при разборке при передаче Parcelable через Messenger на удаленную службу

У меня есть объект Parcelable, который я использую для передачи его из Activity в удаленную службу. Когда я передаю его с помощью интерфейса AIDL, все звучит нормально.

В последнее время я пытаюсь передать его через Messenger из Activity.

// 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): класс не найден, когда unmarshalling: 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

4b9b3361

Ответ 1

Неподготовленный подход (поскольку наш Parcelable является обычным, а не частью Framework, например 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 для отправьте сообщение через процессы, это может быть только не null, если оно содержит Parcelable класса framework (не один, реализованный выражение). Для другой передачи данных используйте setData (Bundle).

Обратите внимание, что Parcelable объекты здесь не поддерживаются до FROYO выпуск.

Ответ 2

Вероятно, вы не используете правильный ClassLoader. Вам нужно отслеживать ClassLoader, который сначала сортирует класс, и используйте THAT ClassLoader, чтобы отменить его.

При использовании unmarshalling вы используете текущий поток ClassLoader, который не является вашим UIThread, но системным потоком Android и, как таковой, не имеет информации о ваших пользовательских классах.

Я использовал статический класс, который содержал мой ClassLoader, чтобы решить эту проблему (аналогичные подходы можно использовать, не будучи статическими). ​​

Что-то вроде:

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

Тогда, когда unmarshalling:

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

См. этот другой вопрос для получения более подробной информации (вероятно, дубликат btw).

Ответ 3

Я получаю следующее исключение в удаленной службе.

Если вы действительно получаете это от удаленной службы, это связано с тем, что приложение удаленного сервиса не содержит этот класс. Если вы собираетесь использовать пользовательские классы Parcelable, и клиент, и сервер должны иметь одно и то же определение класса.

Если, однако, ваша трассировка стека выглядит так, как ваш Parcelable получает доступ из основного процесса ОС, то вы не можете передать объекты Parcelable через obj надежно. Я использовал obj только Message для передачи объекта в процессе, никогда не для сообщений о перекрестных процессах.