I'm an Android newbie. I'm trying to send and receive messages between process. One thing which I'm aware of is communicating via binder calls by implementing a Service. The other message transferring mechanism which I've seen so far is
Broadcast (Not reliable though) - which can be missed
Event bus (Not sure IPC is possible with greenrobot's event bus - this SO link says it's not possible and suggested for alternatives
Registering a ContentObserver so that I can update my content at one process and the other process can get notified of the content change (Not sure this is reliable)
All I mean by reliable is that it can be missed at rare cases. Is there any alternative reliable and ordered (delivered in the same order in which it's published) - message exchanging mechanism between processes in Android?
EDIT: Though there are many ways discussed in this SO Link I would like to maintain the message order and guaranteed delivery of message.
Related
I am working on sharing road traffic information between Android applications, and wondering what is a good transport mechanism.
There are two classes of applications: Publishers post traffic messages they have obtained from various sources (say, an Internet service or a TMC receiver device) and converted to a standard format. Subscribers listen for messages and work with them (e.g. displaying them in a list or guiding drivers around congestions). The system is intended to be decentral: there will be multiple publishers, multiple subscribers and users can mix and match them as they like.
Messages are identified by a unique ID, which remains stable over their entire life cycle. They have an expiration time, after which they are considered invalid. Until then, they can be updated at any time. An update can also cancel the message (replacing it with a tombstone until it expires), or extend its expiration time.
Subscribers get new messages as they arrive. (Filtering may happen in a later phase.) They also need a way to retrieve all currently cached messages from all publishers.
A message is around 1 kByte in size. A publisher can easily hold several hundred active messages at any given time.
In terms of security, the messages are generally public information. The only sensitive information is geodata, as it may allow for conclusions on the location of the device or where its user intends to travel. The precision of such data is low, anywhere from city to country level. Therefore I don’t see a need to hide this information from any app, as long as it has location permission.
Now I am wondering what a good transport mechanism would be:
Option 1: Broadcast intents
Initially I have been working with broadcast intents: whenever a publisher has any new messages, it sends an implicit broadcast with the messages in the extras. Subscribers can register a broadcast receiver at run time to receive messages. They also have the option to send a poll broadcast (an explicit broadcast, with the corresponding broadcast receiver declared in the publisher’s Manifest). Publishers will then respond with a feed of all currently cached messages. To address security concerns, any app sending a broadcast with geodata requires that the receiver hold one of the location permissions.
There is an issue with large feeds, as the Android request broker supports a maximum of 1 MByte for all concurrent transactions (so the maximum amount of data in a feed can be even less if things are busy). I am currently working around that by breaking down feeds into chunks of 100 messages or less.
An advantage of this system is that all central infrastructure is provided by the OS. Having one publisher and one subscriber app installed is sufficient.
Option 2: Content Providers
Some people have pointed out that broadcast intents are not the best way to go, and have suggested I implement a content provider, a territory into which I have not ventured so far. Looking at the documentation, it is not clear if there is a way to have multiple backends (each backend being a separate app) implement functionally identical content providers and advertise them as such. Since content providers support both read and write operations, I could set up one central component as the content provider, and have both publishers and subscribers connect to it. However, that would require providing a central component in order to work, which I would rather avoid.
Questions:
Is there a way to implement the above multi-publisher, multi-subscriber model with content providers, and without having to supply a central component not already provided by the OS?
Specifically, can a single content provider have multiple backends? Alternatively, can multiple, functionally identical content providers advertise themselves as a group?
How would I implement the above using content providers?
What are advantages and drawbacks of broadcast intents or content providers that I may have missed?
Is there a way to implement the above multi-publisher, multi-subscriber model with content providers
Keep the broadcasts. Replace the payload.
Publishers would implement a ContentProvider that serve up the current roster of messages. You can think of a ContentProvider as being a quirky sort of REST-style Web service, where Uri values get mapped to responses by the provider.
Publishers would then send broadcasts as they are today, but perhaps with only two extras:
One that identifies the protocol version that the broadcast is using, since you have lots of independently-updated parties. Rceivers need to know how to interpret the broadcast, as you might change the rules over time.
One that contains a Uri pointing to the publisher's ContentProvider.
If there are other extras that you are using today that you know will remain small, and you want to still put those in the broadcast, that's cool. Just keep the indeterminate-sized ones out of the broadcast.
Receivers would then:
Look at the protocol version extra and branch to the code to handle that version (today, just one branch, but, hey, future-proofing)
Use that Uri and a ContentResolver to get the messages (and other stuff if needed) from the publisher
You might consider developing this communications infrastructure as an SDK. Even if you are the only one developing apps, you'll want to avoid duplicating all this logic across the apps. And, if third parties will develop apps, you're better off giving them an SDK to work from, rather than forcing them "roll their own".
Is there a (more modern) way (besides using sockets) to register a callback method to listen for data?
I'd like to have my app register itself with it's IP and a callback method name. The server would then send data back - much like Whatsapp.
I don't know if I understand your question correctly; besides sockets there are alternatives for pushing messages to Android devices, particularly "Cloud Messaging": https://developers.google.com/cloud-messaging/ .
If you just want to implement TCP or UDP-based communications by implementing your own server, sockets are not "outdated" (what do you mean with "modern"?). You can write your own re-usable Server/Client classes that ease the registering of callbacks for incoming connections/packets.
If you google a bit, you will also find frameworks that offer message-based communications facilities you are searching for, e.g.
http://www.binpress.com/app/chat-messaging-sdk-for-android/2326 .
P.S.: I suggest you reformulate the title of your question, because it seems not to be about callback registering itself!
What is maximum acceptable frequency from your point of view or experience of sending broadcasts in Android to be received by BroadcastReceivers without performance impact?
Let's say we send only basic data in a Bundle without need for long deserialization.
I am going to send broadcasts only inside my app with LocalBroadcastManager.
In other words this question is about when you should stop using broadcasters and write you own implementation for faster usage and when you should not do it.
First of all, if you send data inside one app, I would advise you, instead of BroadcastReceiver use LocalBroadcastManager or even not use any type of broadcast receivers at all - just Observer Pattern (here good article on this topic).
What would be good approach to establish communication between different APKs? One app can send request to other apps and wait for response.
I can think of:
1. using BroadCast receivers: send "request" broadcast and receive returned broadcasts (results). This seems nice clean solution, no security problems, but how to get all results back as "one" - usually I will want to send out broadcast to collect app identifications, and get result like array.
2. use sharedUserId between all these apps and gather or execute whatever I need directly on the apps. But here are have couple of more loose ends:
- how do I get list of apps (through list of installed packages?)
- is with sharedUserId and same signature possible to access other app internals? like register/unregister component, etc.?
Thanks!
EDIT:
Have been reading more about ordered broadcasts and so far this seems good way to go. Using order broadcast each of other apps will fill in its own data part and result will be returned back to supplied "final" receiver.
I am using ordered broadcasts. When broadcast is send out, each receiver adds its information and last receiver calls resultReceiver.
I'm using pubnub as a publish/subscribe channel between an android app and a server.
Currently I'm thinking of how I will implement this.
I'm using the provided library for android (https://github.com/pubnub/pubnub-api/tree/master/android) but I think there will be some problems with the application lifecycle if I use it like it is now. (Correct me if i'm wrong)
I was thinking of implementing it as a service
What I want
The service has to keep on running until an hour (negotiable) after the last app usage. That's because we want to have notifications when a message comes in, but the app is not the currently used app.
How do i stop the service after one hour of non-activity of the app? Probably Android will kill it, but I want some control.
The Service must be able to trigger the app to change it's interface when specific messages come in (I was thinking of sending intents from the service when we receive a pubnub message?), pubnub will send data to the service, so I need a way to pass this data to the application (probably save it in a Bundle in the intent?)
I need to listen to multiple pubnub channels (max 2 at the same time), I think I will have to do this in multiple instances of this service?
I think I will do it like this:
Create a service that's started when the app starts
Let the service listen to a pubnub channel
When a message comes in, send an intent and use the intent filters
implement broadcasthandlers to listen to these internal intents
Is this the right way to do this? any hints?
You have an excellent set of questions an detailed points that I will talk about in this answer. You are using Android and you are interested in the conventions and best practices for PubNub Publish/Subscribe scenarios.
Your use case is very common and the best ways to build apps always vary dependent on application needs. However you definitely have the right idea and have asked all the right questions. You just needed some sample code and a direction to get started on implementing the specifics of your application needs. To define your needs in a list:
Connect/Disconnect Ability.
Always-on Background Service that can Send/Receive data and notify other apps via Android Intents.
Connecting to Multiple PubNub Channels at the Same Time.
So to get started I will provide you direct links to some examples and methods:
Create a Service that is Started when when Android Boots: https://github.com/pubnub/pubnub-api/blob/0dfd8028b803332f5641adc909b1a26f87bd7ff1/android/PubnubAndroid/src/com/aimx/androidpubnub/BootReceiver.java
UnSubscribe/Disconnect Example Code when you want to stop listening on a PubNub Channel: https://github.com/pubnub/pubnub-api/blob/0dfd8028b803332f5641adc909b1a26f87bd7ff1/android/PubnubAndroid/src/com/aimx/androidpubnub/MainActivity.java - Listening to multiple channels is easy by placing the blocking pubnub.Subscribe() method inside a Thread.
Regarding your thoughts - This IS the right way to do it:
Create a service that's started when the app starts
Let the Service listen to a PubNub Channel.
When a message comes in, send an intent and use the intent filters.
Implement BroadcastHandlers to listen to these internal intents.