Является ли использование Parcelable правильным способом отправки данных между приложениями?

Я пытаюсь понять, как взаимодействовать между приложениями в Android, а не только между экземплярами Activity.

Я установил «клиент», который отправляет объект Messenger в службу (в Intent, отправленном в службу); служба создает объект Message и отправляет его «клиенту» с помощью messenger.send(message). Это работает нормально, пока я не попытаюсь использовать Message.obj для хранения объекта.

Я создал свой Parcelable класс MyParcelable в сервисе и вставил его в сообщение. Все работает до тех пор, пока сообщение не будет рассортировано в «клиенте». Unmarshall терпит неудачу, потому что «клиент» не имеет доступа к классу MyParcelable. Это очевидно - они в разных пакетах (скажем, com.whatever.myclient и com.whatever.myserver). Это совершенно неправильный способ сделать это?

Я также пытался создать Parcel и отправить его (таким образом, оба приложения будут иметь доступ к классу), но Parcel не является Parcelable. Я читал об использовании загрузчиков классов, но не понимаю, как отдельные загрузчики классов в отдельных приложениях (процессы, если я понимаю архитектуру Android в этом отношении). То есть, как можно «научить» один загрузчик классов классу, существующему в другом загрузчике классов? Конечно, кажется, что должно быть очевидное «вот как вы это делаете», но я еще не видел этого.


person Art Swri    schedule 25.03.2013    source источник


Ответы (3)


Вы не можете отменить класс в процессе, который не знает об этом классе (как вы уже правильно указали). Если вы хотите, чтобы MyParcelable было отправлено на ваш Service, вам нужно включить MyParcelable в Service при сборке, и включить правильный ClassLoader, который будет использоваться при демаршалинге, потому что демаршалинг выполняется системным потоком, который не знает, что такое MyParcelable, даже если вы включили его во время компиляции.

ИЗМЕНИТЬ:

(a) включить MyParcelable в 2 разных пакета и сделать так, чтобы они рассматривались как один и тот же класс

Создайте библиотеку ваших общих классов и включите ее в оба приложения (приложение и Service). Вы можете либо пометить его как библиотеку Android (в Eclipse это прямо в свойствах Android проекта), либо экспортировать его как JAR и импортировать в оба приложения. Всегда полезно иметь независимые классы в библиотеке, а не размещать их напрямую в приложениях. Таким образом, вы можете повторно использовать их в других проектах;)

(2) включить правильный ClassLoader (например, откуда я могу получить правильный загрузчик классов)

Вы можете получить ClassLoader из текущего потока, когда выполняете свой код. Очевидно, этот ClassLoader знает о ваших классах, потому что он выполняет ваш код ;) Например, в Activity#onCreate() вы можете сделать Thread.currentThread.getContextClassLoader(). Так как ваш класс MyParcelable также включен в Service, вы можете сделать то же самое, чтобы получить действительный ClassLoader для отмены маршаллинга.

Другим решением для IPC является определение интерфейса AIDL, чтобы вам не приходилось реализовать Parcelable.

person m0skit0    schedule 25.03.2013
comment
Привет, m0skit0, ты должен немного расширить это. Я собирался ответить, но вы совершенно правы. Небольшое дополнительное объяснение сделало бы это более ясным. Parcelables работают только в том случае, если ClassLoaders, упорядочивающие и неупорядочивающие данные, имеют идентичные копии класса Parcelable... - person G. Blake Meike; 25.03.2013
comment
Звучит хорошо, но я понятия не имею, как сделать либо (а) включить MyParcelable в 2 разных пакета и сделать так, чтобы они рассматривались как один и тот же класс, либо (2) включить правильный ClassLoader (где я могу получить правильный загрузчик классов, например ). Спасибо за ваш ответ, но вы примерно на 2 уровня выше моего понимания. - person Art Swri; 25.03.2013

Если вы не хотите где-то использовать уровень сохраняемости (я использую облачный API), вы можете запустить службу в отдельном процессе и привязать к службе соответствующие приложения, которым нужны общие данные объекта типа держателя значения. сервис будет там, где вы создаете и получаете значения obj от имени подключения (привязки) приложений.

person Robert Rowntree    schedule 25.03.2013
comment
Это оба очень хороших предложения, и я обязательно буду держать их при себе, когда продолжу. На данный момент я в основном пытаюсь понять концепции Parcelable и загрузчика классов в надежде, что я пойму их достаточно, чтобы иметь возможность использовать их надлежащим образом. Большое спасибо за ваш ответ. - person Art Swri; 25.03.2013
comment
знать основы Android и жизненный цикл активности. это может быть важнее концепций CL. developer.android.com/reference/android/app/Activity.html developer.android.com/guide/components/fundamentals.html - person Robert Rowntree; 25.03.2013
comment
imo-inter app, проще всего было бы использовать поля «intent-extra» и, я думаю, средство выбора, которое позволило бы выбрать целевое приложение. - person Robert Rowntree; 25.03.2013

Хорошо, я нашел «легкий способ», который искал. Вы можете поместить Bundle в поле Message.obj. Bundle является Parcelable, поэтому его можно транспортировать между клиентом и сервером. Нет проблем с тем, что сервер не знает, какой класс он получает, поскольку Bundle «встроен» в Android Java. И Bundle, по-видимому, может включать в себя «sub-Bundles» с in. Это проще, чем иметь дело с обеспечением того, чтобы обе стороны знали определение определяемого пользователем класса. Спасибо за ответы выше - я, безусловно, ценю информацию!

person Art Swri    schedule 28.03.2013