320 likes | 544 Views
Intents and Intent Filters Aim: A llow apps to be composed of smaller units that do not have to be loaded in memory all the time.
E N D
Intents and Intent Filters Aim: • Allow apps to be composed of smaller units that do not have to be loaded in memory all the time. • Provide a generic mechanism so Activities can be started implicitly (i.e. without specifying exactly which Activity should be started) or explicitly (effectively specifying which Activity to start) Means: • Activities have Intent Filters that specify the actions that an Activity can perform • Activities can create Intents that specify which actions need to be performed on behalf of the Activity • Android matches Intents and Intent Filters
Intents and Intent Filters Intents and intent filters provide a generic way to start activities. Why would we want this? • Divide your program into smallish activities to reduce the load (scarce memory) • Do some background processing An intent is an abstract description of an operation to be performed. To start an activity (either from same app or from different app) from another activity, create an instance i of the Intent class and execute (this == current activity) this.startActivity(i); Activities have intent filters, usually specified in the manifest. Android creates instances of the IntentFilter class from this. When this.startActivity(i)is executed, Android searches for an activity that is installed on your device with an intent filter that matches the intent i. This activity is then started. If not found, an exception is thrown.
Android will search the Intent Filters of all installed Apps!
Example of an intent filter (show in Eclipse) HelloActivity Manifest: This action that says that this activity can be started as a main activity that is started without input This category tells Android to add the activity to the launcher screen so it can be launched from there Demo: show whathappensif action/category is missing
Example of starting an activity from another activity (1) Simplest way to do this: explicit intent PersonListActivity (treated later) has Intent Filter with action name as shown below (added especially to enable starting it this way) When adding the action: drop-down list with predefined actions or, as in this case, create your own specific action name
Example of starting an activity from another activity (2) Notice that there are two Intent Filters. Each intent filter has its own specific purpose In this case: one that has the same function as the one of the HelloActivity one to start it with an explicit intent Note: when adding a second activity to an app, one needs to add the activity node and intent filters manually to the Manifest!
Example of starting an activity from another activity (3) StartPersonListActivity instantiates an Intent with the action name and then calls startActivity Intent i = new Intent("nl.tue.win.intent.action.ShowPersonList"); this.startActivity(i); This tells Android to start the activity with this action name in the intent filter Demo: StartPersonList (Notice: if PersonList is not installed yet, StartPersonList crashes if you don’t catch the exception!)
Example of starting an activity from another activity (4) Other ways to start an activity with an explicit intent: • specify context and class name • specify package and class name Both bypass the intent filter matching mechanism, so no intent filter needed Examples (only for reference): i.setClass(Context,Class); //same app if Context = this i.setClassName(packageName,className); i.setComponent(new ComponentName(packageName, className));
Steps to start an activity from another one with an explicit intent: • Add an Intent Filter in the activity you want to start, with • an action that is an arbitrary string s (but choose a meaningful name!) and • a DEFAULT category • If needed: add a piece of code in the onCreate method of the activity that is started like Intent i = this.getIntent(); if(i.getAction().equals(s)){ // piece of code relevant only if // started with this explicit intent ... } In the activity from which you start the other activity: • Intent i = new Intent(s); • … // maybe pass some data (discussed later) • this.startActivity(i);
Passing data between activities With methods i.putExtra(String name,...), it is also possible to pass any data to the Activity started. Here, … can be almost any type, e.g., String, int[], float, … The started Activity can access the data by first getting hold of the Intent it was started with: Intent i = this.getIntent(); Then it can get the extra data with i.getXXXExtra(String name) where XXX stands for String, IntArray, Float, etc. (must of course match the type passed to it!)
Use of putExtraand getXXXExtra: The stringname is used to index a particular item, much like an array index In contrast to array, the types passed can be different So Intent i = ...; //Declaration of data structure //handled in Intent class i.putExtra("stringToPass", "Bonjour"); i.putExtra("value", 4); String s = i.getStringExtra("stringToPass"); int j = i.getIntExtra("value"); inta[] = new int[10]; a[4] = 4; a[5] = 5; int b = a[4]; int c = a[5];
More powerful ways to start an activity need categories: implicit intents Intents and intent filters consist of 3 components • Actions • Specifies what needs to be done (e.g., edit, view, pick) • Several actions may be specified for an activity • Categories • Give additional information about the action • several categories can be supplied • Data* • Data to operate on, can be • Scheme, e.g., http: • Mime type, e.g., text (discussed later) *: Do not confuse this data with the data passed with putExtra(...)!!!
Actions Aim: abstract description of a task Means: • add Action to Intent Filter • create an Intent and set the action either as parameter in the constructor or with the method setAction of the Intent class Examples of standard actions: • ACTION_MAIN start activity as a main activity – no input or output expected • ACTION_VIEW view something specified by uri passed as data • ACTION_EDIT edit something specified by the uri passed as data • ACTION_PICK choose an item from the set specified by the uri passed as data • ACTION_DIAL dial a number specified by the uri passed as data • ACTION_SENDTO send a message to someone as specified by uri passed as data • ACTION_DELETE delete the item specified by the uri passed as data
Categories (1) Aim: give additional information about the action(s) Means: • add category to Intent Filter • Add category to Intent with addCategory(String category); Normally, one can use CATEGORY_DEFAULTin the Intent Filter A few other standard categories: CATEGORY_HOME:the home activity, the first activity that is displayed when the device boots CATEGORY_TEST:test activity CATEGORY_ALTERNATIVE: alternative for an activity the user is currently viewing, e.g., print view instead of normal view (useful for context menus) CATEGORY_LAUNCHER: should be displayed in the launcher screen (after one runs HelloWorld from Eclipse, it can be found on the launcher screen) New categories can be defined as needed
Categories (2) An Intent Filter does not need to specify a category If an Intent Filter does not specify a category, the Intent must not specify one either If an Intent is created with, e.g., Intent i = new Intent("nl.tue.win.intent.action.ShowPersonList"); its category is set to Intent.CATEGORY_DEFAULT If the Intent Filter of the activity to be started does not specify a category, the category must be removed with i.removeCategory(Intent.CATEGORY_DEFAULT); Otherwise the starting app crashes when this.startActivity(i) is executedand no matching activity is found Specifying a default category in the intent filter is simpler…
Data (1) Aim: specify the data a task must operate on Means: • Specify the data type in the Intent Filter • Specify the uri of the data in the Intent Data in an intent filter can either be a scheme, e.g., http, mailto, tel Or a Multipurpose Internet Mail Extensions (MIME) type, an internet standard for text in character sets other than ASCII (rtf), but also for images (jpeg), video, audio. Mime types are specified by a type and a subtype (format: type/subtype, e.g., text/html ) Can be a standard mime type or a custom mime type for use with Android only Mime types must always be given in lower case
Data (2) Custom mime type always has format that starts with vnd.android.cursor.dir(multiple items)orvnd.android.cursor.item(single item) Examples of mime types (examples how to use follow): • custom vendor-specific subtype: vnd.android.cursor.dir/vnd.google.noteand vnd.android.cursor.item/vnd.google.note • simple subtype vnd.android.cursor.dir/phone_v2 and vnd.android.cursor.item/phone_v2 Example of Intent Filter: Notepad
Examples of Intent Filters and Intents (1) Example of an Intent Filter that specifies a scheme: The Intent Filter specifies that the activity • shows something (VIEW) • can be safely invoked from a browser (BROWSABLE) • expects a uri that is a web address Intent Filter matches if the data in the Intentis set to a URL accessed via the http protocol, but not one accessed with the https protocol
Examples of Intent Filters and Intents (2) Example of starting activity implicitly, with data – a scheme: Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.tue.nl")); startActivity(i); Uri.parse takes the string and returns an instance of the Uri class Android will look among all installed apps for intent filters that specify “http” in the data element (see previous slide) Notice: both an action and data (http scheme) are used in creation of the intent; because the filter specifies that it handles http, Android can match the intent with the filter Demo: StartBrowser – notice how, when back is pressed, the top activity is deleted and the previous activity is now on top (activity stack)
Examples of Intent Filters and Intents (3) Example of an intent filter that specifies a mime type (collection): In this case, the Intent Filter of the NotesList activity specifies that it supports the following actions on a collection (first part of the mime type specifies dir) of the custom mime type vnd.google.note: • View the collection • Edit the collection • Choose one item of the collection (for editing)
Examples of Intent Filters and Intents (4) Example of starting an activity with an implicit Intent that specifies a collection of notes Intent i = new Intent(Intent.ACTION_EDIT); i.setType("vnd.android.cursor.item/vnd.google.note"); i.setData(Uri.parse("content://com.google.provider.NotePad/notes")); this.startActivity(i); The uri passed in setDataspecifies that the edit action is to take place on a collection of notes provided by the content provider identified by com.google.provider.NotePad The intent can be matched to the Intent Filter of NotesList because • the edit action occurs in the Intent Filter • the mime type of the data can be matched to the mime type in the Intent Filter • The uri passed refers to the collection, not to a single note The call to setType is not really necessary as the type can be inferred from the uri; NotesList also starts if only the setType call is made Demo: StartNotepad
Note: The activity with this filter uses a ContentResolver to get hold of its ContentProvider, in this case a part of the same app which stores the notes. Subsequently it retrieves that data from the provider. The match with the provider is made based on the URI and the Authority specified in the Provider node in the manifest The URI is passed to the provider, which uses a UriMatcher(must be provided by the ContentProvider itself) to translate the URI to the actual location of the data in the file system or in a database .
Examples of Intent Filters and Intents (5) Example of an Intent Filter that specifies a mime type (single item): In this case, the Intent Filter of the NoteEditoractivity specifies that it supports the following actions on a single item (first part of the mime type specifies item) of the custom mime type vnd.google.note: • View the note • Edit the note (the EDIT_NOTE action only appears in the Manifest) • Choose one item of the collection (for editing)
Examples of Intent Filters and Intents (6) Example of starting an activity with an implicit Intent that specifies a single note Intent i = new Intent(Intent.ACTION_EDIT); i.setType("vnd.android.cursor.item/vnd.google.note"); Uri uri = Uri.parse("content://com.google.provider.NotePad/notes/3"); i.setData(uri); this.startActivity(i); The uri passed in setDataspecifies that the edit action is to take place on a single note provided by the content provider identified by com.google.provider.NotePad The intent can be matched to the Intent Filter of NoteEditor because • the edit action occurs in the Intent Filter • the mime type of the data can be matched to the mime type in the Intent Filter • The uri passed refers to a single note The call to setType is not really necessary as the type can be inferred from the uri; in this case, the uri is essential as it identifies the note to edit Demo: GetNotes
Matching of Intents and Intent Filters An intent matches an intent filter if (at runtime): • The action in the Intent matches one of the actions in the Intent Filter • All categories in the Intent are specified in the Intent Filter • If data is supplied in the Intent it matches the data in the Intent Filter (see next slide) Ad 1. and 2.: Intent.ACTION_XXXXas specified in the Intent is matched to the action with nameandroid.intent.action.XXXXin the Intent Filter (same with categories) If an Intent matches different activities, Android lets the user choose, e.g., if you want to start a browser and more than one browser is installed
Matching Intents and Intent Filters: data test The data test compares both the URI and the data type in the Intent object to a URI and data type specified in the filter. The rules are as follows (from Android documentation): • An Intent object that contains neither a URI nor a data type passes the test only if the filter likewise does not specify any URIs or data types. • An Intent object that contains a URI but no data type (and a type cannot be inferred from the URI) passes the test only if its URI matches a URI in the filter and the filter likewise does not specify a type. This will be the case only for URIs like mailto: and tel: that do not refer to actual data. • An Intent object that contains a data type but not a URI passes the test only if the filter lists the same data type and similarly does not specify a URI. • An Intent object that contains both a URI and a data type (or a data type can be inferred from the URI) passes the data type part of the test only if its type matches a type listed in the filter. It passes the URI part of the test either if its URI matches a URI in the filter or if it has a content: or file: URI and the filter does not specify a URI. In other words, a component is presumed to support content: and file: data if its filter lists only a data type.
Passing data between activities – continued (1) • Starting an activity with this.startActivity(intent) offers no opportunity to get data back from the activity started • Useful for, e.g., opening a text document that the user can read and subsequently close when finished, after which the user returns to the original activity • Sometimes, one needs data produced by the activity that was started – possible with startActivityForResult(intent,requestCode) First activity: Intent i = new Intent(Intent.ACTION_EDIT); // maybe use an Intent filter of your own // choice - for this one Android will // return a list of possible editors // pass data <data> of any type identify it with key <name> i.putExtra(<requestkeyname>,<data>); // start the activity with startACtivityForResult this.startActivityForResult(i,<requestCode>); // requestCode is an arbitrary integer
Passing data between activities – continued (2) At the side of the activity that was started: // inspect the Intent we were started with Intent i = this.getIntent(); if( Intent.ACTION_EDIT.equals(i.getAction())){ // check that we received <requestkeyname> String msg = i.getStringExtra(<requestkeyname>); // do something relevant with msg // and return some data i.putExtra(<replykey>, <data>); // set result code to OK (constant of this class) //and pass the (modified) intent this.setResult(RESULT_OK, i); // the finish call causes a callback to the calling activity finish(); }
Passing data between activities – continued (3) The method startActivityForResult and the call to finish() result in a callback to the function onActivityResult, in which the data returned can be accessed (example will be given later) public void onActivityResult(intrequestCode, intresultCode, Intent data){ super.onActivityResult(requestCode, resultCode, data); // check if the request code matches and the result is OK if(requestCode == <requestCode> && resultCode == RESULT_OK){ // get the value that the called Activity returned String s = data.getStringExtra(<replykey>); } } For data types other than String, there are methods like getIntExtra, getDoubleExtra, etc. Demo: Exercise 11.1 Notice that using startActivity(i) in both these activities instead can be used to pass data, but then the data returned from the second activity is not passed to the original activity but to a new instance of this activity!
Switching screens Possibility to show another part of the UI without starting another activity (remaining within the same activity). “Why” is on next slide. public class ScreenSwitcher extends Activity { ...// layout set to main.xml in onCreate public void onBackClicked(View v){ setContentView(R.layout.main); } public void onOtherClicked(View v){ setContentView(R.layout.otherscreen); } } Demo: ScreenSwitcher
Switch screen or start new Activity? So, in the PersonList app, we could have made a second screen with the AddPerson functionality. Obviously, starting another activity in PersonList is not very useful. When one has e.g. some background calculations that need not execute continuously but that do require considerable amounts of resources or if one has a complex application it would be a very good idea. Which solution is more appropriate depends on the situation. Cooperating small activities/apps are of course less likely to exhaust the resources of the physical device than one big one that implements all functionality in one activity. Cooperating small activities is also what the designers of Android intended Question: were they right to assume resource constraints? Compare to Windows NT: PCs were not powerful enough when NT was developed… But, of course, there was no equivalent of earlier Windows versions to secure a market segment…