Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
CS499 – Mobile Application Development Fall 2013 Programming the Android Platform Activities & Intents Activity • Provides a visual interface • Typically supports one thing a user can do – View an email message – Show a login screen • Applications can include several activities • Only one activity can have ‘focus’ at a time. Other activities are paused or stopped. Tasks • Set of related activities • Android manages an activity ‘back stack’ – Launching an activity pushes it onto the stack – Hitting the back button pops the top activity off the stack, deleting it. Task Stack Activity States • Not started – not yet created • Active – Resumed/Running – visible, has focus – Paused – visible, does not have focus, can be terminated – Stopped – not visible, can be terminated • Finished Activity Lifecycle Android communicates state changes to application by calling specific lifecycle methods: protected void onCreate() protected void onStart() protected void onResume() protected void onPause() protected void onRestart() protected void onStop() protected void onDestroy() onCreate() • protected void onCreate(Bundle savedInstanceState) • Called when Activity is first being created • Must be defined by the activity • Setup global state: – call super.onCreate() – inflate UI views – Configure views Activity functions • All must call super.<fn>() • protected void onStart() Called when the activity starts. • protected void onRestart() Called if the activity has been stopped and is about to be started again. Update any saved info. • protected void onResume() – return to ‘focus’. Restart foreground effects Activity functions • protected void onPause() – focus is switching to another activity. Shut down foreground resources. • protected void onStop() – Activity no longer visible but might be used again eventually. Can save state in case destroyed. • protected void onDestroy() – removed from back stack. Save any important data and release any held resources. public class ExampleActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // The activity is being created. } @Override protected void onStart() { super.onStart(); // The activity is about to become visible. } @Override protected void onResume() { super.onResume(); // The activity has become visible (it is now "resumed"). } @Override protected void onPause() { super.onPause(); // Another activity is taking focus (this activity is about to be "paused"). } @Override protected void onStop() { super.onStop(); // The activity is no longer visible (it is now "stopped") } @Override protected void onDestroy() { super.onDestroy(); // The activity is about to be destroyed. } } Example: Pause/Resume @Override public void onPause() { super.onPause(); // Always call the superclass method first // Release the Camera because we don't need it when paused // and other activities might need to use it. if (mCamera != null) { mCamera.release() mCamera = null; } } @Override public void onResume() { super.onResume(); // Always call the superclass method first // Get the Camera instance as the activity achieves full user focus if (mCamera == null) { initializeCamera(); // Local method to handle camera init } } Example: Stop @Override protected void onStop() { super.onStop(); // Always call the superclass method first // Save the note's current draft, because the activity is stopping // and we want to be sure the current note progress isn't lost. ContentValues values = new ContentValues(); values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText()); values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle()); … } Example: Start or Restart @Override protected void onStart() { super.onStart(); // Always call the superclass method first // The activity is either being restarted or started for the first time // so this is where we should make sure that GPS is enabled LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); boolean gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); if (!gpsEnabled) { // Create a dialog here that requests the user to enable GPS, and use an intent // with the android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS action // to take the user to the Settings screen to enable GPS when they click "OK" } } Activity Lifetime • Entire lifetime – from onCreate() to onDestroy() • Visible lifetime – from onStart() to onStop() • Foreground (focus) lifetime – from onResume() to onPause() Configuration Changes • Device configuration can change at runtime – orientation, locale, etc. • On configuration changes, Android typically kills & restarts the current activity – Basic UI information is saved automatically. – Hard to recompute data can be saved & restored explicitly. Example: saving state static final String STATE_SCORE = "playerScore"; static final String STATE_LEVEL = "playerLevel"; ... @Override public void onSaveInstanceState(Bundle savedInstanceState) { // Save the user's current game state savedInstanceState.putInt(STATE_SCORE, mCurrentScore); savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel); // Always call the superclass so it can save the view hierarchy state super.onSaveInstanceState(savedInstanceState); } Example: restoring state @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Always call the superclass first // Check whether we're recreating a previously destroyed instance if (savedInstanceState != null) { // Restore value of members from saved state mCurrentScore = savedInstanceState.getInt(STATE_SCORE); mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL); } else { // Probably initialize members with default values for a new instance } ... } Starting New Activities • Create an Intent object specifying the activity to start – Can be explicit (by name) or implicit (by purpose) • Pass newly created Intent to one of the following: – startActivity() – startActivityForResult() The Intent Class • An Intent is a data structure that specifies – An operation to be performed – An event that has occurred • Broadcast by one component • Received by 0 or more components • This lecture focuses on using intents to represent operations rather than events. Example: Explicit public class MyAppActivity extends Activity { public final static String EXTRA_MESSAGE = "cs499.examples.myapp.MESSAGE"; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } /** Called when the user selects the Send button */ public void sendMessage(View view) { Intent intent = new Intent(this, DisplayMessageActivity.class); EditText editText = (EditText) findViewById(R.id.edit_message); String message = editText.getText().toString(); intent.putExtra(EXTRA_MESSAGE, message); startActivity(intent); } } public class DisplayMessageActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Get the message from the intent Intent intent = getIntent(); String message = intent.getStringExtra(MyAppActivity.EXTRA_MESSAGE); // Create the text view TextView textView = new TextView(this); textView.setTextSize(40); textView.setText(message); setContentView(textView); } // when this activity finishes, it is popped from the stack } <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cs499.examples.myapp" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="15" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name=".MyAppActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".DisplayMessageActivity" /> </application> </manifest> Getting Results from Activities • startActivityForResult() – Implement onActivityResult() callback method – When the activity is done, it will return the result in an intent to your callback – onActivityResult() – handles this return event – Note: If the current activity can start multiple activities returning values, the returns are all handled with a single onActivityResult() method. Example: getting return values static final int PICK_CONTACT_REQUEST = 1; // The request code ... private void pickContact() { Intent pickContactIntent = new Intent(Intent.ACTION_PICK, new Uri("content://contacts")); pickContactIntent.setType(Phone.CONTENT_TYPE); // Show user only contacts w/ phone numbers startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // Check which request we're responding to if (requestCode == PICK_CONTACT_REQUEST) { // Make sure the request was successful if (resultCode == RESULT_OK) { // The user picked a contact. // The Intent's data Uri identifies which contact was selected. // Do something with the contact here } } } More complete Example • Main activity – gets two integers and sends these to the second activity on a button press. When data arrives back, print out this • Second activity – started by another activity, receives two strings that represent integers. On a button press, adds the integers and returns the result. AndroidManifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cs499.examples.intentexample" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name=".IntentExampleActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".ActivityA" /> </application> </manifest> main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="First Activity" /> <EditText android:layout_width="fill_parent“ android:layout_height="wrap_content“ android:hint="Enter an integer" android:id="@+id/input1” /> <EditText android:layout_width="fill_parent“ android:layout_height="wrap_content“ android:hint="Enter an integer“ android:id="@+id/input2” /> <Button android:layout_width="fill_parent“ android:layout_height="wrap_content" android:text="Update int“ android:onClick="sendMessage“ /> <TextView android:layout_width="fill_parent“ android:layout_height="wrap_content" android:id="@+id/result” /> </LinearLayout> Step 1 – create Main Activity package cs499.examples.intentexample; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.EditText; import android.widget.TextView; public class IntentExampleActivity extends Activity { // parameters for the new activity public void sendMessage(View view) { // Create an intent to send values in response to button Intent intent = new Intent(this, ActivityA.class); String s1 = mVal1.getText().toString(); if (s1.length() != 0) intent.putExtra(ActivityA.PARAM1, s1); else intent.putExtra(ActivityA.PARAM1,"0"); String s2 = mVal2.getText().toString(); if (s2.length() != 0) intent.putExtra(ActivityA.PARAM2, s2); else intent.putExtra(ActivityA.PARAM2,"0"); public final int ACTIVITY_RESULT = 1; private TextView mResultText; private EditText mVal1, mVal2; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mResultText=(TextView)findViewById(R.id.result); mVal1 =(EditText)findViewById(R.id.input1); mVal2=(EditText)findViewById(R.id.input2); } startActivityForResult(intent,ACTIVITY_RESULT); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == ACTIVITY_RESULT) { String address = data.getExtras(). getString(ActivityA.RETVAL); mResultText.setText(address); } } } Step 2 – User presses button in Main Activity package cs499.examples.intentexample; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.EditText; import android.widget.TextView; public class IntentExampleActivity extends Activity { // parameters for the new activity public void sendMessage(View view) { // Create an intent to send values in response to button Intent intent = new Intent(this, ActivityA.class); String s1 = mVal1.getText().toString(); if (s1.length() != 0) intent.putExtra(ActivityA.PARAM1, s1); else intent.putExtra(ActivityA.PARAM1,"0"); String s2 = mVal2.getText().toString(); if (s2.length() != 0) intent.putExtra(ActivityA.PARAM2, s2); else intent.putExtra(ActivityA.PARAM2,"0"); public final int ACTIVITY_RESULT = 1; private TextView mResultText; private EditText mVal1, mVal2; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mResultText=(TextView)findViewById(R.id.result); mVal1 =(EditText)findViewById(R.id.input1); mVal2=(EditText)findViewById(R.id.input2); } startActivityForResult(intent,ACTIVITY_RESULT); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == ACTIVITY_RESULT) { String address = data.getExtras(). getString(ActivityA.RETVAL); mResultText.setText(address); } } } Step 3 - Second Activity starts package cs499.examples.intentexample; import import import import import android.app.Activity; android.content.Intent; android.os.Bundle; android.view.View; android.widget.TextView; public class ActivityA extends Activity { public final static String RETVAL = "cs499.examples.activitya.RETVAL"; public final static String PARAM1 = "cs499.examples.activitya.P1"; public final static String PARAM2 = "cs499.examples.activitya.P2"; private TextView mInt1, mInt2; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // get parameters from the calling activity Intent intent = getIntent(); String str1 = intent.getStringExtra(IntentExampleActivity. PARAM1); String str2 = intent.getStringExtra(IntentExampleActivity. PARAM2); // Create the text view using the input values setContentView(R.layout.main_c); mInt1 = (TextView) findViewById(R.id.start1); mInt1.setText(str1); mInt2 = (TextView) findViewById(R.id.start2); mInt2.setText(str2); } public void sendMessage(View view) { // Do something in response to button int v1 = Integer.parseInt(mInt1.getText().toString()); int v2 = Integer.parseInt(mInt2.getText().toString()); String result = Integer.toString(v1+v2); Intent intent = new Intent(); intent.putExtra(STRVAL,result ); // Set result and finish this Activity setResult(Activity.RESULT_OK, intent); finish(); } } main_c.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent” android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent” android:layout_height="wrap_content" android:text="Second Activity" /> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/start1" /> <TextView android:layout_width="fill_parent” android:layout_height="wrap_content" android:id="@+id/start2" /> <Button android:layout_width="fill_parent“ android:layout_height="wrap_content" android:text="Return Result“ android:onClick="sendMessage“ /> </LinearLayout> Step 4 – button press in Second Activity package cs499.examples.intentexample; import import import import import android.app.Activity; android.content.Intent; android.os.Bundle; android.view.View; android.widget.TextView; public class ActivityA extends Activity { public final static String RETVAL = "cs499.examples.activitya.RETVAL"; public final static String PARAM1 = "cs499.examples.activitya.P1"; public final static String PARAM2 = "cs499.examples.activitya.P2"; private TextView mInt1, mInt2; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // get parameters from the calling activity Intent intent = getIntent(); String str1 = intent.getStringExtra(IntentExampleActivity. PARAM1); String str2 = intent.getStringExtra(IntentExampleActivity. PARAM2); // Create the text view using the input values setContentView(R.layout.main_c); mInt1 = (TextView) findViewById(R.id.start1); mInt1.setText(str1); mInt2 = (TextView) findViewById(R.id.start2); mInt2.setText(str2); } public void sendMessage(View view) { // Do something in response to button int v1 = Integer.parseInt(mInt1.getText().toString()); int v2 = Integer.parseInt(mInt2.getText().toString()); String result = Integer.toString(v1+v2); Intent intent = new Intent(); intent.putExtra(STRVAL,result ); // Set result and finish this Activity setResult(Activity.RESULT_OK, intent); finish(); } } Step 5 – return to Main Activity package cs499.examples.intentexample; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.EditText; import android.widget.TextView; public class IntentExampleActivity extends Activity { // parameters for the new activity public void sendMessage(View view) { // Create an intent to send values in response to button Intent intent = new Intent(this, ActivityA.class); String s1 = mVal1.getText().toString(); if (s1.length() != 0) intent.putExtra(ActivityA.PARAM1, s1); else intent.putExtra(ActivityA.PARAM1,"0"); String s2 = mVal2.getText().toString(); if (s2.length() != 0) intent.putExtra(ActivityA.PARAM2, s2); else intent.putExtra(ActivityA.PARAM2,"0"); public final int ACTIVITY_RESULT = 1; private TextView mResultText; private EditText mVal1, mVal2; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mResultText=(TextView)findViewById(R.id.result); mVal1 =(EditText)findViewById(R.id.input1); mVal2=(EditText)findViewById(R.id.input2); } startActivityForResult(intent,ACTIVITY_RESULT); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == ACTIVITY_RESULT) { String address = data.getExtras(). getString(ActivityA.RETVAL); mResultText.setText(address); } } } Implicit Intents Often used to use components from existing applications: • Uri number = Uri.parse("tel:5551234"); Intent callIntent = new Intent(Intent.ACTION_DIAL, number); • Uri webpage = Uri.parse("http://www.android.com"); Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage); • Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI); Calendar beginTime = Calendar.getInstance().set(2012, 0, 19, 7, 30); Calendar endTime = Calendar.getInstance().set(2012, 0, 19, 10, 30); calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis()); calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis()); calendarIntent.putExtra(Events.TITLE, "Ninja class"); calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo"); Intent Resolution • When the activity to be activated is not named, the system attempts to find activities that match the intent • Only matches on – Action – Data (both URI and mime data type) – Category Intent Actions • String representing the operation • Examples: • new Intent(Intent.ACTION_VIEW) • Intent newInt = new Intent(); newInt.setAction(Intent.ACTION_VIEW); Intent Category • Additional information about the components to handle the intent • Examples: Intent Data • Data associated with the Intent – Formatted as a Uniform Resource Identifier (URI) • Examples: – Data to view on a map • geo:0,0?q=1600+Pennsylvania+Ave+Washington+DC – Number to dial on the phone • tel:+15555555555 Intent Data • Setting the Intent Data • new Intent(Intent.ACTION_CALL, Uri.parse(tel:+15555555555)); • Intent newInt = new Intent(Intent.ACTION_CALL); newInt.setData(Uri.parse(tel:+15555555555)); • Additional information associated with the intent – Treated as a map (key-value pairs) • Setting the Extra attribute – Several forms depending on data type • putExtra(String name, String value): • putExtra(String name, float[] value); •… Intent Type • Sets MIME type of the intent data – for example, “image/*” • If unspecified, Android will infer the type • Intent.setType(String type) • Intent.setDataAndType(Uri data, String type) Implicit Intents • Usually necessary to verify that there is at least one component capable of handling the intent: • Intent mapIntent = new Intent(Intent.ACTION_VIEW, location); PackageManager packageManager = getPackageManager(); List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0); boolean isIntentSafe = activities.size() > 0; if (isIntentSafe) startActivity(mapIntent);