學(xué)習(xí)安卓開發(fā)[4] - 使用隱式Intent啟動(dòng)短信奕巍、聯(lián)系人侦讨、相機(jī)應(yīng)用

在上一篇學(xué)習(xí)安卓開發(fā)[3] - 使用RecyclerView顯示列表中了解了在進(jìn)行列表展示時(shí)RecyclerView的使用驶冒,本次記錄的是在應(yīng)用中如何通過隱式Intent調(diào)用其它應(yīng)用的功能,比如發(fā)短信韵卤、打電話骗污、拍照等

  • 隱式Intent
  • 短信
    • 判斷是否存在相關(guān)APP
  • 相機(jī)
    • FileProvider
    • Bitmap
    • 功能聲明

隱式Intent

Intent對(duì)象用來向操作系統(tǒng)說明需要處理的任務(wù)。使用顯式Intent時(shí)沈条,要指定操作系統(tǒng)需要啟動(dòng)的activity需忿,但使用隱式intent,只需告知操作系統(tǒng)想要進(jìn)行的操作蜡歹,系統(tǒng)就會(huì)啟動(dòng)能完成該操作的activity屋厘,如果有多個(gè)符合條件的activity,會(huì)提供用戶一個(gè)應(yīng)用列表供選擇
Android是如何通過隱式intent找到并啟動(dòng)合適應(yīng)用的呢月而?原因在于配置文件中的itent過濾器設(shè)置汗洒,比如我們也想開發(fā)一款短信應(yīng)用,那么可以在AndroidMainfest的activity聲明中這樣設(shè)置:

<activity android:name=".CrimeListActivity">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

隱式Intent的組成部分有
1)要執(zhí)行的操作父款,通常以Intent類中的常量來表示溢谤,比如訪問URL可以使用Intent.ACTION_VIEW,發(fā)送郵件使用Intent.ACTION_SEND
2)待訪問數(shù)據(jù)的位置憨攒,這可能是設(shè)備以外的資源世杀,如某個(gè)網(wǎng)頁(yè)的URL,某個(gè)文件的URI
3)操作涉及的數(shù)據(jù)類型肝集,如text/html, audio/mpeg3等
4)可選類別瞻坝,用來描述對(duì)activity的使用方式

短信

那么要啟動(dòng)短信的隱式intent的方法為:

mReportButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Intent i = new Intent(Intent.ACTION_SEND);
        i.setType("text/plain");
        i.putExtra(Intent.EXTRA_TEXT, getCrimeReport());
        i.putExtra(Intent.EXTRA_SUBJECT,
                getString(R.string.crime_report_suspect));
        i = Intent.createChooser(i, getString(R.string.send_report));
        startActivity(i);
    }
});

首先指定發(fā)送消息的操作名為ACTION_SEND,然后消息內(nèi)容為文本,所以設(shè)置數(shù)據(jù)類型為text/plain杏瞻,要發(fā)送的文本通過Extra的形式提供

判斷是否存在相關(guān)APP

使用隱式intent時(shí)所刀,如果系統(tǒng)沒有安裝對(duì)應(yīng)的軟件衙荐,應(yīng)用就會(huì)奔潰,所以有必要在使用隱式intent時(shí)勉痴,檢查一下能夠找到對(duì)應(yīng)的軟件赫模,如果沒找到,就避免再去發(fā)生相關(guān)的隱式intent

final Intent pickContact = new Intent(Intent.ACTION_SEND);
PackageManager packageManager = getActivity().getPackageManager();
    if (packageManager.resolveActivity(pickContact, PackageManager.MATCH_DEFAULT_ONLY) == null) {
        mReportButton.setEnabled(false);
}

通過PackageManager可以搜索需要的activity的信息蒸矛,flag標(biāo)志MATCH_DEFAULT_ONLY限定只搜索帶CATEGORY_DEFAULT的activity瀑罗,如果沒有找到,就禁用發(fā)短信按鈕雏掠。

相機(jī)

如果所開發(fā)的APP有拍照功能斩祭,就可以使用系統(tǒng)相機(jī)了。拍攝的照片要保存在設(shè)備文件系統(tǒng)乡话,但這就涉及到私有存儲(chǔ)空間的問題摧玫。出于安全考慮,無法使用公共外部存儲(chǔ)轉(zhuǎn)存绑青,那么如果想共享文件給其他應(yīng)用诬像,或者接收其他應(yīng)用的文件(如相機(jī)拍攝的照片),可以使用ContentProvider把要共享的文件臨時(shí)暴露出來闸婴。對(duì)于接受相機(jī)拍攝的照片這樣的場(chǎng)景坏挠,系統(tǒng)提供的現(xiàn)成的FileProvider類。

FileProvider

要使用FileProvider類邪乍,需要在AndroidMainfest中添加聲明降狠。
首先添加files.xml文件

<paths>
    <files-path
        name="crime_photos"
        path="."/>
</paths>

這個(gè)描述性文件把私有存儲(chǔ)空間的根路徑映射為crime_photos,這個(gè)名字僅供FileProvider自己使用庇楞。
然后添加FileProvider聲明:

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.example.zhixin.crimeintent.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/files" />
</provider>

通過這段聲明榜配,提供了一個(gè)文件保存地,相機(jī)拍攝的照片就可以放在這里了吕晌。exported="false"表示除了應(yīng)用自己和給予授權(quán)的應(yīng)用蛋褥,其它的不允許使用這個(gè)FileProvider,grantUriPermissions="true"表示允許其他應(yīng)用向指定文職的URI寫入文件睛驳。

接下來就可以實(shí)現(xiàn)拍照功能了

mPhotoButton = (ImageButton) v.findViewById(R.id.crime_camera);
final Intent captureImage = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
boolean canTakePhoto = mPhotoFile != null &&
        captureImage.resolveActivity(packageManager) != null;
mPhotoButton.setEnabled(canTakePhoto);

mPhotoButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Uri uri = FileProvider.getUriForFile(getActivity(),
                "com.example.zhixin.crimeintent.fileprovider", mPhotoFile);
        captureImage.putExtra(MediaStore.EXTRA_OUTPUT, uri);

        List<ResolveInfo> cameraActivities = getActivity().getPackageManager().queryIntentActivities(captureImage,
                PackageManager.MATCH_DEFAULT_ONLY);

        for (ResolveInfo activity : cameraActivities) {
            getActivity().grantUriPermission(activity.activityInfo.packageName,
                    uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        }

        startActivityForResult(captureImage,REQUEST_PHOTO);
    }
});

mPhotoView = (ImageView) v.findViewById(R.id.crime_photo);

通過給所有目標(biāo)activity授予Intent.FLAG_GRANT_WRITE_URI_PERMISSION權(quán)限壁拉,允許它們?cè)赨RI指定的位置寫入文件。mPhotoFile表示拍攝生成照片的名稱柏靶。

在相機(jī)拍攝完成后的回調(diào)方法中,取消之前的Intent.FLAG_GRANT_WRITE_URI_PERMISSION授權(quán)溃论,并加載顯示照片屎蜓。

Uri uri=FileProvider.getUriForFile(getActivity(),
        "com.example.zhixin.crimeintent.fileprovider",
        mPhotoFile);
getActivity().revokeUriPermission(uri,Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
updatePhotoView();
Bitmap

在顯示照片時(shí)還有一些工作要做。顯示照片要用到Bitmap钥勋,而Bitmap只存儲(chǔ)實(shí)際像素?cái)?shù)據(jù)炬转,即使是已經(jīng)壓縮過的照片辆苔,存入Bitmap后,文件并不會(huì)同樣壓縮扼劈,比如一張1600萬像素24位的相機(jī)照片存為JPG格式約為5MB驻啤,但載入Bitmap后就會(huì)達(dá)到48MB左右。
要解決這個(gè)問題荐吵,需要手動(dòng)縮放位圖照片骑冗。首先確認(rèn)文件大小,然后根據(jù)要顯示照片的區(qū)域大小合理縮放文件先煎,最后重新讀取縮放后的文件贼涩,再創(chuàng)建Bitmap對(duì)象。

public class PictureUtils {
    public static Bitmap getScaledBitmap(String path, int destWidth, int destHeight) {
        // Read in the dimensions of the image on disk
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);

        float srcWidth = options.outWidth;
        float srcHeight = options.outHeight;

        // Figure out how much to scale down by
        int inSampleSize = 1;
        if (srcHeight > destHeight || srcWidth > destWidth) {
            float heightScale = srcHeight / destHeight;
            float widthScale = srcWidth / destWidth;

            inSampleSize = Math.round(heightScale > widthScale ? heightScale :
                    widthScale);
        }

        options = new BitmapFactory.Options();
        options.inSampleSize = inSampleSize;

        // Read in and create final bitmap
        return BitmapFactory.decodeFile(path, options);
    }
}

還有一個(gè)問題是在Fragment.OnCreateView里面加載照片的時(shí)候薯蝎,無法知道要顯示照片的尺寸遥倦,只有onCreate, onStart, onResume方法執(zhí)行過后,才會(huì)有首個(gè)實(shí)例化布局出現(xiàn)占锯。對(duì)于這種情況袒哥,可以根據(jù)Fragment所在的Activity尺寸確定屏幕的尺寸,按照屏幕尺寸縮放圖像消略。所以再添加一個(gè)getScaledBitmap的重載:

public static Bitmap getScaledBitmap(String path, Activity activity) {
    Point size = new Point();
    activity.getWindowManager().getDefaultDisplay()
            .getSize(size);
    return getScaledBitmap(path, size.x, size.y);
}

最后在OnCreateView和相機(jī)的回調(diào)方法更新照片堡称。

功能聲明

既然APP需要用到拍照功能,但像拍照疑俭、NFC粮呢、紅外等并不是每個(gè)設(shè)備都有,所以進(jìn)行功能聲明钞艇,從而可以在應(yīng)用前讓用戶知道啄寡,如果設(shè)備缺少某項(xiàng)必須功能,應(yīng)用商店會(huì)拒絕安裝應(yīng)用哩照。
在AndroidMainfest中添加:

<uses-feature
    android:name="android.hardware.camera"
    android:required="false">
</uses-feature>

android:required="false"表示不強(qiáng)制拍照功能挺物,因?yàn)槿绻O(shè)備沒有相機(jī),會(huì)禁掉拍照按鈕飘弧。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末识藤,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子次伶,更是在濱河造成了極大的恐慌痴昧,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冠王,死亡現(xiàn)場(chǎng)離奇詭異赶撰,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門豪娜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來餐胀,“玉大人,你說我怎么就攤上這事瘤载》裨郑” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵鸣奔,是天一觀的道長(zhǎng)墨技。 經(jīng)常有香客問我,道長(zhǎng)溃蔫,這世上最難降的妖魔是什么健提? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮伟叛,結(jié)果婚禮上私痹,老公的妹妹穿的比我還像新娘。我一直安慰自己统刮,他們只是感情好紊遵,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著侥蒙,像睡著了一般暗膜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鞭衩,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天学搜,我揣著相機(jī)與錄音,去河邊找鬼论衍。 笑死瑞佩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的坯台。 我是一名探鬼主播炬丸,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼蜒蕾!你這毒婦竟也來了稠炬?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤咪啡,失蹤者是張志新(化名)和其女友劉穎首启,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體撤摸,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡毅桃,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年栽惶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疾嗅。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖冕象,靈堂內(nèi)的尸體忽然破棺而出代承,到底是詐尸還是另有隱情,我是刑警寧澤渐扮,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布论悴,位于F島的核電站,受9級(jí)特大地震影響墓律,放射性物質(zhì)發(fā)生泄漏膀估。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一耻讽、第九天 我趴在偏房一處隱蔽的房頂上張望察纯。 院中可真熱鬧,春花似錦针肥、人聲如沸饼记。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)具则。三九已至,卻和暖如春具帮,著一層夾襖步出監(jiān)牢的瞬間博肋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工蜂厅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留匪凡,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓葛峻,卻偏偏與公主長(zhǎng)得像锹雏,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子术奖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容