I would like to re-design my application into components, so it is more modular and easier to re-use in the future, but I've never really designed applications, so I don't really know how I should do this.
Here is a brief description of the application:
The purpose of the Application is to allow the User to create "Events" that are going to be stored locally on the Device and sent over the network.
The User can interact with the application through 2 Activities: A "NewEventActivity" that allows him to create the new Events and a "LogbookActivity" that allows him to browse previously created Events.
The local storage should be handled by a SQLite Database
The Event should be sent in a specific Binary format.
Other applications should be able to Use the Sending component to Format and send other type of messages in the same format.
This drawing represents how I was thinking of organizing the components. Boxes represent components, and arrows represent interactions without those components.
Here are my questions:
Does this model look OK? Can you see something that could be improved?
Should my SQLiteHelper be a ContentProvider or a ContentResolver?
Should I create one BroadcastReceiver class per type of Signal, or should I create one big BroadcastReceiver that handles all the kind of Signals my application can handle?
Thank you!
A few suggestions to simplify the design:
If EventWriter and EventReader only interact with the activity due to direct user interaction, they don't need to be BroadcastReceivers. In fact, they could just be methods in the activities.
Depending on how you choose when to send Events, you could also refactor MessageFormatter and Sender into an IntentService which will periodically poll the content provider and choose which pieces of data to send. You can schedule the IntentService via alarms.
Should my SQLiteHelper be a
ContentProvider or a ContentResolver?
It should implement ContentProvider (since it provides access to data).
Should I create one BroadcastReceiver
class per type of Signal, or should I
create one big BroadcastReceiver that
handles all the kind of Signals my
application can handle?
I lean towards one receiver per signal type, but that's really just a preference.
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".
anyone knows why the Android developers team have implemented the Content-Resolver as a middleman to get data from a Content-Provider. Why not asking data directly from the Content-Provider ?
It means that the Content-Resolver has a special job, what is it ?
Why not asking data directly from the Content-Provider ?
A content: Uri may refer to a ContentProvider in another app. You cannot work with that ContentProvider directly; inter-process communication (IPC) is required. Hence, the API was designed around that IPC model.
ContentResolvers are designed to create an interface for applications to securely access and/or modify data in other applications which run in separate processes. It creates a common contract for content consumer registrations, requests, updates, binding, etc. to be passed between a particular ContentProvider and the content consumer that runs in another process.
Creating a proper and durable interface for transferring data across processes in Android is complex. If you had to create your own IPC client then it would be time consuming and you would likely overlook important aspects of the implementation. A "direct" connection to the ContentProvider is what a ContentResolver provides, but with a lot of the complexity already addressed. It is a convenience to already have that created and well-defined on both sides.
This is a little like a postal delivery system. If you use the postal service, you put an address on a piece of mail and the postal service (ContentResolver) finds the appropriate place to deliver the message (ContentProvider), and then returns any messages to you in response to your message. Your postal service will also handle new address registrations, tell you if the address is invalid, if the package is too big, if the recipient at the destination address is not accepting messages right now, waits if the message queue is full, handles situations where the vehicle carrying the message breaks down, etc. And in the case of ContentResolvers there are a few other things.
You could handle all of that yourself but when you think about real-life message delivery, it's not simple and much easier to use something built by someone else. Likewise for interprocess communication (IPC) in Android. It's not a perfect analogy but hopefully that helps clarify the need for a ContentResolver.
I am new in android app development and while studying about the basic android components I got confused between intents and content provider as both are being used to send data from one application/component to another application/component . In case of intents we can send data using bundle or extras so why do we use content providers. Can someone please explain me this with a example . Also can we access database in android only using content provider and is this the sole reason why we use content providers ?
both are being used to send data from one application/component to another application/component
Not really.
There are four components in Android:
Activity
Service
BroadcastReceiver
ContentProvider
An Intent is none of those. An Intent is involved when we start an activity, start or bind to a service, or send a broadcast. However, comparing an Intent to a ContentProvider is akin to comparing a shovel with a boot, arguing that both can be used to carry dirt. While true, usually a boot is involved in carrying dirt, but the actual means of carrying dirt is handled by something else, such as a wheelbarrow.
In case of intents we can send data using bundle or extras so why do we use content providers.
We often use different tools for different circumstances. For example, you will find it rather difficult to carry water in a fishing net.
Each of the four components has a different role, particularly in relationship to inter-process communication (IPC):
An Activity drives the bulk of our user interface, including starting up activities from other apps (or having one of our activities be started by other apps)
A Service exists for longer-running operations that are logically decoupled from the user interface, including working with services that are implemented by other apps (or having other apps work with services that you publish)
A BroadcastReceiver is a publish/subscribe messaging system, to allow you to send messages to arbitrary subscribers, or to subscribe to messages from arbitrary senders, across process boundaries
A ContentProvider is for bulk data transfer, whether in the form of a database-style structure (rows and columns) or in the form of a stream, particularly for working with other apps
Also can we access database in android only using content provider
No. After all, if that were true, it would be impossible to access a database. A ContentProvider does not appear by magic. It has to be written by a programmer. If a ContentProvider could only access a database by means of a ContentProvider, we would have a problem.
is this the sole reason why we use content providers ?
No. In addition to offering a database-style API, a ContentProvider can also publish a stream. This is important for getting arbitrary data between apps, such as an email client making a PDF attachment available to a PDF viewer.
Intents are a messaging architecture for sending /receiving transactional commands and data. Content providers are an abstract interface to stored data for create,update, delete and sync operations.
Okay so up front I will say that I am new to Android. I have made a few small projects and played with a few things and done tons and tons of reading. So here is the task I am trying to accomplish:
I have a remote service that runs in the foreground of my phone that can send and receive information with other android devices over a wifi network. APK's on the phone that are built to use this service contain multiple SQLite DB's. I want these APK's to register there content providers with the service so the service always know where to put data that it recieves (I have accomplished this task). When data comes in I will identify where it belongs and place it in the right DB (no problem here). So what would be the best way to notify the correct activity that new data has been received. Do I register Broadcast Receivers for my service to call? Will Broadcast Receivers work if the APK has been killed by the OS? Once the correct activity is loaded would I use a content observer to show the new data? Why would I use IntentServices?
I'm sorry for so many questions. Like I said I am learning fast but Android's SKD is massive and there are so many cool things. I want to make sure I am thinking things through right with best practices and making this very easily maintainable and expandable. Thanks for any help or advice I can get.
If you are asking what the best way is for a current Activity to know data has changed in the ContentProvider it is reading from, than the answer is a ContentObserver.
Lets say, for examples sake, you have a set of Activities and ContentProviders. Activity A is a list view of items from Content Provider A, and that list view is populated via a CursorAdapter of some kind. Whenever you have a query on a ContentProviders CONTENT_URI, the cursor should automatically monitor the CONTENT_URI for changes via a ContentObserver.
The reason this works is because in the ContentProvider:
Your query method calls setNotificationUri on your cursor to the URI that was queried.
Whenever a change happens in an insert/update/delete method, you are calling notifyChange on the URI.
If there is additional data that can change in your service that is not tied to a ContentProvider, than you have a few choices on how to pass data. If the Activity is in the same APK as your service, than you could use some sort of static variable, or the application context, or some other custom form of communication. The methods are rather liberal here because you are running in the same VM, so you have a lot of things available to you.
In your situation, it sounds like most activities will be in separate APKs. If that is the case, you will probably want to send out broadcast Intents to let the entire system knwo about the changes. If these changes only matter when an activity is running, you can register a BroadcastReceiver for the life of the Activity that cares about the change. Alternatively, you could put a BroadcastReceiver in the applications manifest, and always receive that change.
That brings us to IntentServices. IntentServices are the "easiest" way to handle long running tasks in Android. All they do, is create a background thread that will handle intents being sent into the service. A common use case is as follows:
You receive a broadcast intent that you need to react to (and it will take a while)
Send a directed intent (intent with a set component name) to an IntentService with some info from the broadcast intent.
IntentService either spawns a new BG thread, or adds the intent to the processing queue on the existing BG thread
The onHandleIntent function is called in the IntentService so that you can now process that change using as much processing time as you want.
I've been working with Android for well over a year now, but I still have trouble determining when different types of messaging/communication between processes/threads should be used. I'm mainly talking about broadcasting Intents, using AIDL for services, using Handlers to send messages and socket communication.
Many of these tools can be used to accomplish similar tasks, but which is better suited to particular situations?
This is a pretty open ended question, but let me take a shot at describing how I see the intra/inter application communication working best.
One of the key aspects of Android messaging is the concept of all application components being loosely bound. Because all applications run in a separate process, and one 'app' may actually consist of several applications (responsible for providing different Activities or Services), the messaging techniques are all based around the idea of marshaling messages across process boundaries.
Intents
The preferred technique for messaging, always try to use an Intent whenever possible. It is the most 'native' way to transfer messages within Android.
Advantages
Using Intents for messaging maintains the loose binding of application components, letting you transfer messages seamlessly between several applications. Intents are used heavily within the core system to start Activities and Services, and to broadcast and receive system events.
Using extras Bundles you can include key/value pairs of primitives as payload data within Intents to easily pass information from one application component to another - even if those components are running in different processes.
Disadvantages
Because Intents are designed to go between processes, the extras payload only supports primitive types. If you need to send an object using an Intent you'll need to deconstruct it into primitives at one end and reconstruct it at the other.
Application Class
If you only want to communicate within a single application running in a single process this is a handy solution.
Advantages
By extending the Application class (and implementing it as a Singleton) you get an object that will exist whenever any of your application components exist, providing a centralized place to store and transfer complex object data between application components.
Disadvantages
This technique limits your messaging to components within a single application.
Service Binding, IPC, and AIDL
Binding to a service lets you access its methods and exchange objects with it. AIDL is a way of defining how to serialize an object into OS primitives so that it can be marshalled across process boundaries if the Service you're binding to is running in a separate application.
Advantages
When you bind to a Service you have access to it as though it was an object within the calling class. That means you can execute methods on the Service and exchange rich objects with it.
Note that if you're binding to a Service in a different application process you'll need to create the AIDL definitions that tell Android how to seralize / deserialize any objects you want to pass between applications.
Disadvantages
Creating the AIDL classes for IPC is a bit of extra work, and binding creates additional dependencies between Services and Activities which can make it harder for the kernel to clean up resources when other applications are being starved.
Marshelling messages across process boundaries is expensive though. So if you're not executing methods on a Service, using binding and IPC is probably overkill - see if you can achieve the same thing using Intents.
Sockets
If you're resorting to sockets to communicate within or between applications running on a single device, it's either because there's no other way or you've missed a trick somewhere. If your messages are leaving the device then sockets are a good, fast, alternative. If you're staying on the device chances are Intents or IPC is going to be a better option.
It all depends on the use case and kind of your application. If the application is running all the time better to go with AIDL approach as it is most secure way to communicate. If application need not run all the time, then you can go with either broadcast intent or pending intent approach to communicate between applications.
My 2 cents
I have not used local sockets.
Seems like overkill since you have to
generate and parse the data.
Intents are for either things that
other apps might want to do (launch
me in a compose window or to pick
something out)
AIDL/Parcels/Handlers for having a
GUI talk to a headless process that
is running constantly. Depending on
the app a lot of the actual data
transfer might happen using a content
provider but I tend to have some data
that needs to be transferred outside
of that channel.
This is a good article I found helpful in trying to find a substitute for Cocoa's NSUserDefaults class:
http://developer.android.com/guide/appendix/faq/framework.html