Dan Morrill (Google)
Android is not just a framework - it's a complete OS.
An android APK is an android package, which is a collection of components. Components share a set of resources. An "Activity" is a discrete chunk of functionality. A task is a collection of activities. Activities are an encapsulation of a particular operation, and are implemented as a concrete class in the API. They run in the process of the APK which installed them. A task is a runtime record of a sequence of activities, which has a UI history stack - they are what users on other platforms know as "applications".
Android processes are linux processes. 1 Process per APK, 1 thread per process - by default. All (most) components interleave events into the main thread. A process is strated for a given user ID when needed - binding to a service, starting an activity, binding to a contentprovider, etc. Process keep running until killed by the system, possibly to free up memory.
Activities has several states, and lifecycle methods are called upon transitions. There are three general phases:
-
Starting up
- onCreate() : first method called during lifetime
- onStart()/onResume() : signals that execution is beginning
- onResume() : signal that a pause has been undone - you are the top level app
- Normal execution
- onFreeze() : save UI state
- onPause() : loss of focus and possible impending shutdown
-
Shutting down
- onStop()/onDestroy() : final shutdown and process termination
- Not guaranteed to be called
Each thread has a looper to handle a message queue. Events from all components are interleaved into Looper. Loopers cannot accommodate multi-threaded access. They are designed to play nicely with MessageHandlers.
Views use Loopers messages to fire events. Since Loopers are 1:1 with threads the view tree is too.
There are two ways to start a service - explicitly, until explicitly shut down, or implicitly, until the last client unbinds.
Processes are spawned by the special "Zygote" process. Process + pre-warmed Dalvik VM == responsiveness. Process runs under userID unique to system - process + userID == security.
Each application has a unique userID, and each has direct access only to its own data. Other apps resources are available only via defiend APIs that are explicitly exposed.
All this can be confusing, but it's for the noble goal of speed. Serialization is slow, as are memory transfers - so CPU is not the bottleneck.
Process management is transparent to code, almost always. Lifecycle is seamless, but data sometimes isn't.
Binder is a general process IPC mechanism. It's implemented as a kernel module and a system lib. There are generally two entry points: Bundles and Parcelables. A parcelable is a class which can marshal its state to something Binder can handle. Standard Java serialization has semantics parcelables wouldn't use.
Bundles are type safe maps - containers of primitives. Simple data passing APIs use Bundles. Used for onFreeze().
RSS Feed
0 comments:
Post a Comment