Android - Software stack for mobile applications - operating system, middleware and key applications - Reuse and replacement of components - Dalvik virtual machine (NOT Java virtual machine) - .dex files (.jar) - View system - An application runs in its own Linux process (unique Linux user ID) - Process is started when some (any) of the application's code needs to be executed - For example, the user can start the "Main" activity, or some other process may start one of the components of the application - Shut down when the process is no longer needed - In case two applications have the same user ID, data (user files) can be shared between them - Check out how this is done! Application Components (architecture) - An application can make use of other applications' components given that it has the permissions do so. For example, you can have your application display a web or email address, and when the user selects it, the web browser or the email client is opened. Other examples: - Open the camera application when a picture needs to be taken - Open the gallery when the user wants to select a media file - Open the contacts list when a contact needs to be selected - Use a music player background service when you want to play music in your app Components can be started explicitly (using an explicit intent), or implicitly (using an implicit intent). The difference is that with explicit intents you're telling the OS which exact component you want. Usually explicit intents are used when a specific component belonging to the same application needs to be opened. With implicit intents you do not specify the target component directly, but give the OS hints as to which kind on functionality you require, and the OS then selects the most appropriate intent. Sometimes the OS finds two or more applications with equal opportunity to handle an implicit intent. In such a case, the user is presented with a dialog window where the intended application can be selected. Also, the user is able to select an application to use by default for handling the kind of implicit intent in question. For example, if you have two or more web browsers installed on your system and you select a web address, you're presented with a list where the browser applications able to handle the intent are selectable. Unless you want to select the browser every time you click on a link, you can set the default browser for handling the intent. (The default setting can of course be cleared by the user later on if so required.) There is no single application entry point (no main() function). Remember that an application is just a bunch of components belonging to the same package. When a component is requested by an application, Android makes sure the process containing the component is available, starting it if necessary. Also an instance of the component is created if it doesn't already exist. - Activity - An activity presents a UI for the user for a single focused action, or a set of closely linked actions. For example, an activity can present the user a list of contacts, while another activity might open when the user selects a contact, presenting the details view (phone number, email, etc.) of the selected contact. If the user's email address is clicked for example, the email application's "compose email" activity is opened. (Also show examples from LoanShark) - Dialogs are not activities, but are contained within the activity - Visual content provided by a hierarchy of views (derived from the View class) - Layouts - Activity.setContentView(int id); - Service - No UI - Runs in the background - Can be started or bound to (difference?? how do I know whether to try to start a service or bind to it?) - In BroadcastReceiver.onReceive(), startService() must be used since the receiver is no longer alive after returning from onReceive(), and can thus not receive binding result asynchronously - Use peekService(Context, Intent) in case you need to check if a service is already running, then bindService(Intent, ServiceConnection, int) to it - If a service is not already running, it can be started by calling startService(Intent) - A long-lasting background action - For example, playing music, downloading data over the network - User may leave the UI, while the service continues in the background - Runs in the main thread (like all components) *** - Needs to start a separate thread in order not to block the UI - Started by calling Context.startService() - A component can establish an ongoing connection between itself and a service by binding to it - Context.bindService() - Represents a long-running background task that doesn't interact with the user - IntentService - A service that runs in its own thread - Implement onHandleIntent(Intent) - Starts and stops a worker thread as appropriate - When service is started by calling Context.startService() - Service.onCreate() is called (if not already running) - onStartCommand(Intent, int, int) is called - Service continues to run until stopSelf() or Context.stopService() is called - Service can be started multiple times, but runs until the first call to stopSelf() or Context.stopService() - Starting modes - START_STICKY - START_NOT_STICKY - START_REDELIVER_INTENT - Binding to a service results in a persistent connection (IBinder reference) - Usually for services with interface defined in AIDL - BroadcastReceiver - Receives broadcast announcements - For example: alarms, text message, email, calendar reminder, battery low, battery fully charged - Registered either in the manifest or by calling registerReceiver(BroadcastReceiver, IntentFilter) - Example of registering in manifest (from LoanShark): - Derive from class BroadcastReceiver - For example, AlarmManager may send a broadcast, which can be intercepted - onReceive(); No other methods to implement - Must not take long to complete - May start an activity, or show a notification - Doesn't exist in memory (as a "listener") before called into action. Android starts the BroadcastReceiver when a suitable intent is being handled - Active only when onReceive() is being executed - No need to shut down - Can't display a dialog, or take a long time to execute - Rather start an activity or a service - ContentProvider - Makes a subset of application data available to other applications - For example, the contacts application provides means for other applications to acces contacts - Base class ContentProvider - Clients use a ContentResolver object to retrieve data (IPC handled automatically) - Active only when responding to ContentResolver - No need to shut down Intents - Used for activating components (except ContentResolvers) - Can contain a Bundle of data items - Starting an Activity - Context.startActivity() - Doesn't expect a result - Activity.startActivityForResult() - once the started activity finishes (by calling finish()), onActivityResult() is called - If an Activity is already active onNewIntent() is called - ONLY if the activity's launch mode is singleTop - Can also be set when calling startActivity() - Can be stopped by calling finish() - If the activity was started with startActivityForResult(), it can be stopped by the starting Activity with a call to finishActivity(); - Starting a service - Context.startService() - Service's onStart() method is called by the system - Context.bindService() - Service's onBind() method is called by the system - bindService() can also optionally start the service - Can be stopped by calling stopSelf() or Context.stopService() - Starting (Sending) a broadcast - Context.sendBroadcast() - Also sendOrderedBroadcast(), sendStickyBroadcast() - onReceive() method receives the broadcast in BroadcastReceiver - Passing variables (extras) to intent receivers - Parcelable Manifest file - Always named AndroidManifest.xml - Tells Android of the application's components - Specifies libraries to link against - Specifies application permissions Activity stack Layout - XML / visual editor - ViewGroups - LinearLayout - RelativeLayout - TableLayout - GridLayout - Views (widgets) AlarmManager - Alarms are cleared on reboot -- describe how to solve this - Store the alarms in some persistent way - Create a BroadcastReceiver to receive bootup complete event - Register in manifest - Dialogs - Define in xml - onCreateDialog() Toasts - Toast.makeText(Context, String, int) Notifications - NotificationManager Menus - Options menu - Context menu - Submenus - Can be defined in code, or preferably, in xml (res/menu) - onCreateOptionsMenu() - Use MenuInflater to bring up the menu from resources - onOptionsItemSelected() - Handles options menu selection Resources - Layouts - Views & ViewGroups - Styles & themes - Strings - Colors - Defined in xml files (prefered way) or in code - Defining in xml separates layout from functionality, is a lot easier to change (also by persons not familiar with coding) - Designing for Architecture - http://developer.android.com/images/system-architecture.jpg Manifest file - Embedded into .apk - Always named AndroidManifest.xml - Contains information on - Application components (Activities, Services, BroadcastReceivers, ContentProviders) - Libraries to link against (other than android.jar) - Permissions the application requires (expects to be granted) - Activities, Services and ContentProviders MUST be declared in the manifest - Otherwise they're not known to the system - BroadcastReceivers can be declared in the manifest OR - Dynamically in code: Context.registerReceiver(); Intent filters - For implicit (i.e. not explicitly named) intents -- WHAT ARE THEY ANYWAY? PLEASE EXPLAIN. - For an implicit intent, the system goes through registered components in the manifest files of each application, and tries to find the best possible component to match the intent - In the manifest file, intent filters specify the criteria using which the implicit intents are compared. - There are no priorities; all applications are equal to each other when doing the filtering EXAMPLE (from LoanShark) - If you want to have an activity that acts as the entry point to the application (the first activity when the application is started), you need to have an intent filter with android.intent.action.MAIN as the action, and android.intent.category.LAUNCHER as the category: - This provides the application with a launcher icon (+label) - The icon must of course be specified as well - If a component doesn't have any intent filters, it can be only launched with an explicit intent IDEA FOR EXERCISE: An application where a component in a different application is started Task vs Application - An application is a set of components in the same package (and .apk) - A task is a user-perceived experience of an application - For example an APPLICATION may have just one activity, which opens a new activity belonging to a different application. The activity is seamlessly opened, and the user perceives both of the activities as belonging to the same application. This experience is a TASK. "Task is what the user experiences as the application. A group of related activities, arranged in a stack." - A task is a stack of activities that may belong to different applications - Back stack (http://developer.android.com/guide/topics/fundamentals/tasks-and-back-stack.html) - Activities cannot be rearranged, just pushed and popped - The task/activity stack can be moved to background as one cohesive unit when another task is brought to foreground (or when pressing HOME) - Activities are stopped, back stack remains intact - All activities are killable Task affinity - A preference for a set of ACTIVITIES to belong to the same TASK. - In manifest: - Intent: FLAG_ACTIVITY_NEW_TASK - Starts a new task (if no suitable task already exists) - Must be the one with intent-filter action=MAIN, category=LAUNCHER - Otherwise it will not have an icon and there's no way for the user to get back to the activity after leaving it - Activity attribute: allowTaskReparenting Launch modes (of activities) - standard - The default; a new activity is started each time - Activity belongs to the same task as the intent originator - singleTop - If there's an activity with the same class already at the top of the stack, the new existing activity handles the intent - Activity.onNewInstance() - Activity belongs to the same task as the intent originator - singleTask - Always the root activity of the task - Specifies that this activity starts a new task - Must be the one with intent-filter action=MAIN, category=LAUNCHER - Otherwise it will not have an icon and there's no way for the user to get back to the activity after leaving it - May have other activities on top of it in the activity stack - If the activity is not at the top of the stack when the intent arrives, - singleInstance - Always the root activity of the task - Specifies that this activity starts a new task - Must be the one with intent-filter action=MAIN, category=LAUNCHER - Otherwise it will not have an icon and there's no way for the user to get back to the activity after leaving it - The single and only activity in its task; if it starts another activity, it is launched into a new task Clearing a task of activities - If the user leaves a task on its own for extended periods of time, the system may pop all but the root activity off the stack. - This behavior can be altered by setting these flags in the root activity in the manifest file: - alwaysRetainTaskState (true/false) - All activities are retained on the stack, not popped by the system (HOW ABOUT IF MEMORY IS CRITICALLY LOW?) - clearTaskOnLaunch (true/false) - When the user returns to the task, the stack is cleared down to the root activity - always the initial state of the task - finishOnTaskLaunch - FLAG_ACTIVITY_CLEAR_TOP, FLAG_ACTIVITY_NEW_TASK Processes - By default, all of an application's components run in a single thread in a single process - In manifest, each component can specify a "process" attribute - E.g each component can run in its own process - Some components may share a process while others do not - Also, components of different applications can be set to run in the same process - The Linux user id MUST be the same - The components MUST be signed by the same authority - The element can set the process behavior to all elements, instead of having to specify each one individually - System calls (e.g. onKeyDown()) are handled by the main thread - Do not do long-running operations when handling system calls - If a long-running operation is needed, you can spawn a thread (or a service) Threads - Created in code using standard Java Thread objects - Looper: for running a message loop within a thread - Handler: for processing messages - HandlerThread: a thread with a message loop Q: The differences and common ground of threads and services? Remote procedure calls (RPCs) Timers Activity lifecycle - State change methods - onResume() - Called after onStart() - Called when the application comes to foreground - Activity has user focus after the call - onPause() - Called when the Activity loses user focus - E.g. when another activity is being started - Followed by onResume() or onStop() - Commonly used to save user data - After Activity has been paused, the system may finish() or kill it - Next Activity is not resumed until onPause() returns - The only method guaranteed to be called BEFORE the Activity is killed by the system (if so needed) - onStart() - Called just before the Activity goes on-screen - At this point the Activity is not necessarily at foreground! But it is visible. - Followed by onResume() - onStop() - Called after the Activity goes off-screen - onRestart() - Called after the Activity has been stopped - Followed by onStart() - onCreate(Bundle savedInstanceState) - All Activities must implement - Initial setup, e.g. setting layout - onDestroy() - The final call an Activity receives from the system - Called when either Activity's finish() has been called, or if the Activity is being killed - Can be checked in onDestroy() by calling isFinishing() - Lifecycle transition between two Activities: A.onPause() B.onCreate() B.onStart() B.onResume() A.onStop() // If A is no longer visible - After pausing or stopping an Activity, the system can finish() or kill it - onPause() is the only method guaranteed to be called before killing/finishing - Saving activity state - Activity.onSaveInstanceState(Bundle savedInstanceState) - Called BEFORE onPause() - NOT called when user presses Back - Only when the "the Activity becomes vulnerable to be killed by the system" - For example, pressing Home key, or receiving a phone call - IS called when Home pressed - Activity.onRestoreInstanceState(Bundle savedInstanceState) - Called when activity is started again, after with onStart() Service lifecycle - Service is STARTED by calling - Context.startService() - Context.bindService() // can also launch Service if not already started - Service is STOPPED by calling - Context.stopService() OR Service.stopSelf() OR Service.stopSelfResult() - Context.unbindService() - onCreate() - onStart(Intent intent) // Called only for Services started with startService() - onDestroy() BroadcastReceiver lifecycle - onReceive() - Must be completed quickly (executed in the main thread with UI) - I.e. no popup dialogs - After completion, the receiver is inactive - If a long-running task is required, a Service must be started - If a thread is started, it is inactivated after returning from onReceive() Process importance hierarchy 1. Foreground process - Required by the current user interaction - After Activity.onResume() is called - Hosts a service that is bound to the current activity - Can be e.g. in a different process than the activity - Has a Service executing its onCreate(), onStart() or onDestroy() - Has a BroadcastReceiver executing its onReceive() 2. Visible process - No foreground components, but still visible - Has an activity still that is still visible but whose onPause() has been called (e.g. a dialog activity (?) that only partially obscures the activity behind it) - Hosts a Service that is bound to a visible activity (whose onPause() has been called or not) - Only killed if required to keep all foreground processes running 3. Service process - Started with Context.startService() 4. Background process - Holds an Activity that is currently not visible (i.e. onStop() has been called). - Kept in a LRU (least recently used) list 5. Empty process - Holds no active components - Used as cache to improve startup times - "A process that is serving another process can never be ranked lower than the process it is serving." Setting OnCLickListeners and such Styles & Themes Fragments - http://blog.radioactiveyak.com/2011/02/strategies-for-honeycomb-and-backwards.html Retaining application state when orientation changes *** - onSaveInstanceState() - For saving "dynamic instance state" (not saving to storage) - onPause() is for saving "persistent data" to storage (e.g. DB) - Called before onDestroy() - Not called when Activity us being finished (Back pressed) - Not called when another Activity comes on top - Unless being killed due to lack of memory - Android calls this method automatically for every view with an id - Remember to call super.onSaveInstanceState() if you override this - Called before onStop() - Not guaranteed to be called before/after onPause() - onRestoreInstanceState() - Called after onCreate() - Android calls this method automatically for every view with an id - Remember to call super.onRestoreInstanceState() if you override this - Called between onStart() and onPostCreate() Localization Activity stack Activity states - Running / active - The foreground activity - Paused - Still visible, at least partly - Obscured by a non-fullscreen Activity or a dialog - Only killed if memory critically low - Stopped - Completely obscured by another activity - May be killed if memory is low - Entire lifetime: onCreate() - onDestroy() - Visible lifetime: onStart() - onStop() - Foreground lifetime: onResume() - onPause() Performance considerations - Application Not Responding (ANR) - For activities, after stalling the UI thread for 5 seconds - For BroadcastReceivers, after stalling 10 seconds - goAsync() (API level 11, i.e. Honeycomb) - How to prevent - Do not do long-running tasks on the UI thread - Spawn a background thread/service to do the work - Writing to disk is slow - Prefer to do writes in background Gestures Threading - AsyncTask - Handler - Looper - Runnable - android.app.IntentService - Example of usage, e.g. AudioRecord, MediaPlayer Fragments (Honeycomb and beyond) -