響應(yīng)通知,訪問(wèn)相冊(cè)和播放音視頻

日常手機(jī)使用中,常常會(huì)遇到頭部彈出一條新消息,有的還伴隨著震動(dòng),音樂(lè)以及燈光閃爍,它們是怎么實(shí)現(xiàn)的呢?許多app的個(gè)人設(shè)置頁(yè)面都有頭像設(shè)置的功能,一般都有使用者從相冊(cè)中選取或者立即拍照兩種選擇.很多時(shí)候,app中也會(huì)有播放音視頻的功能.它們都是如何實(shí)現(xiàn)的呢?

1通知

通過(guò)通知,能夠在app打開(kāi),但是被切換到后臺(tái)時(shí),及時(shí)通知用戶(hù)app的變化.發(fā)送通知類(lèi)似啟動(dòng)Activity,只不過(guò)啟動(dòng)對(duì)象換成了PendingIntent,用于啟動(dòng)通知時(shí)對(duì)Intent進(jìn)行再次封裝.示例如下:

Intent intent = new Intent(this, NotificationActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Notification notification = new NotificationCompat.Builder(this)
        .setContentTitle("this is title")
        .setContentText("this is text")  
        .setStyle(new  NotificationCompat.BigPictureStyle().bigPicture(BitmapFactory.decodeResource(
                getResources(), R.drawable.banana
        )))
        .setPriority(NotificationCompat.PRIORITY_HIGH)
        .setWhen(System.currentTimeMillis())
        .setSmallIcon(R.drawable.left)
        .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
        .setContentIntent(pi)
        //設(shè)置通知的取消
        .setAutoCancel(true)
        //設(shè)置聲音
        .setSound(Uri.fromFile(new File("/system/media/audio/ringtones/Luna.ogg")))
        //設(shè)置震動(dòng)
        .setVibrate(new  long[] {0, 1000, 1000, 1000})
        //設(shè)置閃光燈
        .setLights(Color.GREEN, 1000, 1000)
        .build();
notificationManager.notify(2, notification);

示例中PendingIntent中需要四個(gè)參數(shù),第一個(gè)參數(shù)是上下文context,第三個(gè)參數(shù)是封裝的Intent,第一/四個(gè)參數(shù)一般傳入0即可.

2拍照和訪問(wèn)相冊(cè)

我們可以把常見(jiàn)的場(chǎng)景簡(jiǎn)化成如下圖的效果.

拍照和訪問(wèn)相冊(cè)

點(diǎn)擊TAKE PHOTO調(diào)用相機(jī)功能拍照,并將拍攝成功的照片設(shè)置給下面的ImageView.點(diǎn)擊CHOOSE_FROM_ALBUM啟動(dòng)相冊(cè),將選擇的照片設(shè)置給下面的ImageView.

按照布局-處理邏輯的思路,先在layout中添加Button和ImageView的組件.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button_photo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Take photo"
        android:layout_gravity="center"
         />

    <Button
        android:id="@+id/choose_from_album"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="choose_from_album"
        android:layout_gravity="center"
        />

    <ImageView
        android:id="@+id/imageView_picture"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"/>

</LinearLayout>

點(diǎn)擊TAKE PHOTO后,調(diào)用相機(jī)功能.

public  static final int TAKE_PHOTO = 1;
private ImageView picture;
private Uri imageUri;

 Button button_photo = (Button)findViewById(R.id.button_photo);
 picture = (ImageView)findViewById(R.id.imageView_picture);

  button_photo.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        File outputImage = new File(getExternalCacheDir(), "output_image.jpg");
        try {
            if (outputImage.exists()){
                outputImage.delete();
            }
            outputImage.createNewFile();
        }catch (IOException e){
            e.printStackTrace();
        }
        if (Build.VERSION.SDK_INT >= 24){
            imageUri = FileProvider.getUriForFile(MainActivity.this, "com.example.zhudong.cameraalbumtest.file" +
                    "provider", outputImage);
        }else {
            imageUri = Uri.fromFile(outputImage);
        }
        Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        startActivityForResult(intent, TAKE_PHOTO);
    }

調(diào)用相機(jī)通過(guò)匿名Intent,傳入action名稱(chēng)android.media.action.IMAGE_CAPTURE后,系統(tǒng)會(huì)自動(dòng)識(shí)別.在intent傳入imageUri存儲(chǔ)拍照成功照片.在onActivityResult中對(duì)存儲(chǔ)的照片進(jìn)行處理.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode){
        case TAKE_PHOTO:
        if (resultCode == RESULT_OK) {
            try {
                Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
                picture.setImageBitmap(bitmap);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
            break;
        default:
            break;
    }
}

點(diǎn)擊CHOOSE_FROM_ALBUM后調(diào)用相冊(cè)功能.

Button button_choose = (Button)findViewById(R.id.choose_from_album);
button_choose.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
        }else {
            openAlbum();
        }
    }
});
private void openAlbum(){
    Intent intent = new Intent("android.intent.action.GET_CONTENT");
    intent.setType("image/*");
    startActivityForResult(intent, CHOOSE_ALBUM);
}

調(diào)用相冊(cè)實(shí)質(zhì)是讀SD卡,屬于Android系統(tǒng)的危險(xiǎn)權(quán)限,使用之前需要申請(qǐng).在onRequestPermissionsResult中對(duì)申請(qǐng)結(jié)果進(jìn)行處理.

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    switch (requestCode){
        case 1:
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                openAlbum();
            }else {
                Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();
            }
            break;
        default:
            break;
    }
}

類(lèi)似啟動(dòng)相機(jī)功能,調(diào)用相冊(cè)也是通過(guò)匿名Intent的方式.在onActivityResult的回調(diào)中可以得到選擇的圖片.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
   switch (requestCode){
       case CHOOSE_ALBUM:
           if (resultCode == RESULT_OK){
               if (Build.VERSION.SDK_INT >= 19){
                   handleImageOnKitKat(data);
               }else {
                   handleImageBeforeKitKat(data);
               }
           }
       default:
           break;
   }
}

@TargetApi(19)
private void handleImageOnKitKat(Intent data) {
   String imagePath = null;
   Uri uri = data.getData();
   if (DocumentsContract.isDocumentUri(this, uri)) {
       String id = DocumentsContract.getDocumentId(uri);
       if ("com.android.providers.media.documents".equals(uri.getAuthority())){
           String id1 = id.split(":")[1];
           String selection = MediaStore.Images.Media._ID + "=" + id1;
           imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
       }else if("com.android.providers.downloads.documents".equals(uri.getAuthority())){
           Uri contentUri = ContentUris.withAppendedId(Uri.parse("conent://downloads/public_downloads"), Long.valueOf(id));
           imagePath = getImagePath(contentUri, null);
       }
   }else if("content".equalsIgnoreCase(uri.getScheme())) {
       imagePath = getImagePath(uri,null);
   }else if("file".equalsIgnoreCase(uri.getScheme())) {
       imagePath = uri.getPath();
   }
   displayImage(imagePath);
}
private void handleImageBeforeKitKat(Intent data) {
   Uri uri = data.getData();
   String imagePath = getImagePath(uri, null);
   displayImage(imagePath);
}
private String getImagePath(Uri uri, String selection) {
   String path = null;
   Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
   if (cursor != null){
       if (cursor.moveToFirst()){
           path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
       }
       cursor.close();
   }
   return path;
}
private void displayImage(String imagePath) {
   if (imagePath !=null){
       Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
       picture.setImageBitmap(bitmap);
   }else {
       Toast.makeText(MainActivity.this, "U don't choose album", Toast.LENGTH_SHORT).show();
   }
}

Android4.4以后對(duì)回調(diào)的Uri進(jìn)行了封裝,需要通過(guò)getContentResolver進(jìn)一步處理.所以通過(guò)Android版本和19的比較,對(duì)回調(diào)的Uri進(jìn)行了handleImageOnKitKat和handleImageBeforeKitKat不同的處理.

3播放音視頻

播放音頻通過(guò)MediaPlayer類(lèi)來(lái)實(shí)現(xiàn),可以很方便的控制音頻的開(kāi)始,暫停和重新播放.

public class MainActivity extends AppCompatActivity {

//    private MediaPlayer mediaPlayer = new MediaPlayer();
    private MediaPlayer mediaPlayer;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);

        }else {
            initMediaPlayer();
        }
    }

    private void initMediaPlayer(){
        try{
//            File file = new File(Environment.getExternalStorageDirectory(), "music.mp3");
//             ;
//            mediaPlayer.setDataSource(file.getPath());
            mediaPlayer =  MediaPlayer.create(this, R.raw.voa);
            mediaPlayer.prepare();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode){
            case 1:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    initMediaPlayer();
                }else {
                    Toast.makeText(MainActivity.this, "U don't permission", Toast.LENGTH_SHORT).show();
                    finish();
                }
                break;
            default:
        }
    }

    public void play(View v){
        if (!mediaPlayer.isPlaying()){
            mediaPlayer.start();
        }

    }
    public void pause(View v){
        if (mediaPlayer.isPlaying()){
            mediaPlayer.pause();
        }
    }
    public void stop(View v){
        if (mediaPlayer.isPlaying()){
            mediaPlayer.reset();
            initMediaPlayer();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mediaPlayer != null){
            mediaPlayer.stop();
            mediaPlayer.release();
        }
    }
}

播放音頻,也需要申請(qǐng)權(quán)限.并且在onDestroy中需要釋放掉MediaPlayer初始化時(shí)占用的資源.

播放視頻通過(guò)VideoView來(lái)實(shí)現(xiàn).因?yàn)閂ideoView是對(duì)MediaPlayer進(jìn)行的封裝,所以使用方式和播放音頻非常類(lèi)似,只不過(guò)在重置時(shí)調(diào)用的是resume方法;OnDestroy中釋放資源時(shí),調(diào)用suspend的方法.

public class MainActivity extends AppCompatActivity {

    private VideoView videoView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        videoView = (VideoView)findViewById(R.id.videoView);
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) ==
                PackageManager.PERMISSION_GRANTED){
            initVideoView();
        }else {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    1);
        }
    }

    private void initVideoView(){

        File file = new File(Environment.getExternalStorageDirectory(), "movie.mp4");
        videoView.setVideoPath(file.getPath());

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode){
            case 1:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                    initVideoView();
                }else {
                    Toast.makeText(this, "U have reject!", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
                break;
        }
    }

    public void play() {
        if (!videoView.isPlaying()){
            videoView.start();
        }
    }

    public void pause() {
        if (videoView.isPlaying()){
            videoView.pause();
        }
    }

    public void stop() {
        if (videoView.isPlaying()){
            videoView.resume();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (videoView != null){
            videoView.suspend();
        }
    }
}
總結(jié)

Android中的多媒體知識(shí),包括高階的通知使用,調(diào)用相機(jī)和相冊(cè)的功能以及音視頻的播放.取消通知需要設(shè)置setAutoCancel屬性為true.調(diào)用相冊(cè)和音視頻的播放都需要申請(qǐng)權(quán)限.調(diào)用相冊(cè)后選擇的圖片根據(jù)Android版本的不同需要做不同的處理.

喜歡和關(guān)注都是對(duì)我的鼓勵(lì)和支持~
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末担钮,一起剝皮案震驚了整個(gè)濱河市咆繁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡骤公,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)扬跋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)阶捆,“玉大人,你說(shuō)我怎么就攤上這事∪魇裕” “怎么了倍奢?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)垒棋。 經(jīng)常有香客問(wèn)我卒煞,道長(zhǎng),這世上最難降的妖魔是什么捕犬? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任跷坝,我火速辦了婚禮酵镜,結(jié)果婚禮上碉碉,老公的妹妹穿的比我還像新娘。我一直安慰自己淮韭,他們只是感情好垢粮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著靠粪,像睡著了一般蜡吧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上占键,一...
    開(kāi)封第一講書(shū)人閱讀 51,737評(píng)論 1 305
  • 那天昔善,我揣著相機(jī)與錄音,去河邊找鬼畔乙。 笑死君仆,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的牲距。 我是一名探鬼主播返咱,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼牍鞠!你這毒婦竟也來(lái)了咖摹?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤难述,失蹤者是張志新(化名)和其女友劉穎萤晴,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體胁后,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡硫眯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了择同。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片两入。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖敲才,靈堂內(nèi)的尸體忽然破棺而出裹纳,到底是詐尸還是另有隱情择葡,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布剃氧,位于F島的核電站敏储,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏朋鞍。R本人自食惡果不足惜已添,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望滥酥。 院中可真熱鬧更舞,春花似錦、人聲如沸坎吻。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)瘦真。三九已至刊头,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間诸尽,已是汗流浹背原杂。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留您机,地道東北人穿肄。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像往产,于是被迫代替她去往敵國(guó)和親被碗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

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