In this example MainActivity will start a DetailActivity and then expect a result from it. Each request type should have its own int request code, so that in the overriddenonActivityResult(int requestCode, int resultCode, Intent data) method in MainActivity , it can be determined which request to process by comparing values of requestCode and REQUEST_CODE_EXAMPLE (though in this example, there is only one).
MainActivity:
publicclassMainActivityextendsActivity{// Use a unique request code for each use case privatestaticfinalint REQUEST_CODE_EXAMPLE =0x9345;@OverrideprotectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// Create a new instance of Intent to start DetailActivityfinalIntent intent =newIntent(this,DetailActivity.class);// Start DetailActivity with the request codestartActivityForResult(intent, REQUEST_CODE_EXAMPLE);}// onActivityResult only get called // when the other Activity previously started using startActivityForResult@OverridepublicvoidonActivityResult(int requestCode,int resultCode,Intent data){super.onActivityResult(requestCode, resultCode, data);// First we need to check if the requestCode matches the one we used.if(requestCode == REQUEST_CODE_EXAMPLE){// The resultCode is set by the DetailActivity// By convention RESULT_OK means that whatever// DetailActivity did was executed successfullyif(resultCode ==Activity.RESULT_OK){// Get the result from the returned IntentfinalString result = data.getStringExtra(DetailActivity.EXTRA_DATA);// Use the data - in this case, display it in a Toast.Toast.makeText(this,"Result: "+ result,Toast.LENGTH_LONG).show();}else{// setResult wasn't successfully executed by DetailActivity // Due to some error or flow of control. No data to retrieve.}}}}
DetailActivity:
publicclassDetailActivityextendsActivity{// Constant used to identify data sent between Activities.publicstaticfinalString EXTRA_DATA ="EXTRA_DATA";@OverrideprotectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_detail);finalButton button =(Button)findViewById(R.id.button);// When this button is clicked we want to return a result
button.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(View view){// Create a new Intent object as container for the resultfinalIntent data =newIntent();// Add the required data to be returned to the MainActivity
data.putExtra(EXTRA_DATA,"Some interesting data!");// Set the resultCode as Activity.RESULT_OK to // indicate a success and attach the Intent// which contains our result datasetResult(Activity.RESULT_OK, data);// With finish() we close the DetailActivity to // return back to MainActivityfinish();}});}@OverridepublicvoidonBackPressed(){// When the user hits the back button set the resultCode // as Activity.RESULT_CANCELED to indicate a failuresetResult(Activity.RESULT_CANCELED);super.onBackPressed();}}
A few things you need to be aware of:
Data is only returned once you call `finish()`. You need to call `setResult()` before calling `finish()`, otherwise, no result will be returned.
Make sure your `Activity` is not using `android:launchMode="singleTask"`, or it will cause the `Activity` to run in a separate task and therefore you will not receive a result from it. If your `Activity` uses `singleTask` as launch mode, it will call `onActivityResult()` immediately with a result code of `Activity.RESULT_CANCELED`.
Be careful when using `android:launchMode="singleInstance"`. On devices before Lollipop (Android 5.0, API Level 21), Activities will not return a result.
You can use [explicit](https://developer.android.com/guide/components/intents-filters.html#ExampleExplicit) or [implicit](https://developer.android.com/guide/components/intents-filters.html#ExampleSend) intents when you call `startActivityForResult()`. When starting one of your own activities to receive a result, you should use an explicit intent to ensure that you receive the expected result.
An explicit `intent` is always delivered to its target, no matter what it contains; the `filter` is not consulted. But an implicit intent is delivered to a component only if it can pass through one of the component's filters.
Passing data between activities
This example illustrates sending a String with value as "Some data!" from OriginActivity to DestinationActivity.
NOTE: This is the most straightforward way of sending data between two activities. See the example on using the starter pattern(opens new window) for a more robust implementation.
OriginActivity
publicclassOriginActivityextendsAppCompatActivity{@OverrideprotectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_origin);// Create a new Intent object, containing DestinationActivity as target Activity.finalIntent intent =newIntent(this,DestinationActivity.class);// Add data in the form of key/value pairs to the intent object by using putExtra()
intent.putExtra(DestinationActivity.EXTRA_DATA,"Some data!");// Start the target Activity with the intent objectstartActivity(intent);}}
DestinationActivity
publicclassDestinationActivityextendsAppCompatActivity{publicstaticfinalString EXTRA_DATA ="EXTRA_DATA";@OverrideprotectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_destination);// getIntent() returns the Intent object which was used to start this ActivityfinalIntent intent =getIntent();// Retrieve the data from the intent object by using the same key that// was previously used to add data to the intent object in OriginActivity.finalString data = intent.getStringExtra(EXTRA_DATA);}}
Serializable is a standard Java interface. You simply mark a class as Serializable by implementing the Serializableinterface and Java will automatically serialize it during required situations.
Parcelable is an Android specific interface which can be implemented on custom data types (i.e. your own objects / POJO objects ), it allows your object to be flattened and reconstruct itself without the destination needing to do anything. There is a documentation example of making an object parcelable(opens new window).
Once you have a parcelable object you can send it like a primitive type, with an intent object:
and then also read it from the intent object at the destination as shown below:
finalSerializableType data =(SerializableType)bundle.getSerializable(EXTRA_DATA);
Open a URL in a browser
Opening with the default browser
This example shows how you can open a URL programmatically in the built-in web browser rather than within your application. This allows your app to open up a webpage without the need to include the INTERNET permission in your manifest file.
publicvoidonBrowseClick(View v){String url ="http://www.google.com";Uri uri =Uri.parse(url);Intent intent =newIntent(Intent.ACTION_VIEW, uri);// Verify that the intent will resolve to an activityif(intent.resolveActivity(getPackageManager())!=null){// Here we use an intent without a Chooser unlike the next examplestartActivity(intent);}}
publicvoidonBrowseClick(View v){String url ="http://www.google.com";Intent intent =newIntent(Intent.ACTION_VIEW,Uri.parse(url));// Note the Chooser below. If no applications match, // Android displays a system message.So here there is no need for try-catch.startActivity(Intent.createChooser(intent,"Browse with"));}
In some cases, the URL may start with "www". If that is the case you will get this exception:
android.content.ActivityNotFoundException : No Activity found to handle Intent
The URL must always start with "http://" or "https://". Your code should therefore check for it, as shown in the following code snippet:
Check if there are no apps on the device that can receive the implicit intent. Otherwise, your app will crash when it calls startActivity(). To first verify that an app exists to receive the intent, call resolveActivity() on your Intent object. If the result is non-null, there is at least one app that can handle the intent and it's safe to call startActivity(). If the result is null, you should not use the intent and, if possible, you should disable the feature that invokes the intent.
Starter Pattern
This pattern is a more strict approach to starting an Activity. Its purpose is to improve code readability, while at the same time decrease code complexity, maintenance costs, and coupling of your components.
The following example implements the starter pattern, which is usually implemented as a static method on the Activity itself. This static method accepts all required parameters, constructs a valid Intent from that data, and then starts the Activity.
An Intent is an object that provides runtime binding between separate components, such as two activities. The Intent represents an app’s "intent to do something." You can use intents for a wide variety of tasks, but here, your intent starts another activity.
publicclassExampleActivityextendsAppCompatActivity{privatestaticfinalString EXTRA_DATA ="EXTRA_DATA";publicstaticvoidstart(Context context,String data){Intent intent =newIntent(context,ExampleActivity.class);
intent.putExtra(EXTRA_DATA, data);
context.startActivity(intent);}@OverrideprotectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);Intent intent =getIntent();if(!intent.getExtras().containsKey(EXTRA_DATA)){thrownewUnsupportedOperationException("Activity should be started using the static start method");}String data = intent.getStringExtra(EXTRA_DATA);}}
This pattern also allows you to force additional data to be passed with the intent.
The ExampleActivity can then be started like this, where context is an activity context:
ExampleActivity.start(context,"Some data!");
Clearing an activity stack
Sometimes you may want to start a new activity while removing previous activities from the back stack, so the back button doesn't take you back to them. One example of this might be starting an app on the Login activity, taking you through to the Main activity of your application, but on logging out you want to be directed back to Login without a chance to go back. In a case like that you can set the FLAG_ACTIVITY_CLEAR_TOP flag for the intent, meaning if the activity being launched is already running in the current task (LoginActivity), then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.
It's also possible to use the flags FLAG_ACTIVITY_NEW_TASK along with FLAG_ACTIVITY_CLEAR_TASK if you want to clear all Activities on the back stack:
Intent intent =newIntent(getApplicationContext(),LoginActivity.class);// Closing all the Activities, clear the back stack.
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |Intent.FLAG_ACTIVITY_CLEAR_TASK);startActivity(intent);
Start an activity
This example will start DestinationActivity from OriginActivity.
Here, the Intent constructor takes two parameters:
A Context as its first parameter (this is used because the Activity class is a subclass of Context)
The Class of the app component to which the system should deliver the Intent (in this case, the activity that should be started)
publicclassOriginActivityextendsAppCompatActivity{@OverrideprotectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_origin);Intent intent =newIntent(this,DestinationActivity.class);startActivity(intent);finish();// Optionally, you can close OriginActivity. In this way when the user press back from DestinationActivity he/she won't land on OriginActivity again.}}
Another way to create the Intent to open DestinationActivity is to use the default constructor for the Intent, and use the setClass() method to tell it which Activity to open:
Intent i=newIntent();
i.setClass(this,DestinationActivity.class);startActivity(intent);finish();// Optionally, you can close OriginActivity. In this way when the user press back from DestinationActivity he/she won't land on OriginActivity
Sending emails
// Compile a Uri with the 'mailto' schemaIntent emailIntent =newIntent(Intent.ACTION_SENDTO,Uri.fromParts("mailto","[email protected]",null));// Subject
emailIntent.putExtra(Intent.EXTRA_SUBJECT,"Hello World!");// Body of email
emailIntent.putExtra(Intent.EXTRA_TEXT,"Hi! I am sending you a test email.");// File attachment
emailIntent.putExtra(Intent.EXTRA_STREAM, attachedFileUri);// Check if the device has an email clientif(emailIntent.resolveActivity(getPackageManager())!=null){// Prompt the user to select a mail appstartActivity(Intent.createChooser(emailIntent,"Choose your mail application"));}else{// Inform the user that no email clients are installed or provide an alternative}
This will pre-fill an email in a mail app of the user's choice.
If you need to add an attachment, you can use Intent.ACTION_SEND instead of Intent.ACTION_SENDTO. For multiple attachments you can use ACTION_SEND_MULTIPLE
A word of caution: not every device has a provider for ACTION_SENDTO, and calling startActivity() without checking with resolveActivity()(opens new window) first may throw an ActivityNotFoundException.
This is a good alternative to using a WebView for some cases. It allows loading of a web page with an Intent, with the added ability to inject some degree of the look and feel of your app into the browser.
Here is an example of how to open a url using CustomTabsIntent
This example shows how to open a default dialer (an app that makes regular calls) with a provided telephone number already in place:
Intent intent =newIntent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:9988776655"));//Replace with valid phone number. Remember to add the tel: prefix, otherwise it will crash.startActivity(intent);
Intents can be used to broadcast messages to other components of your application (such as a running background service) or to the entire Android system.
To send a broadcast within your application, use the LocalBroadcastManager class:
Intent intent =newIntent("com.example.YOUR_ACTION");// the intent action
intent.putExtra("key","value");// data to be passed with your broadcastLocalBroadcastManager manager =LocalBroadcastManager.getInstance(context);
manager.sendBroadcast(intent);
To send a broadcast to components outside of your application, use the sendBroadcast() method on a Context object.
Intent intent =newIntent("com.example.YOUR_ACTION");// the intent action
intent.putExtra("key","value");// data to be passed with your broadcast
context.sendBroadcast(intent);
It is also possible to pass your custom object to other activities using the Bundle(opens new window) class.
There are two ways:
Serializable interface—for Java and Android
Parcelable interface—memory efficient, only for Android (recommended)
Parcelable
Parcelable processing is much faster than serializable. One of the reasons for this is that we are being explicit about the serialization process instead of using reflection to infer it. It also stands to reason that the code has been heavily optimized for this purpose.
Intent sendIntent =newIntent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT,"This is my text to send.");
sendIntent.setType("text/plain");startActivity(Intent.createChooser(sendIntent,getResources().getText(R.string.send_to)));
Open Google map with specified latitude, longitude
You can pass latitude, longitude from your app to Google map using Intent
String uri =String.format(Locale.ENGLISH,"http://maps.google.com/maps?q=loc:%f,%f",28.43242324,77.8977673);Intent intent =newIntent(Intent.ACTION_VIEW,Uri.parse(uri));startActivity(intent);
Intent mIntent =getIntent();int intValue = mIntent.getIntExtra("intVariableName",0);// set 0 as the default value if no value for intVariableName found
Intent mIntent =getIntent();double doubleValue = mIntent.getDoubleExtra("doubleVariableName",0.00);// set 0.00 as the default value if no value for doubleVariableName found
publicvoidshowFileChooser(){Intent intent =newIntent(Intent.ACTION_GET_CONTENT);// Update with mime types
intent.setType("*/*");// Update with additional mime types here using a String[].
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);// Only pick openable and local files. Theoretically we could pull files from google drive// or other applications that have networked files, but that's unnecessary for this example.
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.putExtra(Intent.EXTRA_LOCAL_ONLY,true);// REQUEST_CODE = <some-integer>startActivityForResult(intent, REQUEST_CODE);}
Reading the Result
@OverrideprotectedvoidonActivityResult(int requestCode,int resultCode,Intent data){// If the user doesn't pick a file just returnif(requestCode != REQUEST_CODE || resultCode != RESULT_OK){return;}// Import the fileimportFile(data.getData());}publicvoidimportFile(Uri uri){String fileName =getFileName(uri);// The temp file could be whatever you wantFile fileCopy =copyToTempFile(uri,File tempFile)// Done!}/**
* Obtains the file name for a URI using content resolvers. Taken from the following link
* https://developer.android.com/training/secure-file-sharing/retrieve-info.html#RetrieveFileInfo
*
* @param uri a uri to query
* @return the file name with no path
* @throws IllegalArgumentException if the query is null, empty, or the column doesn't exist
*/privateStringgetFileName(Uri uri)throwsIllegalArgumentException{// Obtain a cursor with information regarding this uriCursor cursor =getContentResolver().query(uri,null,null,null,null);if(cursor.getCount()<=0){
cursor.close();thrownewIllegalArgumentException("Can't obtain file name, cursor is empty");}
cursor.moveToFirst();String fileName = cursor.getString(cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME));
cursor.close();return fileName;}/**
* Copies a uri reference to a temporary file
*
* @param uri the uri used as the input stream
* @param tempFile the file used as an output stream
* @return the input tempFile for convenience
* @throws IOException if an error occurs
*/privateFilecopyToTempFile(Uri uri,File tempFile)throwsIOException{// Obtain an input stream from the uriInputStream inputStream =getContentResolver().openInputStream(uri);if(inputStream ==null){thrownewIOException("Unable to obtain input stream from URI");}// Copy the stream to the temp fileFileUtils.copyInputStreamToFile(inputStream, tempFile);return tempFile;}
Sharing Multiple Files through Intent
The String List passed as a parameter to the share() method contains the paths of all the files you want to share.
It basically loops through the paths, adds them to Uri, and starts the Activity which can accept Files of this type.
public static void share(AppCompatActivity context,List<String> paths) {
if (paths == null || paths.size() == 0) {
return;
}
ArrayList<Uri> uris = new ArrayList<>();
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_SEND_MULTIPLE);
intent.setType("*/*");
for (String path : paths) {
File file = new File(path);
uris.add(Uri.fromFile(file));
}
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
context.startActivity(intent);
}
Start Unbound Service using an Intent
A Service is a component which runs in the background (on the UI thread) without direct interaction with the user. An unbound Service is just started, and is not bound to the lifecycle of any Activity.
To start a Service you can do as shown in the example below:
// This Intent will be used to start the serviceIntent i=newIntent(context,ServiceName.class);// potentially add data to the intent extras
i.putExtra("KEY1","Value to be used by the service");
context.startService(i);
You can use any extras from the intent by using an onStartCommand() override:
publicclassMyServiceextendsService{publicMyService(){}@OverridepublicintonStartCommand(Intent intent,int flags,int startId){if(intent !=null){Bundle extras = intent.getExtras();String key1 = extras.getString("KEY1","");if(key1.equals("Value to be used by the service")){//do something}}return START_STICKY;}@Nullable@OverridepublicIBinderonBind(Intent intent){returnnull;}}
In the following example ActivityOne contains FragmentOne, which will start ActivityTwo and expect a result from it.
ActivityOne
publicclassActivityOneextendsActivity{@OverrideprotectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_one);}// You must override this method as the second Activity will always send its results to this Activity and then to the Fragment@OverridepublicvoidonActivityResult(int requestCode,int resultCode,Intent data){super.onActivityResult(requestCode, resultCode, data);}}
publicclassFragmentOneextendsFragment{publicstaticfinalint REQUEST_CODE =11;publicstaticfinalint RESULT_CODE =12;publicstaticfinalString EXTRA_KEY_TEST ="testKey";// Initializing and starting the second ActivityprivatevoidstartSecondActivity(){Intent intent =newIntent(getActivity(),ActivityTwo.class);startActivityForResult(REQUEST_CODE, intent);}@OverridepublicvoidonActivityResult(int requestCode,int resultCode,Intent data){super.onActivityResult(requestCode, resultCode, data);if(requestCode == REQUEST_CODE && resultCode == RESULT_CODE){String testResult = data.getStringExtra(EXTRA_KEY_TEST);// TODO: Do something with your extra data}}}
ActivityTwo
publicclassActivityTwoextendsActivity{@OverrideprotectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_two);}privatevoidcloseActivity(){Intent intent =newIntent();
intent.putExtra(FragmentOne.EXTRA_KEY_TEST,"Testing passing data back to ActivityOne");setResult(FragmentOne.RESULT_CODE, intent);// You can also send result without any data using setResult(int resultCode)finish();}}
Additional options for how the Activity should be started
name
The name of the extra data
value
The value of the extra data
CHOOSE_CONTACT_REQUEST_CODE
the code of the request, to identify it on onActivityResult method
action
Any action to perform via this intent, ex: Intent.ACTION_VIEW
uri
data uri to be used by intent to perform specified action
packageContext
Context to use to initialize the Intent
cls
Class to be used by this intent
Remarks
Caveats of using implicit intent
When calling a implicit intent it's always helpful to check if it's possible by the system to handle it.
This can be done by checking using PackageManager.queryIntentActivities(Intent intent, int flags)
PackageManager pm =getActivity().getPackageManager();if(intent.resolveActivity(pm)!=null){//intent can be handledstartActivity(intent);}else{//intent can not be handled}
Starting Activity which is a singleTask or singleTop
When the activity's launch mode(opens new window) is singleTask or singleTop, the onActivityResult will be called as soon as the activity is started with a data null. To prevent this, use Intent.setFlags(0) to reset the default flags.