响应通知,访问相册和播放音视频

日常手机使用中,常常会遇到头部弹出一条新消息,有的还伴随着震动,音乐以及灯光闪烁,它们是怎么实现的呢?许多app的个人设置页面都有头像设置的功能,一般都有使用者从相册中选取或者立即拍照两种选择.很多时候,app中也会有播放音视频的功能.它们都是如何实现的呢?

1通知

通过通知,能够在app打开,但是被切换到后台时,及时通知用户app的变化.发送通知类似启动Activity,只不过启动对象换成了PendingIntent,用于启动通知时对Intent进行再次封装.示例如下:

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)
        //设置通知的取消
        .setAutoCancel(true)
        //设置声音
        .setSound(Uri.fromFile(new File("/system/media/audio/ringtones/Luna.ogg")))
        //设置震动
        .setVibrate(new  long[] {0, 1000, 1000, 1000})
        //设置闪光灯
        .setLights(Color.GREEN, 1000, 1000)
        .build();
notificationManager.notify(2, notification);

示例中PendingIntent中需要四个参数,第一个参数是上下文context,第三个参数是封装的Intent,第一/四个参数一般传入0即可.

2拍照和访问相册

我们可以把常见的场景简化成如下图的效果.

拍照和访问相册

点击TAKE PHOTO调用相机功能拍照,并将拍摄成功的照片设置给下面的ImageView.点击CHOOSE_FROM_ALBUM启动相册,将选择的照片设置给下面的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>

点击TAKE PHOTO后,调用相机功能.

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);
    }

调用相机通过匿名Intent,传入action名称android.media.action.IMAGE_CAPTURE后,系统会自动识别.在intent传入imageUri存储拍照成功照片.在onActivityResult中对存储的照片进行处理.

@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;
    }
}

点击CHOOSE_FROM_ALBUM后调用相册功能.

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);
}

调用相册实质是读SD卡,属于Android系统的危险权限,使用之前需要申请.在onRequestPermissionsResult中对申请结果进行处理.

@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;
    }
}

类似启动相机功能,调用相册也是通过匿名Intent的方式.在onActivityResult的回调中可以得到选择的图片.

@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以后对回调的Uri进行了封装,需要通过getContentResolver进一步处理.所以通过Android版本和19的比较,对回调的Uri进行了handleImageOnKitKat和handleImageBeforeKitKat不同的处理.

3播放音视频

播放音频通过MediaPlayer类来实现,可以很方便的控制音频的开始,暂停和重新播放.

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();
        }
    }
}

播放音频,也需要申请权限.并且在onDestroy中需要释放掉MediaPlayer初始化时占用的资源.

播放视频通过VideoView来实现.因为VideoView是对MediaPlayer进行的封装,所以使用方式和播放音频非常类似,只不过在重置时调用的是resume方法;OnDestroy中释放资源时,调用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();
        }
    }
}
总结

Android中的多媒体知识,包括高阶的通知使用,调用相机和相册的功能以及音视频的播放.取消通知需要设置setAutoCancel属性为true.调用相册和音视频的播放都需要申请权限.调用相册后选择的图片根据Android版本的不同需要做不同的处理.

喜欢和关注都是对我的鼓励和支持~
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容