Android中的Intent是一個非常重要的類,如果對Intent不是特別了解,可以參見《詳解Android中Intent的使用方法》。如果對Intent Filter不是特別了解,可以參見《詳解Android中Intent對象與Intent Filter過濾匹配過程》。
本文著重講一下Android中一些常見的Intent的習慣用法,比如如何通過Intent發送短信、發送郵件、啟動攝像機拍照錄視頻、設置鬧鈴、打開WIFI設置界面等等。
限于篇幅,本文分為上下兩篇,這是上篇。
發送短信
發送短信的時候,我們要使用的action是Intent.ACTION_SENDTO,并且要指定其URI是smsto:協議,這樣能保證是短信應用接收并處理我們的intent對象,而不是其他應用接收,從而準確實現發送短信的目的。如果我們的action不是Intent.ACTION_SENDTO,而是Intent.ACTION_SEND,且沒有指定smsto:協議的URI的話,那么Android在接收到intent對象之后不會直接啟動短信應用,而是彈出了App Chooser,讓我們選擇要啟動哪個應用,比如電子郵件、QQ等等,所以為了確保直接啟動短信應用,我們應該使用Intent.ACTION_SENDTO并且指定smsto:協議的URI。
示例代碼如下:
//使用ACTION_SENDTO而不是ACTION_SENDIntent intent = new Intent(Intent.ACTION_SENDTO);//指定URI使用smsto:協議,協議后面是接收短信的對象Uri uri = Uri.parse("smsto:10086");intent.setData(uri);//設置消息體intent.putExtra("sms_body", "手頭有點緊,借點錢吧~~");ComponentName componentName = intent.resolveActivity(getPackageManager());if(componentName != null){ startActivity(intent);}在構造發送短信的URI時,前面是smsto:協議,后面跟的是接收短信的對方的手機號。如果在構建URI時,只寫了smsto:,而沒有寫后面的手機的號的話,那么該intent也可以成功啟動短信應用,不過這種情形下,在啟動了短信應用之后,還需要我們自己再手動輸入接收信息的手機號。我們通過key為sms_body的extra設置短信的內容。
需要注意的是,在執行了startActivity(intent)之后,雖然短信應用啟動了,但是短信沒有直接發出去,需要我們再點擊一下發送消息才可以。
發送郵件
發送郵件的時候,我們要使用的action也是Intent.ACTION_SENDTO,并且要指定其URI是mailto:協議,這樣能保證是郵件應用接收并處理我們的intent對象,而不是其他應用接收,從而準確實現發送郵件的目的。如果我們的action不是Intent.ACTION_SENDTO,而是Intent.ACTION_SEND,且沒有指定mailto:協議的URI的話,那么Android在接收到intent對象之后不會直接郵件應用,而是彈出了App Chooser,讓我們選擇要啟動哪個應用,比如短信、QQ等等,所以為了確保直接啟動郵件應用,我們應該使用Intent.ACTION_SENDTO并且指定mailto:協議的URI。
示例代碼如下:
//使用ACTION_SENDTO而不是ACTION_SENDIntent intent = new Intent(Intent.ACTION_SENDTO);//指定URI使用mailto:協議,確保只有郵件應用能接收到此intent對象Uri uri = Uri.parse("mailto:");intent.setData(uri);String[] addresses = {"zhangsan@126.com", "lisi@126.com"};String[] cc = {"boss@126.com"};String[] bcc = {"girlfriend@126.com"};String subject = "加班";String content = "國慶正常上班~~";//設置郵件的接收方intent.putExtra(Intent.EXTRA_EMAIL, addresses);//設置郵件的抄送方intent.putExtra(Intent.EXTRA_CC, cc);//設置郵件的密送方intent.putExtra(Intent.EXTRA_BCC, bcc);//設置郵件標題intent.putExtra(Intent.EXTRA_SUBJECT, subject);//設置郵件內容intent.putExtra(Intent.EXTRA_TEXT, content);//設置郵件附件//intent.putExtra(Intent.EXTRA_STREAM, Uri.parse(...));ComponentName componentName = intent.resolveActivity(getPackageManager());if(componentName != null){ startActivity(intent);}啟動郵件應用后的截圖如下所示:

我們分別通過key為Intent.EXTRA_EMAIL、Intent.EXTRA_CC和Intent.EXTRA_BCC的extra依次設置郵件的接收方、抄送方、密送方,其值均為String數組。我們通過key為Intent.EXTRA_SUBJECT的extra設置郵件標題,通過key為Intent.EXTRA_TEXT的extra設置郵件內容。如果想發送附件,那么可以將附件封裝成Uri的形式,然后通過key為Intent.EXTRA_STREAM的extra設置郵件附件。
需要注意的是,在執行了startActivity(intent)之后,雖然郵件應用啟動打開了,但是郵件沒有直接發出去,需要我們再點擊一下右上角的發送按鈕才能將郵件發出去。
打電話
要想通過Intent打電話,我們有兩個可以使用的action:Intent.ACTION_DIAL和Intent.ACTION_CALL,二者有一定的區別。
如果使用Intent.ACTION_DIAL作為intent對象的action,那么當執行startActivity(intent)之后,會啟動打電話應用,并且會自動輸入指定的手機號,但是不會自動撥打,需要我們手動按下撥打按鈕才能真正給對方打電話。
如果使用Intent.ACTION_CALL作為intent對象的action,那么當執行startActivity(intent)之后,會啟動打電話應用,并且直接撥打我們指定的手機號,無需我們再手動按下撥打按鈕。但是需要注意的是,該action需要權限android.permission.CALL_PHONE,如果在應用的AndroidManifest.xml文件中沒有添加該權限,那么當指定到startActivity(intent)這句代碼的時候,就會拋出異常,應用崩潰退出。
以下是示例代碼:
//Intent.ACTION_DIAL只撥號,不打電話//Intent intent = new Intent(Intent.ACTION_DIAL);//Intent.ACTION_CALL直接撥打指定電話,需要android.permission.CALL_PHONE權限Intent intent = new Intent(Intent.ACTION_CALL);Uri uri = Uri.parse("tel:10086");intent.setData(uri);ComponentName componentName = intent.resolveActivity(getPackageManager());if(componentName != null){ startActivity(intent);}在該示例代碼中,我們使用了Intent.ACTION_CALL作為intent對象的action,并且在AndroidManifest.xml中添加了如下權限:
拍照
要想通過Intent啟動攝像機進行拍照,我們需要設置intent對象的action值為MediaStore.ACTION_IMAGE_CAPTURE的action。然后我們用key為MediaStore.EXTRA_OUTPUT的extra設置圖片的輸出路徑,最后調用startActivityForResult()方法以啟動攝像機應用,并重寫我們的onActivityResult()以便在該方法中得知拍照完成。
示例代碼如下:
//表示用于拍照的requestCode private final int REQUEST_CODE_IMAGE_CAPTURE = 1; //我們存儲照片的輸出路徑,以便后續使用 private Uri imageOutputUri = null; //拍照 private void captureImage(){ PackageManager pm = getPackageManager(); //先判斷本機是否在硬件上有攝像能力 if(pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)){ Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); ComponentName componentName = intent.resolveActivity(pm); //判斷手機上有無攝像機應用 if(componentName != null){ //創建圖片文件,以便于通過Uri.fromFile()生成對應的Uri File imageFile = createImageFile(); if(imageFile != null){ //根據imageFile生成對應的Uri imageOutputUri = Uri.fromFile(imageFile); //利用該Uri作為拍照完成后照片的存儲路徑,注意,一旦設置了存儲路徑,我們就不能獲取縮略圖了 intent.putExtra(MediaStore.EXTRA_OUTPUT, imageOutputUri); //調用startActivityForResult()方法,以便在onActivityResult()方法中進行相應處理 startActivityForResult(intent, REQUEST_CODE_IMAGE_CAPTURE); }else{ Toast.makeText(this, "無法創建圖像文件!", Toast.LENGTH_LONG).show(); } }else{ Toast.makeText(this, "未在本機找到Camera應用,無法拍照!", Toast.LENGTH_LONG).show(); } }else{ Toast.makeText(this, "本機沒有攝像頭,無法拍照!", Toast.LENGTH_LONG).show(); } } //創建圖片文件,以便于通過Uri.fromFile()生成對應的Uri private File createImageFile(){ File image = null; //用時間戳拼接文件名稱,防止文件重名 String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "JPEG_" + timeStamp + "_"; File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); try{ image = File.createTempFile( imageFileName, //前綴 ".jpg", //后綴 storageDir //文件夾 ); }catch (IOException e){ image = null; e.printStackTrace(); Log.e("DemoLog", e.getMessage()); } return image; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { //首先判斷是否正確完成 if(resultCode == RESULT_OK){ switch (requestCode){ case REQUEST_CODE_IMAGE_CAPTURE: //此處,我們可以通過imageOutputUri獲取到我們想要的圖片 String imagePath = imageOutputUri.toString(); Log.i("DemoLog", "照片路徑是: " + imagePath); Toast.makeText(this, "照片路徑是: " + imagePath, Toast.LENGTH_LONG).show(); //以下代碼嘗試獲取縮略圖 //如果設置MediaStore.EXTRA_OUTPUT作為extra的時候,那么此處的intent為null,需要判斷 if(intent != null){ Bitmap thumbnail = intent.getParcelableExtra("data"); //有的手機并不會給拍照的圖片生成縮略圖,所以此處也要判斷 if(thumbnail != null){ Log.i("DemoLog", "得到縮略圖"); } } default: break; } } }我們分析一下上面的代碼片段:
不是所有的Android設備都能拍照的,所以首先我們調用了PackageManager的hasSystemFeature(PackageManager.FEATURE_CAMERA)方法,判斷當前設備在硬件層級是否具有拍照的能力。
然后我們創建了一個action為MediaStore.ACTION_IMAGE_CAPTURE的intent對象。
然后我們通過調用intent.resolveActivity(pm)方法判斷當前設備有無攝像機應用以便我們啟動。如果沒有攝像機應用但是我們卻把intent對象傳遞給startActivity()或startActivityForResult()的話,就會拋出異常,應用崩潰退出。
我們自己寫了一個createImageFile方法,通過該方法我們在自己的應用所對應的外設存儲卡上創建了一個圖片文件。需要注意的是,此步驟需要WRITE_EXTERNAL_STORAGE權限,在AndroidManifest.xml中注冊如下:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18"></uses-permission>
我們利用上面生成的圖片文件生成了對應的Uri,將其存儲在Activity中類型為Uri的字段imageOutputUri中,之后我們執行了intent.putExtra(MediaStore.EXTRA_OUTPUT, imageOutputUri),利用該Uri作為拍照完成后照片的存儲路徑。
此處需要特別注意的是,一旦設置了存儲路徑,我們就不能在onActivityResult()中獲取縮略圖了。
最后我們需要調用方法startActivityForResult(intent, REQUEST_CODE_IMAGE_CAPTURE)以啟動攝像機應用進行拍照,其中REQUEST_CODE_IMAGE_CAPTURE是我們自定義指定的用于拍照的requestCode。
我們覆寫了onActivityResult方法,拍照完成后觸發該方法的執行。首先我們要判斷resultCode是否與RESULT_OK相等,只有相等才表明拍照成功,然后我們判斷如果requestCode是否等于REQUEST_CODE_IMAGE_CAPTURE,若相等表明是拍照返回的結果。那么此時,我們就可以通過我們之前存儲的imageOutputUri獲取剛剛拍完的照片了,其URI字符串如:
file:///storage/sdcard0/Android/data/com.ispring.commonintents/files/Pictures/JPEG_20150919_112704_533002075.jpg
需要注意的是,如果我們在第5步之中設置MediaStore.EXTRA_OUTPUT作為照片輸出路徑的話,那么在onActivityResult中無法獲取從攝像機應用換回的Intent,即為null,這樣也就無法獲取縮略圖。反之,如果在第5步沒有設置MediaStore.EXTRA_OUTPUT作為照片輸出路徑的話,intent不為空,可以嘗試執行Bitmap thumbnail = intent.getParcelableExtra("data")獲取縮略圖,如果thumbnail不為空,表示能成功獲取縮略圖。但是有的手機并不會給拍照的圖片生成縮略圖,所以此處的thumbnail也有可能是null,所以在使用之前要先判斷。
攝像
通過Intent啟動攝像機進行攝像的步驟與上面剛提到的通過Intent啟動攝像機進行拍照的步驟非常相似,稍有區別。要啟動Camera進行攝像,我們需要給intent設置值為MediaStore.ACTION_VIDEO_CAPTURE的action,然后我們用key為MediaStore.EXTRA_OUTPUT的extra設置圖片的輸出路徑,最后調用startActivityForResult()方法以啟動攝像機應用,并重寫我們的onActivityResult()以便在該方法中得知攝像完成。
以下是示例代碼:
//表示用于錄視頻的requestCode private final int REQUEST_CODE_VIDEO_CAPTURE = 2; //我們存儲視頻的輸出路徑,以便后續使用 private Uri videoOutputUri = null; //攝像 private void captureVideo(){ PackageManager pm = getPackageManager(); //先判斷本機是否在硬件上有攝像能力 if(pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)){ //將intent的action設置為MediaStore.ACTION_VIDEO_CAPTURE Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); ComponentName componentName = intent.resolveActivity(pm); //判斷手機上有無攝像機應用 if(componentName != null){ //創建視頻文件,以便于通過Uri.fromFile()生成對應的Uri File videoFile = createVideoFile(); if(videoFile != null){ //根據videoFile生成對應的Uri videoOutputUri = Uri.fromFile(videoFile); //利用該Uri作為攝像完成后視頻的存儲路徑 intent.putExtra(MediaStore.EXTRA_OUTPUT, videoOutputUri); //調用startActivityForResult()方法,以便在onActivityResult()方法中進行相應處理 startActivityForResult(intent, REQUEST_CODE_VIDEO_CAPTURE); }else{ Toast.makeText(this, "無法創建視頻文件!", Toast.LENGTH_LONG).show(); } }else{ Toast.makeText(this, "未在本機找到Camera應用,無法攝像!", Toast.LENGTH_LONG).show(); } }else{ Toast.makeText(this, "本機沒有攝像頭,無法攝像!", Toast.LENGTH_LONG).show(); } } //創建視頻文件,以便于通過Uri.fromFile()生成對應的Uri private File createVideoFile(){ File videoFile = null; //用時間戳拼接文件名稱,防止文件重名 String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "MP4" + timeStamp + "_"; File storageDir = getExternalFilesDir(Environment.DIRECTORY_MOVIES); try{ videoFile = File.createTempFile( imageFileName, //前綴 ".mp4", //后綴 storageDir //文件夾 ); }catch (IOException e){ videoFile = null; e.printStackTrace(); Log.e("DemoLog", e.getMessage()); } return videoFile; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { //首先判斷是否正確完成 if(resultCode == RESULT_OK){ switch (requestCode){ case REQUEST_CODE_VIDEO_CAPTURE: //如果設置MediaStore.EXTRA_OUTPUT作為extra的時候, //在有的手機上,此處的intent為不為null,但是在有的手機上卻為null, //所以不建議從intent.getData()中獲取視頻路徑 //我們應該自己記錄videoOutputUri來得知視頻路徑,下面注釋的代碼不建議使用 /*if(intent != null){ Uri videoUri = intent.getData(); if(videoUri != null){ //路徑格式如content://media/external/video/media/130025 Log.i("DemoLog", "視頻路徑是: " + videoUri.toString()); } }*/ String videoPath = videoOutputUri.toString(); //1.如果沒有設置MediaStore.EXTRA_OUTPUT作為視頻文件存儲路徑,那么路徑格式如下所示: // 路徑格式如content://media/external/video/media/130025 //2.如果設置了MediaStore.EXTRA_OUTPUT作為視頻文件存儲路徑,那么路徑格式如下所示: // 路徑格式如file:///storage/sdcard0/Android/data/com.ispring.commonintents/files/Movies/MP420150919_184132_533002075.mp4 Log.i("DemoLog", "視頻路徑是: " + videoPath); Toast.makeText(this, "視頻路徑是: " + videoPath, Toast.LENGTH_LONG).show(); break; default: break; } } }可以看到上面啟動Camera攝像的代碼與拍照的代碼幾乎完全一樣,具體解釋參見對拍照代碼的描述。在該示例代碼中,我們通過MediaStore.EXTRA_OUTPUT設置了視頻的存放路徑,拍照的時候我們也通過它設置了照片的輸出路徑,但是二者稍有區別:
以上就是關于Android中常見Intent習慣用法,希望對大家的學習有所幫助。
附源碼: 《Android中Intent習慣用法》
新聞熱點
疑難解答
圖片精選