Android基础回顾(七)| 使用手机多媒体

参考书籍:《第一行代码》 第二版 郭霖
如有错漏,请批评指出!

通知(Notification)的使用

我们在使用手机过程中,经常会收到应用程序发出的通知。当某个应用程序希望向用户发送一些提示信息或推送时,就可以借助通知来实现。发出一条通知后,状态栏会显示一个应用图标,下拉状态栏后可以看到通知的详细内容。

  • 通知的基本用法
  1. 首先要获取一个NotificationManager来对通知进行管理。
    NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    
    调用Context的 getSystemService() 方法获取,这个方法接收一个String参数用于确定获取系统的哪个服务,我们传入Context.NOTIFICATION_SERVICE 即可。
  2. 接下来需要使用一个Builder构造器来创建 Notification 对象,这里我们使用 support-v4 库中的 NotificationConpat 类的构造器来创建(因为Android系统每次更新版本基本都会对Notification功能进行修改,所以使用app包下的构造器可能存在不稳定性)。
    Notification notification = new NotificationCompat.Builder(this, "default")
           .setContentText("通知")
           .setContentTitle("第一行代码")
           .setWhen(System.currentTimeMillis())
           .setSmallIcon(R.drawable.ic_huaji)
           .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_android))
           .build();
    
    NotificationCompat.Builder() 接收两个参数,第一个参数是Context,第二个参数是一个String,用于对Notification进行分类。我们可以通过一系列的set方法来丰富我们创建的Notification对象。这里我们使用了几个最基本的方法,setContentTitle() 用于设置通知的标题,setContentText()用于设置通知显示的内容,setWhen()用于设置通知创建的时间,setSmallIcon()用于设置状态栏显示的小图标,setLargeIcon()用于设置下拉状态栏中显示的大图标。最后还要调用build()方法来创建Notification对象。
  3. 然后我们调用 NotificationManager 对象的notify()方法来发送通知。这个方法接收两个参数,第一个参数是id,是通知的唯一标识,第二个参数就是要发送的 Notification 对象。
    manager.notify(1, notification);
    
  4. 最后,虽然我们的 Notification 创建并且发送出去了,但是我们并没有给这个通知指定事件,当我们点击这个通知时,是没有任何反应的,下面我们来设置点击通知时跳转到某个Activity,并且通知消失。
    Intent intent = new Intent(this, CpMainActivity.class);
    PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
    NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    Notification notification = new NotificationCompat.Builder(this, "default")
           .setContentText("通知")
           .setContentTitle("第一行代码")
           .setWhen(System.currentTimeMillis())
           .setSmallIcon(R.drawable.ic_huaji)
           .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_android))
           .setContentIntent(pi)
           .setAutoCancel(true)
           .build();
    manager.notify(1, notification);
    

    这里我们调用了setContentIntent()方法,这个方法接收有一个PendingIntent 参数,这种Intent可以理解为一种延时执行的Intent,因为我们在使用Intent时,必须依赖于一个Activity跳转到另一个Activity,否则,我们传递的数据会被清理掉,而我们这里点击通知跳转到另一个Activity,明显发送通知的Activity很多时候并不在后台,因此我们可以理解为,PendingIntent实现Activity跳转的这个动作延时了,当我们点击通知时,才进行跳转。这里由于我们要实现Activity跳转,因此我们调用PendingIntent的getActivity()方法来获取实例,这个方法接收四个参数,第一个参数是Context,第三个参数是一个Intent对象,另两个参数我们传0即可,感兴趣的话可以查看文档,了解每个参数的含义。setAutoCancel()方法用于设置通知被点击时自动取消掉。这里给出的代码是创建以及发送通知的过程,我们需要将这段代码放到某一个Button的点击事件里面,才会触发。直接运行看看效果吧。

关于通知的内容远不止这么多,我们只是实现了一个简单的通知,Notification.Builder 中提供了很丰富的API,可以帮助我们实现很多炫酷的通知效果,我们这里就不一一介绍了,可以根据自己的需求去查询相关文档。

播放多媒体文件

  • 播放音频
    在Android中,播放音频一般都是使用Mediaplayer类来实现,它对多种音频提供了非常全面的控制方法,使得播放音乐的工作变得十分简单。
    我们先来了解一下Mediaplayer的工作流程:首先创建一个MediaPlayer对象,然后调用setDataSource()方法来设置音频文件的路径,再调用prepare()方法使MediaPlayer进入准备状态,接下来调用start()方法就可以开始播放音频,调用pause()方法可以暂停播放,调用reset()方法可以将Mediaplayer对象重置到刚刚创建的状态,想要再播放音频,就需要重新给它设置音频文件路径;而stop()方法则会使当前Mediaplayer对象无法再播放个音频。
    接下来写一个小Demo,首先看一下布局:

    很简单,就不贴代码了,三个Button,点击Start,开始播放音乐;点击pause,音乐会暂停,再点击start,会从暂停的地方继续播放;点击stop,音乐停止,再点击start,从头开始播放音乐。功能很简单,下面来看代码。

    1. 首先创建MediaPlayer对象,并进行初始化操作:
    private static final int TAG_AUDIO_PERMISSION = 100;
    
    private MediaPlayer mMediaPlayer;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mm_activity_audio_and_video);
        ButterKnife.bind(this);
        initView();
    }
    
    private void initView() {
        mMediaPlayer = new MediaPlayer();
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, TAG_AUDIO_PERMISSION);
        }else {
            initMediaPlayer();
        }
    }
    
    private void initMediaPlayer() {
        try{
            File file = new File(Environment.getExternalStorageDirectory(), "music.mp3");
            mMediaPlayer.setDataSource(file.getPath());
            mMediaPlayer.prepare();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case TAG_AUDIO_PERMISSION:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                    initMediaPlayer();
                }else {
                    ToastUtil.showShortToast(this, "拒绝权限将无法使用程序");
                    finish();
                }
                break;
            default:
                break;
        }
    }
    

    可以看到,我们动态申请了 WRITE_EXTERNAL_STORAGE 这个权限,因为我们要指定音频文件的位置,并读取这个文件,因此我们需要读取手机存储的权限(关于动态权限申请的内容在前面讲过),我们这里主要看关于MediaPlayer的内容。Environment.getExternalStorageDirectory() 这个方法获取的是手机外部存储的根目录,也就是说,我们指定了在手机外部存储的根目录读取 music.mp3 这个文件,为什么读取这个位置呢?当然是因为我在这个目录下准备了一个 music.mp3 音频文件(你可以指定别的位置,只要你在相应的位置放了这个文件)。接下来就是调用 prepare() 方法了,这时我们的 Mediaplayer 对象已经为播放音乐做好了准备。
    关于内部存储 和 外部存储 ,我们可能会有疑问,其实在我们使用的智能手机中,无论是手机自带的XXG的内存还是插入SD卡的内存,都属于外部存储。具体可以参考 这篇博客

    1. 接下来就是给我们的Button添加点击事件了(使用了 ButterKnife)
    @OnClick({R.id.but_start, R.id.but_pause, R.id.but_stop})
    public void click(View view) {
        switch (view.getId()){
            default:
                break;
            case R.id.but_start:
                if (!mMediaPlayer.isPlaying()){
                    mMediaPlayer.start();
                }
                break;
            case R.id.but_pause:
                if (mMediaPlayer.isPlaying()){
                    mMediaPlayer.pause();
                }
                break;
            case R.id.but_stop:
                mMediaPlayer.reset();
                initMediaPlayer();
                break;
        }
    }
    

    逻辑很简单,就不解释了。

    1. 最后别忘了调用 MediaPlayer 对象的 stop() 和 release() 方法将 MediaPlayer相关的资源释放掉。
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mMediaPlayer.isPlaying()){
            mMediaPlayer.stop();
        }
        if (mMediaPlayer != null){
            mMediaPlayer.release();
        }
    }
    

    最后附上 MediaPlayer 相关的常用方法:
  • 播放视频
    播放视频主要使用VideoView 类来实现,其实它的使用方法和Mediaplayer很像。这个类将视频的显示和控制集于一身,是的我们仅仅使用这个类就可以实现一个简单的视频播放器。下面直接看完整的代码吧(包括前面的音频部分)。

    1. 布局部分:
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".multimedia.MmAudioAndVideoActivity">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:layout_marginTop="24dp">
    
            <Button
                android:id="@+id/but_start"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/start"
                android:textAllCaps="false"
                tools:ignore="ButtonStyle" />
    
            <Button
                android:id="@+id/but_pause"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="24dp"
                android:text="@string/pause"
                android:textAllCaps="false"
                tools:ignore="ButtonStyle" />
    
            <Button
                android:id="@+id/but_stop"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="24dp"
                android:text="@string/stop"
                android:textAllCaps="false"
                tools:ignore="ButtonStyle" />
    
        </LinearLayout>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_marginTop="20dp">
    
            <VideoView
                android:id="@+id/video_view"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center_horizontal">
    
                <Button
                    android:id="@+id/but_start_video"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@string/start"
                    android:textAllCaps="false"
                    tools:ignore="ButtonStyle" />
    
                <Button
                    android:id="@+id/but_pause_video"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="24dp"
                    android:text="@string/pause"
                    android:textAllCaps="false"
                    tools:ignore="ButtonStyle" />
    
                <Button
                    android:id="@+id/but_replay_video"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="24dp"
                    android:text="@string/replay"
                    android:textAllCaps="false"
                    tools:ignore="ButtonStyle" />
            </LinearLayout>
    
        </LinearLayout>
    
    </LinearLayout>
    
    1. java代码:
    public class MmAudioAndVideoActivity extends AppCompatActivity {
    
        @BindView(R.id.video_view)
        VideoView mVideoView;
    
        private static final int TAG_AUDIO_PERMISSION = 100;
    
        private MediaPlayer mMediaPlayer;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.mm_activity_audio_and_video);
            ButterKnife.bind(this);
            initView();
        }
    
        private void initView() {
            mMediaPlayer = new MediaPlayer();
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    != PackageManager.PERMISSION_GRANTED){
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, TAG_AUDIO_PERMISSION);
            }else {
                initMediaPlayer();
                initVideoPath();
            }
        }
    
        private void initMediaPlayer() {
            try{
                File file = new File(Environment.getExternalStorageDirectory(), "music.mp3");
                mMediaPlayer.setDataSource(file.getPath());
                mMediaPlayer.prepare();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        private void initVideoPath() {
            File file = new File(Environment.getExternalStorageDirectory(), "movie.mp4");
            mVideoView.setVideoPath(file.getPath());
        }
    
        @OnClick({R.id.but_start, R.id.but_pause, R.id.but_stop, R.id.but_start_video,
                R.id.but_pause_video, R.id.but_replay_video})
        public void click(View view) {
            switch (view.getId()){
                default:
                    break;
                case R.id.but_start:
                    if (!mMediaPlayer.isPlaying()){
                        mMediaPlayer.start();
                    }
                    break;
                case R.id.but_pause:
                    if (mMediaPlayer.isPlaying()){
                        mMediaPlayer.pause();
                    }
                    break;
                case R.id.but_stop:
                    mMediaPlayer.stop();
                    mMediaPlayer.reset();
                    initMediaPlayer();
                    break;
                case R.id.but_start_video:
                    if (!mVideoView.isPlaying()){
                        mVideoView.start();
                    }
                    break;
                case R.id.but_pause_video:
                    if (mVideoView.isPlaying()){
                        mVideoView.pause();
                    }
                    break;
                case R.id.but_replay_video:
                    mVideoView.resume();
                    break;
            }
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            switch (requestCode) {
                case TAG_AUDIO_PERMISSION:
                    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                        initMediaPlayer();
                        initVideoPath();
                    }else {
                        ToastUtil.showShortToast(this, "拒绝权限将无法使用程序");
                        finish();
                    }
                    break;
                default:
                    break;
            }
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            if (mMediaPlayer.isPlaying()){
                mMediaPlayer.stop();
            }
            if (mMediaPlayer != null){
                mMediaPlayer.release();
            }
            if (mVideoView != null){
                mVideoView.suspend();
            }
        }
    }
    

    下面也附上 VideoView 的常用方法:

    下面来看看 Demo 的实现效果:

上一篇:Android基础回顾(六)| 关于 Content provider
下一篇:Android基础回顾(八)| 使用HTTP协议访问网络


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

推荐阅读更多精彩内容